为什么不使用会话 ID 作为 XSRF 令牌? [英] Why not use session ID as XSRF token?

查看:18
本文介绍了为什么不使用会话 ID 作为 XSRF 令牌?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么 Play Framework 使用 [会话 ID 的签名版本] 作为 跨站点请求伪造 (XSRF/CSRF) 预防令牌,而不是会话 ID 本身?

Why does Play Framework use [a signed version of the session id] as Cross Site Request Forgery (XSRF/CSRF) prevention token, rather than the session ID itself?

(使用 XSRF 预防令牌,我的意思是必须包含在表单提交中的魔法值,以便 web 应用程序接受表单.)

(With XSRF prevention token, I mean a magic value that must be included in a form submission, for the webapp to accept the form.)

如果有窃听者,他/她无论如何都会找到 XSRF 令牌和 SID cookie(?).

If there's an eavesdropper s/he'll find both the XSRF token and the SID cookie anyway (?).

如果存在 XSS 漏洞,那么恶意 JavaScript 代码可以读取 XSRF 令牌和 SID cookie (?).

If there's an XSS exploit, then the malicious JavaScript code can read both the XSRF token and the SID cookie (?).

然而:

  1. 在给定 SID 的情况下,攻击者无法构建有效的 XSRF 令牌,因为他/她没有在签署 SID 以获取 XSRF 令牌时使用的密钥.-- 但是攻击者怎么可能只得到 SID 而不是 XSRF 令牌呢?是不是很牵强?

  1. An attacker cannot construct a valid XSRF token, given a SID, since s/he doesn't have the secret key used when signing the SID to obtain the XSRF token. -- But how could it happen that an attacker gets hold of only the SID, not the XSRF token? Is that far-fetched?

如果 SID 是在 HTTP Only cookie 中发送的,那么即使他/她找到了 XSRF 令牌,攻击者也不会有 SID,也许攻击者真的需要 SID?-- 这是否牵强?

If the SID is sent in a HTTP Only cookie, then an attacker wouldn't have the SID even if s/he found the XSRF token, and perhaps the attacker really needs the SID? -- Is this far-fetched?

代码片段:

此处 Play 构造了它的 XSRF 令牌(getId 返回会话 ID):(play/framework/src/play/mvc/Scope.java)

Here Play constructs it's XSRF token (getId returns the session ID): (play/framework/src/play/mvc/Scope.java)

    public String getAuthenticityToken() {
        return Crypto.sign(getId());
    }

此处 Play 检查

是否具有有效的 XSRF 令牌:(play/framework/src/play/mvc/Controller.java)

Here Play checks that a <form> has a valid XSRF token: (play/framework/src/play/mvc/Controller.java)

protected static void checkAuthenticity() {
    if(Scope.Params.current().get("authenticityToken") == null ||
       !Scope.Params.current().get("authenticityToken").equals(
                       Scope.Session.current().getAuthenticityToken())) {
        forbidden("Bad authenticity token");
    }
}

更新:

Play 改变了它生成 XSRF 令牌的方式,现在不再使用 SID,而是使用随机值签名和使用!(我刚刚将我的 Play Framework Git 存储库克隆从旧版 Play 1.1 更新到了新版 1.2.也许我应该这样做......昨天,嗯.)

Play has changed the way it generates XSRF tokens, now the SID is no longer used, instead a random value is signed and used! (I just updated my Play Framework Git repo clone from old Play version 1.1 to new 1.2. Perhaps I should have done this ... yesterday, hmm.)

    public String getAuthenticityToken() {
        if (!data.containsKey(AT_KEY)) {
            data.put(AT_KEY, Crypto.sign(UUID.randomUUID().toString()));
        }
        return data.get(AT_KEY);
    }

那么,他们为什么要进行这种更改?

Well, then why did they do this change?

我找到了提交:
[#669] 再次修复并同时申请 Flash 和 Errors
d6e5dc50ea11fa7ef626cbdf01631595cbdda54c

I found the commit:
[#669] Fix again and apply for Flash and Errors as well
d6e5dc50ea11fa7ef626cbdf01631595cbdda54c

来自问题 #669:
仅在绝对必要时创建会话
对资源的每个请求都会创建会话 cookie.如果真的有数据要存储在会话中,play 应该只创建一个会话 cookie.

所以他们使用的是随机值,而不是 SID,因为 SID 可能尚未创建.嗯,这就是不使用 SID 的衍生物作为 XSRF 令牌的原因.但没有说明为什么他们在过去使用 SID 时对其进行签名/散列处理.

So they're using a random value, not the SID, because the SID might not yet have been created. Well that's a reason not to use a derivative of the SID as XSRF token. But doesn't clarify why they signed/hashed the SID, in the past, when they were using it.

推荐答案

首先要说的是,您可以重用会话 ID 作为 CSRF 令牌,只要它可以保护您免受CSRF 并不会自动创建任何严重的安全漏洞.但是,出于某种合理的原因,OWASP 过去曾明确建议反对它.(他们现在根本没有解决这个问题.)

The first thing to say is that you can reuse the session ID as the CSRF token, insofar as it will protect you fine against CSRF and does not automatically create any serious security holes. However, for somewhat sound reasons, OWASP used to explicitly recommend against it. (They now don't address the question at all.)

反对将会话 ID 重新用作 CSRF 令牌的论点可以总结如下(关键点以粗体显示,理由如下):

The argument against reusing the session ID as the CSRF token can be summarized as follows (key points in bold, with justification beneath):

  1. 攻击者获取的会话 ID 通常比攻击者获取的 CSRF 令牌更严重.

攻击者从拥有 CSRF 令牌中获得的一切(假设其他一些安全信息,如会话 ID,没有被重新用作 CSRF 令牌)就是执行 CSRF 攻击的能力.这给了他们两个巨大的限制,如果他们实际获得了会话 ID,则不会有这些限制:

All that an attacker gains from having the CSRF token (assuming that some other secure piece of information, like the session ID, hasn't been reused as the CSRF token) is the ability to perform CSRF attacks. This gives them two huge limitations that they wouldn't have if they actually acquired a session ID:

  • 他们仍然需要用相应的会话令牌将用户引诱到攻击页面(或让他们阅读攻击电子邮件,或在 iframe 中查看攻击广告等)以任何方式利用 CSRF 令牌.有了会话 ID,他们只需将其放入浏览器,然后就可以像该用户一样使用该网站.
  • 虽然他们可以发送请求使用用户的凭据,同源策略 仍然阻止他们查看对这些请求的响应.这可能(也可能不,取决于您保护的 API 的结构和攻击者的独创性)实际上意味着虽然攻击者可以代表用户执行操作,但他们不能获取用户有权查看的敏感信息.(您更关心哪些取决于上下文 - 人们假设攻击者倾向于获取您银行账户的内容而不是仅仅知道它是多少,但他们也宁愿知道您的病史而不是破坏它.)

  • They still need to lure the user with the corresponding session token to an attack page (or have them read an attack email, or view an attack ad in an iframe, etc.) to exploit the CSRF token in any way at all. With the session ID, they'd just need to put it in their browser and then use the website as if they were that user.
  • While they can send requests using the user's credentials, the Same Origin Policy still prevents them from viewing the responses to those requests. This may (or may not, depending on the structure of the API you're protecting and the attacker's ingenuity) mean in practice that while the attacker can perform actions on the user's behalf, they cannot acquire sensitive information that the user is authorized to view. (Which of these you care more about depends upon the context - one assumes that an attacker would tend to prefer taking the contents of your bank account to merely knowing how much that is, but that they'd also rather know your medical history than vandalise it.)

CSRF 令牌可能比会话 ID 更容易被攻击者获取

  • XSS 攻击很可能允许攻击者获取 CSRF 令牌,因为通常的做法是将它烘焙到 DOM 中(例如作为 元素的值在 ><form>.另一方面,会话 cookie 可以是 即使面对使用 HttpOnly 标志的成功 XSS 攻击,它也会保密,要求攻击者做更多的前期工作以有效利用 XSS 漏洞.
  • 如果 CSRF 令牌作为请求参数而不是自定义 HTTP 标头发送回服务器(保证将其包含在普通 HTML 提交中时的情况),然后 Web 服务器访问日志通常会在 GET 请求上记录 CSRF 令牌(因为它是 URL 的一部分).因此,设法查看访问日志的攻击者将能够获得许多 CSRF 令牌.
  • CSRF 令牌嵌入的页面或脚本可能会缓存在用户的浏览器中,从而允许攻击者从缓存中检索它们(可以想象,在用户使用了图书馆或互联网中的公共机器之后咖啡馆,然后要么清除他们的 cookie 而不是他们的缓存,要么使用注销"按钮从浏览器中删除他们的会话 cookie,而不会使其服务器端无效).

  • XSS attacks are likely to permit an attacker to acquire the CSRF token, since it's common practice to bake it into the DOM (e.g. as the value of an <input> element in a <form>. Session cookies, on the other hand, can be kept secret even in the face of a successful XSS attack using the HttpOnly flag, demanding more up-front work from an attacker to usefully exploit an XSS vulnerability.
  • If the CSRF token is being sent back to the server as a request parameter rather than a custom HTTP header (guaranteed to be the case when including it in ordinary HTML <form> submits), then web server access logs will generally log the CSRF token on GET requests (as it's part of the URL). Thus an attacker who manages to view the access log would be able to acquire many CSRF tokens.
  • Pages or scripts that the CSRF token is baked into may be cached in the user's browser, permitting an attacker to retrieve them from the cache (conceivably relevant after the user has, for example, used a public machine in a library or internet cafe, and then either cleared their cookies but not their cache, or used a 'Log Out' button that removes their session cookie from the browser without invalidating it server-side).

但如果您将会话 ID 重复用作 CSRF 令牌,那么任何允许他们获取 CSRF 令牌的攻击也会自动为他们提供会话 ID.

因此,您不应将 CSRF 令牌重复用作会话 ID,因为这会使会话 ID 更容易受到攻击.

老实说,我认为以上所有内容更像是一种理论问题,而不是实际问题.论证中的弱点是第 2 点;我能想到的唯一可用于获取 CSRF 令牌但不能用于获取会话 cookie 的现实漏洞仍然是非常严重的漏洞.如果您的站点上存在 XSS 漏洞,或者攻击者可以访问您该死的服务器日志,那么无论如何您很可能已经完蛋了.而且在我去过的大多数图书馆和网吧中,工作人员并不精通安全,安装未被发现的键盘记录器并获取密码非常容易——攻击者无需前往等待人们使用机器,然后翻录浏览器缓存的内容.

To be honest, I kind of regard everything above as more of a theoretical concern than a practical one. The weak point in the argument is point 2; the only realistic vulnerabilities I can think of that could be used for acquiring CSRF tokens but not for acquiring session cookies are still really serious vulnerabilities. If you have an XSS hole on your site, or an attacker has access to your freaking server logs, chances are you're totally fucked anyway. And in most libraries and internet cafes I've been to, the staff were not security-savvy and it'd be pretty easy to install a keylogger undetected and just harvest passwords - there'd be no need for an attacker to go to the effort of waiting for people to use the machine and then ripping the contents of their browser cache.

然而,除非您的情况以某种方式使得在随机会话 ID 旁边存储额外的 CSRF 随机令牌变得困难,为什么不只是为了它给您带来的适度安全好处而这样做呢?

However, unless your circumstances somehow make it difficult to store an additional random token for CSRF alongside the random session ID, why not just do it anyway for whatever modest security benefit it gives you?

这篇关于为什么不使用会话 ID 作为 XSRF 令牌?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆