播放有关cookie和会话的框架安全问题

nao*_*oru 13 security playframework-2.0

对于我的应用程序,我正在实现与zentask中显示的相同的安全性.

public class Secured extends Authenticator {

@Override
public String getUsername(Context ctx) {
    return ctx.session().get("email");

}

@Override
public Result onUnauthorized(Context ctx) {
    ctx.flash().put("error", "please login to proceed");
    return redirect(routes.Application.index());
}

}
Run Code Online (Sandbox Code Playgroud)

当用户通过isuser身份验证时session().put("email", email);

我有两个问题.第一:当用户在不使用注销的情况下离开应用程序时,如何使会话无效?第二个更严重的是我使用firefox插件检查了cookie cookies manager+并且我可以复制一个cookie然后粘贴它因此我可以访问方法而无需首先登录,基本上我可以窃取会话

Jam*_*per 39

Play Framework使用无状态会话.服务器端没有存储状态,而是所有状态都存储在会话cookie中.为了验证会话,Play使用密钥对会话进行签名,并在有会话cookie的请求到达时验证签名.如果用户要篡改会话数据,例如,如果他们将会话中的电子邮件地址更改为其他人的电子邮件地址,则签名将不匹配,因此Play将拒绝会话cookie.

是的,您可以复制cookie并在以后使用它.但是你不能改变cookie.这意味着你可以"窃取"的唯一cookie就是你自己的,但偷你自己并不是真正的偷窃.所以不,你不能窃取会话,除非通过利用其他漏洞,如XSS,但会话令牌也容易受到攻击.

默认情况下,Play配置为创建"会话"cookie,即在您关闭浏览器时过期的cookie.因此,如果用户退出浏览器,浏览器将删除所有会话cookie,用户将不再登录.会话令牌也是如此.

有一个需要注意的问题,那就是会话令牌也会在服务器上到期,因为服务器保持状态.无状态签名会话(例如Play中使用的会话)不会.但是,您可以自己实现过期机制,方法是在创建会话时在会话中存储时间戳,并验证该时间戳不早于getUsername()方法中已配置的有效期.由于时间戳存储在已签名的会话中,因此在不更改签名的情况下不能篡改时间戳,因此这种简单的机制非常安全.更高级的解决方案可能是实现每次请求进入时更新该时间戳的过滤器,以便过期可以基于上次访问,而不是用户登录时.

  • 这个.应该实现Play. (3认同)
  • “但会话令牌也容易受到此攻击。” 在普通服务器上,当我注销时,任何窃取我的 cookie 的人都无法再使用它。是的,cookie 不应该被窃取,但需要深度防御。 (2认同)

nkr*_*nkr 7

您的假设绝对正确,您不能在Zentask示例之后使服务器上的会话无效.虽然会话cookie使用配置文件中的私钥进行签名,但相同的未签名cookie值会生成签名的相同cookie.正如您已经想到的那样,如果有人从用户那里窃取cookie,用户和您(服务器)都不能阻止小偷"登录"到用户的帐户.

现在基本上有两种选择:

  1. 将易失性信息存储在您和用户知道的cookie中.一个例子是用户的密码哈希.如果用户更改此信息,则旧cookie将失效.但我不建议使用密码哈希,因为它是一个有价值的信息.这样做的坏处是:如果用户没有更改此信息,cookie将在很长一段时间内有效.
  2. 进行服务器端会话管理.为此,您必须拥有类似数据库的东西.在那里,您存储随机生成的会话密钥,用户以及会话将自动失效的日期.您还可以存储IP地址以提高cookie窃取的安全性.然后必须将会话密钥写入cookie.当用户单击注销按钮时,您将使当前会话无效(或者此用户的所有会话).


Agi*_*Pro 5

将用户 ID 简单地放在 cookie 中根本不安全。正如您所指出的,任何人都可以发明 cookie 值。

会话:相反,您需要在 cookie 中放置一个任意(例如随机)值,然后在服务器上在映射表中查找用户的身份。该任意值必须经常更改,因此您的登录会话通常持续 30 分钟。每次登录都会提供一个新的任意值,该值称为会话 ID。

无效:在一段时间没有任何请求(例如 30 分钟)后,通过从查找表(在服务器端)中删除该条目来使会话无效。任何具有不在表中的会话 ID 的请求都被视为未经身份验证的请求,您将再次提示登录。用户是否忘记注销也没有关系。

Hacking:由于该值是任意的,因此黑客无法提前知道未来的 session id 是什么。您仍然容易受到会话窃取的影响,但难度要大得多:黑客只需在使用时找到会话 ID,然后只能在特定时间内使用它。您可以采取一些措施来防止这种情况发生,例如只允许来自特定 IP 地址的特定会话请求。您还可以快速循环会话 ID,即使是每个请求,但也有负面影响。一般而言,为每次登录提供唯一的会话 ID,尤其是在通过 HTTPS 完成时,足以满足大多数身份验证需求。

持久性:如果在任何给定的会话期间(例如 30 分钟)并发用户的数量很少,那么您不一定需要将其放入数据库中。在内存中维护它的开销很低,但缺点是如果您循环服务器,所有用户都需要再次登录。如果确实将会话 ID 放入数据库中,则需要确保服务器启动时可以清除所有旧会话。

用户信息:将用户的电子邮件地址放在 cookie 中仍然有价值,但仅用作登录的“默认”用户 ID。这应该仅被视为对用户的一种方便,而不应视为用户已通过身份验证的指示。

  • 播放会话 cookie 已签名。所以它不仅仅是一个 cookie 中的用户 id,它是一个带有签名的用户 id,验证是 Play 将该用户 id 放入 cookie 中。 (11认同)

viv*_*011 5

  • 我建议使用一个模块来为您生成会话 ID。在此模块中,您可以使用诸如 createSessionId() 之类的方法。生成会话Id的逻辑保留在这个方法中。

  • 我将创建会话 ID 作为(userId + providerId(Facebook/Google - 在 OAuth/UsernamePassword/Any Provider 的情况下)+ 当前时间戳 + UUID)的组合,并在创建此会话 ID 后,我将使用某种算法对其进行加密。这会给我会话 ID

  • 这样做的优点是:

    • 尽管生成会话 ID 需要时间,但没有人会理解它。
    • 另一个优点是,您可以随时在 createSessionId() 方法中更改创建会话 ID 的加密逻辑/策略

  • Playframework 中 session 的另一个问题是 session 没有过期时间:
    • 为了解决这个问题,一旦用户登录,我们就可以将时间戳存储在会话中,即只存储在 cookie 中(可能是通过加密?)
    • 现在,对于每个请求,检查会话中的时间戳。如果时间戳大于 30 分钟,则使会话无效。如果时间戳不大于 30 分钟,则将会话中的时间戳更新为当前时间戳