【问题标题】:Why Same-origin policy isn't enough to prevent CSRF attacks?为什么同源策略不足以防止 CSRF 攻击?
【发布时间】:2016-01-20 13:32:32
【问题描述】:

首先,我假设有一个控制输入以防止 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 本身的一般建议是同步器令牌模式,但我看不出还有哪些漏洞:

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

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

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

【问题讨论】:

  • SOP 不会阻止发送请求。它确实会阻止页面访问结果的跨域请求。
  • @Bergi 在后端包含一个显式控件来检查原始标头怎么样?如果检查失败,我会立即返回错误状态码。

标签: cookies jwt cross-domain csrf same-origin-policy


【解决方案1】:

为什么同源策略不足以防止 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 存在一些漏洞,可以让客户端更改它。基本上,您会相信 Adob​​e 不会在未来搞砸任何事情……这听起来是个好主意吗?

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

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

【讨论】:

【解决方案2】:

我只是想总结一下答案。

  1. 正如其他提到的,SOP 仅适用于 XmlHttpRequests。这意味着按照规范,浏览器必须发送 ORIGIN 标头以及通过 XmlHttpRequests 发出的请求。
  2. 如果您在提交表单时选中Chromium,也会发送origin。然而,这并不意味着其他浏览器会这样做。下图说明了在 Firefox 中发出的两个 post 请求。一个是由submitting 制作的,另一个是使用XHR 制作的。这两个请求都是从http://hack:3002/changePasswordhttp://bank:3001/chanePassword 发出的。
  3. 如果请求来自同一个域,则允许浏览器不发送origin 标头。所以服务器应该只在设置了源头时才检查源策略。

结论是:如果您使用 cookie 并且请求到达服务器时没有 origin 标头,则您无法区分它是通过从另一个域提交表单还是由同一域内的 XHR 生成的。这就是您需要对 CSRF 进行额外检查的原因。

【讨论】:

    【解决方案3】:

    总结

    @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。

    总之,我认为等式

    • TLS + JWT 在安全的 httpOnly cookie + 源头检查 + 无 XSS 漏洞。

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

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

    Silverlight 指向this

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

    更新:对于那些观看这篇文章的人,我有 doubts 关于是否需要使用 JWT 的原始标头。

    等式是:

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

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

    【讨论】:

    • 从你的最后一段中,我觉得我们想要“TLS + JWT 存储在安全 cookie + JWT 中的请求标头 + 没有 XSS 漏洞。”因为 httpOnly 标志是关闭的,所以 cookie 仍然是跨域发送的。如果我们打开 httpOnly 标志,那么 csrf 不会有问题吗?因为正如您提到的,cookie 不是跨域发送的?
    • 嗯,在您最终建议的解决方案中,cookie 中的 jwt 可以从客户端 Javascript 读取吗?否则应用程序将如何在请求标头中发送它?
    • 如果是,那它不会易受xss影响吗?
    猜你喜欢
    • 2021-07-06
    • 2010-11-27
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 2018-01-08
    • 2021-06-26
    • 1970-01-01
    • 2015-09-28
    相关资源
    最近更新 更多