一种在不存储会话 cookie 的情况下验证会话 cookie 的方法
A way to validate session cookies without storing them
基本信息
- 我有一个网络服务器,上面有很多花哨的东西。
- 它在我的半土豆 PC 上运行,所以我没有任何免费的 64TB SSD 存储空间。
- 我必须关心可扩展性,因为有一天我可能会有 1000 个用户。
哇,这样的用户,非常多!
- 如果用户丢失他的设备,我不希望任何密码被盗。所以我决定使用会话。
- 我不想存储所有用户会话,因为这可能是 100 台设备。所以
1000 * 100
是很多会话 cookie。
- 我想到了一种方法不存储,而是验证 会话以检查请求是否来自帐户所有者。
结构
全球
// Secret 128 bytes array.
const ByteArray serverMagic;
// Generates a SHA512 hash based on data.
function hash(ByteArray data);
// Encodes array of bytes into base64 string.
function base64(ByteArray data);
// Returns current time on the server.
function getCurrentDate();
// Returns userMagic based on the user ID.
function getUserMagic(Integer uid);
// Returns true if user entered wrong password.
function isLoginInvalid(Integer uid, String password);
function Object.toShortString(); // Encodes an object into a short ASCII string.
对于每个用户
const Integer uid; // User ID.
var String password; // Secret code that gives you all of that damn power.
var ByteArray userMagic // Secret 128 bytes array.
逻辑
如果用户要登录
他将发送:
- 会话到期日期(因此 cookie 在所需时间后将无效)
- 用户编号
- 密码(或密码的哈希值,这并不重要)
function logIn(Date expire, Integer uid, String password) {
if(isLoginInvalid(uid, password)) then
return error;
String encExpire = expire.toShortString();
String encUID = uid.toShortString();
ByteArray userMagic = getUserMagic(uid);
ByteArray food = encExpire + '_' + serverMagic + userMagic + '_' + encUID;
ByteArray hash = hash(food);
String session = encExpire + '_' + encUID + '_' + base64(hash);
return session;
}
客户端将保存该会话 cookie。
如果用户会做一些动作
他将向服务器发送一个会话 cookie。
// After parsing session cookie
function request(Date sessionExpire, Integer uid, ByteArray sessionHash) {
if(sessionExpire < getCurrentDate()) then
return error;
String encExpire = sessionExpire.toShortString();
String encUID = uid.toShortString();
ByteArray userMagic = getUserMagic(uid);
ByteArray food = encExpire + '_' + serverMagic + userMagic + '_' + encUID;
ByteArray hash = hash(food);
if(hash == sessionHash) then
return success;
else
return error;
}
如果用户想要使所有会话无效
由于设备丢失或密码更改,服务器只能生成一个新的 userMagic
,这将使所有以前的会话 cookie 失效。
问题
存储而不是存储会话是一种好方法吗?
- 我的系统有问题吗?
- 可以破解吗?
- 以及如何破解?
- 怎么会被滥用呢?
- 如何改进我的系统?
修改后的答案:
像这样的解决方案的问题是它们通常容易受到非常微妙的错误的影响,例如 length extension attacks. Play it safe and use HMAC。
仅供参考,.Net 的一些结构与此差别不大,但使用 HMAC 且没有用户魔法。
上一个已撤回的答案:
任何用户都可以计算:
String session = encExpire + '_' + encUID + '_' + base64(hash);
这意味着任何用户都可以创建任意会话。黑客将通过将 encUID 设置为管理员 uid 来执行此操作,该 uid 可能是 1 或 0 或类似的东西。
我可能会建议使用带有密钥的 HMAC 来修复这个错误,但你真的不应该自己实现这个。找到一个广泛使用且经过深入研究的库,它可以为您进行会话管理,而不是试图重新发明轮子。
基本信息
- 我有一个网络服务器,上面有很多花哨的东西。
- 它在我的半土豆 PC 上运行,所以我没有任何免费的 64TB SSD 存储空间。
- 我必须关心可扩展性,因为有一天我可能会有 1000 个用户。
哇,这样的用户,非常多!
- 如果用户丢失他的设备,我不希望任何密码被盗。所以我决定使用会话。
- 我不想存储所有用户会话,因为这可能是 100 台设备。所以
1000 * 100
是很多会话 cookie。 - 我想到了一种方法不存储,而是验证 会话以检查请求是否来自帐户所有者。
结构
全球
// Secret 128 bytes array.
const ByteArray serverMagic;
// Generates a SHA512 hash based on data.
function hash(ByteArray data);
// Encodes array of bytes into base64 string.
function base64(ByteArray data);
// Returns current time on the server.
function getCurrentDate();
// Returns userMagic based on the user ID.
function getUserMagic(Integer uid);
// Returns true if user entered wrong password.
function isLoginInvalid(Integer uid, String password);
function Object.toShortString(); // Encodes an object into a short ASCII string.
对于每个用户
const Integer uid; // User ID.
var String password; // Secret code that gives you all of that damn power.
var ByteArray userMagic // Secret 128 bytes array.
逻辑
如果用户要登录
他将发送:
- 会话到期日期(因此 cookie 在所需时间后将无效)
- 用户编号
- 密码(或密码的哈希值,这并不重要)
function logIn(Date expire, Integer uid, String password) {
if(isLoginInvalid(uid, password)) then
return error;
String encExpire = expire.toShortString();
String encUID = uid.toShortString();
ByteArray userMagic = getUserMagic(uid);
ByteArray food = encExpire + '_' + serverMagic + userMagic + '_' + encUID;
ByteArray hash = hash(food);
String session = encExpire + '_' + encUID + '_' + base64(hash);
return session;
}
客户端将保存该会话 cookie。
如果用户会做一些动作
他将向服务器发送一个会话 cookie。
// After parsing session cookie
function request(Date sessionExpire, Integer uid, ByteArray sessionHash) {
if(sessionExpire < getCurrentDate()) then
return error;
String encExpire = sessionExpire.toShortString();
String encUID = uid.toShortString();
ByteArray userMagic = getUserMagic(uid);
ByteArray food = encExpire + '_' + serverMagic + userMagic + '_' + encUID;
ByteArray hash = hash(food);
if(hash == sessionHash) then
return success;
else
return error;
}
如果用户想要使所有会话无效
由于设备丢失或密码更改,服务器只能生成一个新的 userMagic
,这将使所有以前的会话 cookie 失效。
问题
存储而不是存储会话是一种好方法吗?- 我的系统有问题吗?
- 可以破解吗?
- 以及如何破解?
- 怎么会被滥用呢?
- 如何改进我的系统?
修改后的答案:
像这样的解决方案的问题是它们通常容易受到非常微妙的错误的影响,例如 length extension attacks. Play it safe and use HMAC。
仅供参考,.Net 的一些结构与此差别不大,但使用 HMAC 且没有用户魔法。
上一个已撤回的答案:
任何用户都可以计算:
String session = encExpire + '_' + encUID + '_' + base64(hash);
这意味着任何用户都可以创建任意会话。黑客将通过将 encUID 设置为管理员 uid 来执行此操作,该 uid 可能是 1 或 0 或类似的东西。
我可能会建议使用带有密钥的 HMAC 来修复这个错误,但你真的不应该自己实现这个。找到一个广泛使用且经过深入研究的库,它可以为您进行会话管理,而不是试图重新发明轮子。