为什么同源策略不足以阻止CSRF攻击?

时间:2015-10-21 13:54:16

标签: cookies cors csrf jwt same-origin-policy

首先,我假设一个后端控制输入以防止XSS漏洞。

this answer @Les Hazlewood解释如何在客户端保护JWT。

  

假设所有通信都有100%TLS - 无论是在期间还是在任何时间   登录后 - 通过基本用户名/密码进行身份验证   验证和接收JWT是一个有效的用例。   这几乎就是OAuth 2的流量之一('密码授权')   作品。   [...]

     

您只需设置授权标题:

Authorization: Bearer <JWT value here>
     

但话说,如果您的REST客户端是“不受信任的”(例如,   启用JavaScript的浏览器),我甚至不会这样做:任何值   可通过JavaScript访问的HTTP响应 - 基本上是任何标头   价值或反应的身体价值 - 可以通过嗅探和拦截   MITM XSS攻击。

     

最好将JWT值存储在仅限安全的http-only cookie中   (cookie config:setSecure(true),setHttpOnly(true))。这保证了   浏览器将:

     
      
  1. 只能通过TLS连接传输cookie,
  2.   
  3. 永远不要将cookie值用于JavaScript代码。
  4.         

    这种方法几乎是您为最佳实践所需要做的一切   安全。 最后一件事是确保您拥有CSRF保护   每个HTTP请求,以确保外部域发起请求   到您的网站无法正常运行。

         

    最简单的方法是仅设置安全(但不仅限于http)   具有随机值的cookie,例如一个UUID。

我不明白为什么我们需要具有随机值的cookie,以确保启动对您网站的请求的外部域无法正常运行。对于同源政策,这不是免费的吗?

来自OWASP

  

检查原始标题

     

Origin HTTP Header标准是作为一种方法引入的   防御CSRF和其他跨域攻击。不像   referer,原点将出现在发起的HTTP请求中   来自HTTPS网址。

     

如果存在原始标题,则应检查它   一致性。

我知道OWASP本身的一般建议是同步器令牌模式,但我看不出剩下的漏洞是什么:

  • 安全httpOnly cookie中的TLS + JWT +同源策略+没有XSS漏洞。

更新1:  同源策略仅适用于XMLHTTPRequest,因此恶意站点可以轻松地生成表单POST请求,这将破坏我的安全性。需要显式的原始标头检查。等式将是:

  • TLS + JWT在安全的httpOnly cookie + Origin Header检查 +没有XSS漏洞。

3 个答案:

答案 0 :(得分:14)

摘要

@Bergi,@ Neil McGuigan和@SilverlightFox让我澄清了有关同源策略和CORS的误解概念。

首先,@ Bergi所说的

  

SOP不会阻止发送请求。它确实阻止了一个页面   访问跨域请求的结果。

是一个重要的概念。我认为浏览器不会根据SOP限制向跨域提出请求,但这仅适用于Monsur Hossain所称的&#34;不那么简单的请求&#34;在this优秀的教程中。

  

跨域请求有两种形式:

     
      
  • 简单请求
  •   
  • &#34;不那么简单的请求&#34; (我刚刚编造的一个词)
  •   
     

简单请求是符合以下条件的请求:

     
      
  • HTTP方法匹配(区分大小写)以下之一:      
        
    • HEAD
    •   
    • GET
    •   
    • POST
    •   
  •   
  • HTTP标头匹配(不区分大小写):      
        
    • 接受
    •   
    • 接受语言
    •   
    • 内容的语言
    •   
    • 最后-事件ID
    •   
    • Content-Type,但仅当值为以下值之一时:      
          
      • 应用程序/ x-WWW窗体-urlencoded
      •   
      • 的multipart / form-data的
      •   
      • 文本/纯
      •   
    •   
  •   

因此,具有内容类型application / x-www-form-urlencoded的POST将命中服务器(这意味着CSRF漏洞),但浏览器将无法访问该请求的结果。 具有内容类型application / json的POST是一个&#34;不那么简单的请求&#34;所以浏览器会发出像这样的预备请求

选项/端点HTTP / 1.1
主持人:https://server.com
连接:保持活力
访问控制请求方法:POST
来源:https://evilsite.com
访问控制请求标题:内容类型
接受:* / *
Accept-Encoding:gzip,deflate,sdch
Accept-Language:es-ES,es; q = 0.8

如果服务器响应,例如:

  

访问控制 - 允许 - 来源:http://trustedsite.com
  访问控制允许方法:GET,POST,PUT
  Access-Control-Allow-Headers:内容类型
  内容类型:text / html;字符集= UTF-8

浏览器根本不会发出请求,因为

  

XMLHttpRequest无法加载http://server.com/endpoint。回应   预检请求没有通过访问控制检查:   &#39;访问控制允许来源&#39; header包含无效值   &#39; trustedsite.com&#39 ;.起源&#39; evilsite.com&#39;因此不允许访问。

所以我认为Neil在谈到这一点时正在谈论这个:

  

同源策略仅适用于读取数据而不适用   写它。

然而,由于我向Bergi提议的原始标题显式控制,我认为就此问题而言已经足够了。

关于我对Neil的回答,我并不意味着答案是我所有问题的答案,但它记得我关于SOP的另一个重要问题,那就是该政策仅适用于XMLHTTPRequest&#39; s

总之,我认为方程式

  • 安全httpOnly cookie中的TLS + JWT + Origin Header检查+没有XSS漏洞。
如果API位于另一个域,如SilverlightFox所说,

是一个不错的选择。如果客户端位于同一个域中,那么客户端将遇到不包含Origin头的请求的麻烦。再次来自cors tutorial

  

Origin标头的存在并不一定意味着   请求是跨域请求。而所有跨源请求   将包含一个Origin标头,一些同源请求可能有   一个也是。例如,Firefox没有包含Origin标头   同源请求。但Chrome和Safari包含一个Origin标头   在同源的POST / PUT / DELETE请求(同源GET请求将   没有Origin标题)。

Silverlight指出this

唯一的风险是客户端可以欺骗原始标头以匹配允许的来源,所以我正在寻找的答案实际上是this

更新:对于那些观看此帖子的人,我doubts关于是否需要使用JWT的原始标题。

等式将是:

  • TLS + JWT存储在安全cookie + JWT请求标头中+没有XSS漏洞。

此外,前面的公式有httpOnly cookie,但如果你的客户端和服务器位于不同的域(如今许多SPA应用程序),这将无法工作,因为每次请求都不会发送cookie到服务器。因此,您需要访问存储在cookie中的JWT令牌并将其发送到标题中。

答案 1 :(得分:12)

  

为什么同源策略不足以阻止CSRF攻击?

因为同源策略仅适用于读取数据而不是写入数据。

您希望避免http://compromised.com发出此类请求(来自用户的浏览器):

POST https://example.com/transfer-funds
fromAccountId:1
toAccountId:666

合法请求看起来像这样:

POST https://example.com/transfer-funds
fromAccountId: 1
toAccountId: 666
csrfToken: 249f3c20-649b-44de-9866-4ed72170d985

您可以通过要求外部网站无法读取的值(CSRF令牌)来实现此目的,即在HTML表单值或响应标头中。

关于Origin标头,旧浏览器不支持它,而Flash有一些漏洞让客户端更改它。基本上你会相信Adobe不会在将来搞砸任何东西......这听起来像个好主意吗?

  

确保您对每个HTTP请求都有CSRF保护

您只需要对带有副作用的请求进行CSRF保护,例如更改状态或发送消息

答案 2 :(得分:1)

我只是想总结答案。

  1. 正如其他提到的SOP仅适用于XmlHttpRequests。这意味着通过规范,浏览器必须发送ORIGIN标头以及通过XmlHttpRequests发出的请求。
  2. 如果您在提交表单时检查Chromium发送origin。然而,这并不意味着其他浏览器会这样做。下图显示了在Firefox中发出的两个帖子请求。一个是submitting表单,另一个是XHR。这两项请求均来自http://hack:3002/changePasswordhttp://bank:3001/chanePassword
  3. 如果请求来自同一个域,则允许浏览器不发送origin标头。因此,只有在设置了origin头时,服务器才应检查原始策略。
  4. 结论是:如果您使用Cookie并且请求在没有origin标头的情况下发送到服务器,则您无法通过在同一域中提交来自其他域或XHR的表单来区分它。这就是您需要使用CSRF进行额外检查的原因。

    enter image description here