一种在不存储会话 cookie 的情况下验证会话 cookie 的方法

A way to validate session cookies without storing them

基本信息

结构

全球

// 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.

逻辑

如果用户要登录

他将发送:


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 来修复这个错误,但你真的不应该自己实现这个。找到一个广泛使用且经过深入研究的库,它可以为您进行会话管理,而不是试图重新发明轮子。