为什么同源策略不足以防止 CSRF 攻击? [英] Why Same-origin policy isn't enough to prevent CSRF attacks?

查看:68
本文介绍了为什么同源策略不足以防止 CSRF 攻击?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

this answer中,@Les Hazlewood 解释了如何在客户端保护 JWT.

<块引用>

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

您只需设置授权标头:

Authorization: Bearer <JWT value here>

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

最好将 JWT 值存储在仅安全、仅 http 的 cookie 中(cookie 配置:setSecure(true)、setHttpOnly(true)).这保证浏览器将:

  1. 仅通过 TLS 连接传输 cookie,并且,
  2. 永远不要让 cookie 值可用于 JavaScript 代码.

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

执行此操作的最简单方法是设置仅安全(但不是仅 http)具有随机值的 cookie,例如一个 UUID.

我不明白为什么我们需要具有随机值的 cookie 来确保向您的站点发起请求的外部域无法运行.同源政策不是免费的吗?

来自 OWASP:

<块引用>

检查源头

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

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

我知道 OWASP 本身的一般建议是同步器令牌模式,但我看不出还有哪些漏洞:

  • 安全 httpOnly cookie 中的 TLS + JWT + 同源策略 + 无 XSS 漏洞.

更新 1:同源策略只适用于 XMLHTTPRequest,所以一个邪恶的网站可以轻松地发出表单 POST 请求,这会破坏我的安全.需要显式的源头检查.等式是:

  • 安全 httpOnly cookie 中的 TLS + JWT + Origin Header 检查 + 无 XSS 漏洞.

解决方案

总结

@Bergi、@Neil McGuigan 和 @SilverlightFox 帮助我澄清了关于同源政策和 CORS 的误解.

首先,@Bergi 是怎么说的

<块引用>

SOP 不会阻止发送请求.它确实可以防止页面访问跨域请求的结果.

是一个重要的概念.我认为浏览器不会根据 SOP 限制向跨域发出请求,但这仅适用于 Monsur Hossain 在 this 非常棒的教程.

<块引用>

跨域请求有两种形式:

  • 简单的请求
  • 不那么简单的请求"(我刚刚编造的一个术语)

简单请求是满足以下条件的请求:

  • HTTP 方法匹配(区分大小写)以下之一:
    • 头部
    • 获取
    • 发布
  • HTTP 标头匹配(不区分大小写):
    • 接受
    • 接受语言
    • 内容语言
    • 最后事件 ID
    • Content-Type,但仅当值为以下之一时:
      • application/x-www-form-urlencoded
      • 多部分/表单数据
      • 文本/纯文本

因此,内容类型为 application/x-www-form-urlencoded 的 POST 将访问服务器(这意味着 CSRF 漏洞),但浏览器将无法访问该请求的结果.内容类型为 application/json 的 POST 是一个不那么简单的请求",因此浏览器会发出这样的 prefligth 请求

<块引用>选项/endpoint HTTP/1.1
主机:https://server.com
连接:保持活动
访问控制请求方法:POST
来源:https://evilsite.com
访问控制请求标头:内容类型
接受:*/*
接受编码:gzip、deflate、sdch
接受语言:es-ES,es;q=0.8

如果服务器响应例如:

<块引用>

访问控制允许来源:http://trustedsite.com
访问控制允许方法:GET、POST、PUT
访问控制允许标头:内容类型
内容类型:文本/html;字符集=utf-8

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

<块引用>

XMLHttpRequest 无法加载 http://server.com/endpoint.回应预检请求未通过访问控制检查:Access-Control-Allow-Origin"标头包含无效值'trustedsite.com'.因此,不允许访问 Origin 'evilsite.com'.

所以我认为尼尔在指出以下内容时正在谈论这个:

<块引用>

同源策略仅适用于读取数据,不适用于写吧.

但是,对于这个问题,我认为我向 Bergi 提出的原始标头显式控制已经足够了.

关于我对 Neil 的回答,我并不是说这个回答是我所有问题的答案,但它让我想起了关于 SOP 的另一个重要问题,那就是该政策仅适用于 XMLHTTPRequest.

总之,我认为等式

  • 安全 httpOnly cookie 中的 TLS + JWT + Origin Header 检查 + 无 XSS 漏洞.

如果 API 位于像 SilverlightFox 所说的另一个域中,这是一个不错的选择.如果客户端与客户端在同一个域中,我将无法处理不包含 Origin 标头的请求.再次来自 cors 教程:

<块引用>

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

Silverlight 指出 这个.

剩下的唯一风险是客户端可以欺骗源头以匹配允许的源,所以我正在寻找的答案实际上是 这个

更新:对于那些观看这篇文章的人,我有怀疑如果来源使用 JWT 完全需要标头.

等式是:

  • TLS + JWT 存储在安全 cookie + 请求标头中的 JWT + 无 XSS 漏洞.

此外,前面的等式有 httpOnly cookie,但如果您将客户端和服务器放在不同的域中(如今天的许多 SPA 应用程序),这将不起作用,因为 cookie 不会随每个请求一起发送到服务器.因此,您需要访问存储在 cookie 中的 JWT 令牌并将其发送到标头中.

First of all, I assume a backend that control inputs to prevent XSS vulnerabilities.

In this answer @Les Hazlewood explain how to protect the JWT in the client side.

Assuming 100% TLS for all communication - both during and at all times after login - authenticating with username/password via basic authentication and receiving a JWT in exchange is a valid use case. This is almost exactly how one of OAuth 2's flows ('password grant') works. [...]

You just set the Authorization header:

Authorization: Bearer <JWT value here>

But, that being said, if your REST client is 'untrusted' (e.g. JavaScript-enabled browser), I wouldn't even do that: any value in the HTTP response that is accessible via JavaScript - basically any header value or response body value - could be sniffed and intercepted via MITM XSS attacks.

It's better to store the JWT value in a secure-only, http-only cookie (cookie config: setSecure(true), setHttpOnly(true)). This guarantees that the browser will:

  1. only ever transmit the cookie over a TLS connection and,
  2. never make the cookie value available to JavaScript code.

This approach is almost everything you need to do for best-practices security. The last thing is to ensure that you have CSRF protection on every HTTP request to ensure that external domains initiating requests to your site cannot function.

The easiest way to do this is to set a secure only (but NOT http only) cookie with a random value, e.g. a UUID.

I don't understand why we need the cookie with the random value to ensure that external domains initiating requests to your site cannot function. This doesn't come free with Same-origin policy?

From OWASP:

Checking The Origin Header

The Origin HTTP Header standard was introduced as a method of defending against CSRF and other Cross-Domain attacks. Unlike the referer, the origin will be present in HTTP request that originates from an HTTPS url.

If the origin header is present, then it should be checked for consistency.

I know that the general recommendation from OWASP itself is Synchronizer Token Pattern but I can't see what are the vulnerabilities that remains in:

  • TLS + JWT in secure httpOnly cookie + Same-origin policy + No XSS vulnerabilities.

UPDATE 1: The same-origin policy only applies to XMLHTTPRequest, so a evil site can make a form POST request easily an this will break my security. An explicit origin header check is needed. The equation would be:

  • TLS + JWT in secure httpOnly cookie + Origin Header check + No XSS vulnerabilities.

解决方案

Summary

I had a misunderstood concepts about Same-origin policy and CORS that @Bergi, @Neil McGuigan and @SilverlightFox helped me to clarify.

First of all, what @Bergi says about

SOP does not prevent sending requests. It does prevent a page from accessing results of cross-domain requests.

is an important concept. I thought that a browser doesn't make the request to the cross domain accordingly to the SOP restriction but this is only true for what Monsur Hossain calls a "not-so-simple requests" in this excellent tutorial.

Cross-origin requests come in two flavors:

  • simple requests
  • "not-so-simple requests" (a term I just made up)

Simple requests are requests that meet the following criteria:

  • HTTP Method matches (case-sensitive) one of:
    • HEAD
    • GET
    • POST
  • HTTP Headers matches (case-insensitive):
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type, but only if the value is one of:
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain

So, a POST with Content Type application/x-www-form-urlencoded will hit to the server (this means a CSRF vulnerability) but the browser will not make accessible the results from that request. A POST with Content Type application/json is a "not-so-simple request" so the browser will make a prefligth request like this

OPTIONS /endpoint HTTP/1.1
Host: https://server.com
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: https://evilsite.com
Access-Control-Request-Headers: content-type
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: es-ES,es;q=0.8

If the server respond with for example:

Access-Control-Allow-Origin: http://trustedsite.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: content-type
Content-Type: text/html; charset=utf-8

the browser will not make the request at all, because

XMLHttpRequest cannot load http://server.com/endpoint. Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains the invalid value 'trustedsite.com'. Origin 'evilsite.com' is therefore not allowed access.

So I think that Neil was talking about this when he pointed out that:

the Same-origin Policy only applies to reading data and not writing it.

However, with the origin header explicit control that I proposed to Bergi I think is enough with respect to this issue.

With respect to my answer to Neil I didn't mean that that answer was the one to all my question but it remembered me another important issue about SOP and it was that the policy only applies to XMLHTTPRequest's.

In conclusion, I think that the equation

  • TLS + JWT in secure httpOnly cookie + Origin Header check + No XSS vulnerabilities.

is a good alternative if the API is in another domain like SilverlightFox says. If the client is in the same domain that the client I will have troubles with requests that doesn't include the Origin header. Again from the cors tutorial:

The presence of the Origin header does not necessarily mean that the request is a cross-origin request. While all cross-origin requests will contain an Origin header, some same-origin requests might have one as well. For example, Firefox doesn't include an Origin header on same-origin requests. But Chrome and Safari include an Origin header on same-origin POST/PUT/DELETE requests (same-origin GET requests will not have an Origin header).

Silverlight pointed this out to.

The only risk that remains is that a client can spoof the origin header to match the allowed origin, so the answer i was looking for was actually this

UPDATE: for those who watch this post, I have doubts about if the origin header is needed at all using JWT.

The equation would be:

  • TLS + JWT stored in secure cookie + JWT in request header + No XSS vulnerabilities.

Also, the previous equation has httpOnly cookie but this won't work if you got the client and the server in different domains (like many SPA application today) because the cookie wouldn't be sent with each request to the server. So you need access the JWT token stored in the cookie and send it in a header.

这篇关于为什么同源策略不足以防止 CSRF 攻击?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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