2013-05-12 79 views
12

对于我的应用程序,我正在实施与zentask中显示的相同的安全性。发挥关于cookie和会话的框架安全问题

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()); 
} 

} 

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

我有两个问题。首先:当用户离开应用程序而不使用注销时,您如何使会话失效?其次更严重的是我使用firefox插件cookies manager+检查了cookie,我可以复制一个cookie并稍后粘贴它,因此我可以访问方法而不必先登录,基本上我可以窃取会话

回答

36

播放框架使用无状态的会话。在服务器端没有存储状态,相反,所有状态都存储在会话cookie中。要验证会话,Play使用密钥签名会话,并在带有会话cookie的请求到达时验证签名。如果用户篡改会话数据,例如,如果他们将会话中的电子邮件地址更改为其他人的电子邮件地址,则签名不匹配,因此Play会拒绝会话Cookie。

是的,你可以复制的cookie,并在以后使用。但是你不能更改cookie。这意味着您可以“窃取”的唯一cookie是您自己的,但是从自己窃取并不是真正的窃取行为。所以不行,除了通过利用其他漏洞(如XSS)之外,您不能窃取会话,但会话令牌也容易受到攻击。

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

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

+1

“,但会话令牌也容易受此影响。”在普通服务器上,当我注销时,任何盗取我的cookie的人都不能再使用它了。是的,曲奇不应该被盗,但需要深度防守。 – 2015-03-07 02:36:03

+3

这个。应该实施到Play中。 – BAR 2015-08-23 01:39:32

4

简单地将用户ID放入一个cookie根本就不是安全的。正如你指出的,任何人都可以发明一个cookie值。相反,您需要在Cookie中放入一个任意值(例如随机),然后在服务器上查找映射表中用户的身份。这个任意值必须经常改变,所以你通常会有一个持续30分钟的登录会话。每个登录提供一个新的任意值,并且该值被称为会话ID。

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

黑客行为:由于该值是任意的,因此黑客无法事先知道未来的会话ID是什么。你仍然很容易受到会话窃取的影响,但它更加困难:黑客必须仅在使用时找到会话ID,然后才能在特定时间内使用它。您可以采取一些措施来防止这种情况发生,例如只允许来自特定IP地址的特定会话请求。即使是每个请求,您也可以快速循环会话ID,但是有负面的一面。一般来说,为每次登录提供一个唯一的会话ID(特别是通过HTTPS完成时),对于大多数身份验证需求来说已足够好。

持久性:如果并发用户的数量超过任何给定的会话期间(例如30分钟)较小,则不一定需要把这个数据库中。将其维持在内存中的开销较低,但具有的缺点是,如果循环使用服务器,则所有用户都需要重新登录。如果确实将会话ID放入数据库中,则需要确保服务器启动时可清除所有旧会话。

用户信息:将用户的电子邮件地址放入cookie中仍有价值,但仅作为“默认”用户标识登录为。这应该只是为了方便用户,而不是作为用户认证的指示。

+0

ive将以下信息放在cookie上session()。put(“email”,email); ()“(timestamp”,new Date()。toString()); ()。put(“ip”,request()。remoteAddress());并比较它。这够好吗? – naoru 2013-05-12 16:54:41

+0

取决于你是否希望黑客进入或不进入。任何人都可以生成电子邮件,时间戳和IP地址,如果这是您需要进行身份验证的全部内容,那么您将被黑客入侵。密钥是一个随机生成的号码,将服务器映射到经过身份验证的用户(和IP地址)。如果没有真正的身份验证,黑客无法在您的(服务器端)表中获得条目。 – AgilePro 2013-05-17 05:20:51

+0

这样生成和UUID,将它分配给cookie并且在说30分钟之后使该UUID失效会带来相对较好的保护? – naoru 2013-05-17 13:22:33

7

您的假设是绝对正确的,您无法使Zentask示例中的服务器上的会话无效。虽然会话cookie是使用配置文件中的私钥签名的,但同一个未签名的cookie值会生成已签名的相同cookie。正如你已经想到的那样,如果有人从用户那里窃取了cookie,用户和你(服务器)都不能阻止小偷“登录”到用户的账户中。

基本上有现在两个选项:

  1. 储存在你和用户知道的cookie挥发性信息。一个例子就是用户的密码哈希。如果用户更改此信息,则旧Cookie将失效。但我不会推荐使用密码哈希,因为它是一个有价值的信息。坏消息是:如果用户没有更改这些信息,那么Cookie将会在很长一段时间内有效。
  2. 进行服务器端会话管理。为此,你必须有一个像数据库的东西。在那里存储会话的随机生成密钥,用户和会话自动失效的日期。您还可以存储IP地址,以提高防止cookie窃取的安全性。会话密钥必须写入cookie中。当用户点击注销按钮时,会使当前会话(或者此用户的所有会话)无效。
+0

第二种方法被认为是有效的,它基本上意味着如果用@Secured注释装饰一个类,每个reqauest都必须针对db进行验证。 – naoru 2013-05-15 13:32:32

+0

基本上,是的。但它也允许跟踪未登录的用户。如果客人可以做的事情,如果客人注册永久保存的东西很有用。 – nkr 2013-05-15 16:53:45

4
  • 我建议有一个模块,这将产生会话ID为您服务。 在这个模块中,你可以有一些像createSessionId()之类的方法。 生成会话Id的逻辑你保留在这个方法中。

  • 我会创建会话ID作为(userId + providerId(Facebook /谷歌 - 在OAuth/UsernamePassword /任何提供者的情况下)+当前时间戳+ UUID)的组合和创建此会话ID后,我会加密它用一些算法。这会给我的会话ID

  • 与优势,这将是:

    • 虽然产生的会话ID都需要时间,没有身体会使它的意义。
    • 另一个好处是,您可以随时在createSessionId()方法中创建会话ID,您可以更改的加密逻辑/策略

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