【问题标题】:Invalidate Guava cache by the part of the key部分 key 使 Guava 缓存失效
【发布时间】:2016-11-07 05:29:08
【问题描述】:

我正在使用 Guava LoadingCache 来缓存外部存储的身份验证请求。关键是对象Auth:

public class Auth {
    private String username;
    private String password;
    public boolean equals(Object o);
}

响应是 HttpStatus、OK 或 FORBIDDEN。

当外部存储中username的密码更改时,我需要删除username的缓存记录,但问题是密码只存储为哈希,而不是原始值,所以我不能只需为失效构造新的 Auth 对象,例如:

cache.invalidate(new Auth(<username>, <password>));

我怎样才能使缓存记录无效,只使用username 值?

【问题讨论】:

  • 为什么不用Auth作为key呢?
  • 因为我不知道原始密码,只知道存储的 MD5 哈希。在缓存中我有原始密码的 Auth,所以它们不相等。
  • 我觉得很傻,我想问的是,“为什么不用username作为key”?
  • 它必须如何工作?例如,我在缓存中有两条记录:Auth(user1, password1) = OK 和 Auth(user1, password2) = FORBIDDEN。所以password1是正确的,password2是不正确的。如果我将收到更多带有 Auth(user1, password2) 的请求,我只返回 FORBIDDEN 而不查询外部存储。如果我只使用用户名作为键,我每次收到请求时都需要查询存储。

标签: java caching guava


【解决方案1】:

例如,我在缓存中有两条记录:Auth(user1, password1) = OK 和 Auth(user1, password2) = FORBIDDEN。所以password1是正确的,password2是不正确的。如果我会收到更多带有 Auth(user1, password2) 的请求,我只返回 FORBIDDEN 而不查询外部存储。

这样做的问题是你几乎不会再看到Auth(user1, password2)(即无效的对)。合法用户可能会犯错误,他们可能会重复完全相同的错误,但这种情况很少见。攻击者不会浪费时间重复失败的组合。所以这样的条目只是浪费内存。

将user 存储为键,将password 或hashedPassword 存储为值应该可以正常工作,如果发生命中,它将为您节省外部存储访问权限:您所需要的只是比较和散列。

虽然我认为您的问题没有意义,但我尝试提出一个解决方案:通过密钥的一部分无效是不可能的,但您可以改为保留一组所有用户最近更改了密码(例如,在过去 24 小时内)。如果将expireAfterWrite设置为较小的值,则可以确定通过查询设置可以检测到无效的Auth。

请注意,仅通过 MD5 保护密码是非常耗时的。有更好的算法,如 bcrypt 或 bcrypt,旨在减缓密码破解速度。

【讨论】:

    【解决方案2】:

    如何实现一个在驱逐时执行并删除密钥的 RemovalListener,例如用户名来自基于键值对的单独数据结构。

    【讨论】:

      【解决方案3】:

      怎么样

      • 遍历缓存键
      • 寻找改变的用户
      • 使密钥无效

      第二个选项是使用user作为缓存键和the password hash作为值而不是缓存服务响应

      【讨论】:

        【解决方案4】:

        在我看来,缓存密码而不是哈希不是一个好习惯。 密钥只能是用户名或用户名和哈希。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-09-08
          • 2015-11-11
          • 1970-01-01
          • 2015-04-02
          • 2011-01-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多