Spring 文档说记住我是通过在 cookie 中存储以下信息来实现的 -
base64(用户名 + ":" + 过期时间 + ":" + md5Hex(用户名 + ":" + 过期时间 + ":" 密码 + ":" + 密钥))
我有以下困惑——
-
为什么使用像 MD5 这样的不安全哈希来消化信息,而不是使用 SHA-1 或 SHA-2。对于这么小的信息,这些对性能的影响是否很大?
-
为什么要通过网络传输这些信息?为什么不在服务器上维护加密安全随机数和此信息的映射,仅返回映射密钥作为cookie。AFAIK 这是 Servlet API 使用的方法,被认为更安全。
让我们从第二个问题开始,因为它是更相关的问题:
第二个问题"为什么要通过网络传输密码......"答:
因为你描述的只是Simple Hash-Based Token Approach
如果您向下滚动页面 Spring 安全参考:第 10 章记住我身份验证,您将看到 Spring 安全性也可以使用不同的记住我方法:第 10.3 章持久令牌方法。这就是你在第二个问题中建议的。
第一个问题:简短回答"对于这么小的信息,这些对性能的影响是否重要?"- 否
因此,如果你想使用Simple Hash-Based Token Approach
并且觉得MD5是不安全的,那么你可以子类TokenBasedRememberMeService
[javadoc]并覆盖String makeTokenSignature(long tokenExpiryTime, String username, String password)
方法。例如(未经测试)
protected String makeTokenSignature(long tokenExpiryTime, String username, String password) {
String data = username + ":" + tokenExpiryTime + ":" + password + ":" + getKey();
MessageDigest digest;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("No SHA-256 algorithm available!");
}
return new String(Hex.encode(digest.digest(data.getBytes())));
}
基于简单哈希的令牌使用的 MD5 哈希不是该方法的漏洞。
使用MD5 对密码进行哈希处理是危险的,因为给定现有密码的哈希值,您可以找到另一个哈希为相同值的密码(使用彩虹表)。
但是,在这种情况下,MD5 不用于散列密码,而是用作 MAC。 如果您确实使用彩虹表来查找与该哈希冲突的值,那么您究竟如何使用该值?
对 cookie 使用不同的哈希函数可能会让您感觉更安全,但在这种情况下它不会提供更多的安全性。
如果你想要更高的安全性,那么你应该使用持久哈希令牌方法。 简单哈希令牌以明文形式公开用户名,容易受到重播攻击。 持久令牌避免了这些问题。
无论哪种方式,您都应该通过设置其安全和仅限 HTTP 标志来保护你的记住我 cookie。