为啥 CORS 中没有针对具有标准内容类型的 POST 请求的预检

Posted

技术标签:

【中文标题】为啥 CORS 中没有针对具有标准内容类型的 POST 请求的预检【英文标题】:Why is there no preflight in CORS for POST requests with standard content-type为什么 CORS 中没有针对具有标准内容类型的 POST 请求的预检 【发布时间】:2017-02-05 03:52:58 【问题描述】:

我对 CORS POST 请求的安全方面有点困惑。我知道网上有关此主题的信息丢失了,但我找不到我的问题的明确答案。

如果我理解正确,同源策略的目标是防止 CSRF 攻击,而 CORS 的目标是在(且仅当)服务器同意与托管在其他服务器上的应用程序共享其数据时启用资源共享网站(来源)。

HTTP 指定 POST 请求不是“安全的”,即它们可能会改变服务器的状态,例如通过添加新评论。当使用 HTTP 方法 POST 发起 CORS 请求时,如果请求的内容类型是非标准的(或者如果存在非标准的 http 标头),浏览器只会执行“安全”的预检请求。因此,具有标准内容类型和标准标头的 POST 请求会被执行,并且可能会对服务器产生负面影响(尽管请求脚本可能无法访问响应。)

有一种向每个表单添加随机令牌的技术,然后服务器要求它成为每个非“安全”请求的一部分。如果脚本试图伪造请求,它要么

    没有随机令牌,服务器拒绝请求,或者 它尝试访问定义随机令牌的表单。这个带有随机令牌的响应应该有适当的头字段,这样浏览器就不会授予恶意脚本访问这个响应的权限。在这种情况下,尝试也会失败。

我的结论是,针对具有标准内容类型和标头的伪造 POST 请求的唯一保护是上述技术(或类似技术)。对于任何其他非“安全”请求,例如 PUT 或 DELETE,或带有 json-content 的 POST,不必使用该技术,因为 CORS 执行“安全”OPTIONS 请求。

为什么 CORS 的作者将这些 POST 排除在预检请求之外,因此有必要采用上述技术?

【问题讨论】:

【参考方案1】:

见What is the motivation behind the introduction of preflight CORS requests?。

CORS 不要求浏览器对 application/x-www-form-urlencodedmultipart/form-datatext/plain 内容类型进行预检的原因是,如果这样做,这会使 CORS 比浏览器一直允许的限制更严格(并且 CORS 的目的不是对没有 CORS 的情况下已经可能的事情施加新的限制)。

也就是说,使用 CORS,您以前可以跨域执行的 POST 请求不会被预检——因为在 CORS 存在之前浏览器已经允许它们,并且服务器知道它们。因此,CORS 不会改变那些“旧”类型的请求。

但在 CORS 之前,浏览器根本不允许您进行跨域 application/json POST,因此服务器可以假设他们不会收到它们。这就是为什么这些类型的“新”请求而不是“旧”请求需要 CORS 预检的原因 - 以提醒服务器:这是一种不同的“新”请求类型,他们必须明确选择 -支持。

【讨论】:

确实,我们允许 POST,因为 <form> 已经这样做了,我们无法限制 <form> 换句话说,允许旧的内容类型,以免破坏浏览器允许旧内容类型的已构建 Web 应用程序。因此,意图是向后兼容浏览器的行为。如果政策对浏览器添加更多限制,Web 应用程序将开始失败。

以上是关于为啥 CORS 中没有针对具有标准内容类型的 POST 请求的预检的主要内容,如果未能解决你的问题,请参考以下文章

如果我在使用 cors 时添加标准 http 标头,为啥会预检请求?

CORS:为啥我的浏览器不发送 OPTIONS 预检请求?

针对具有 IdentityServer3 授权的 MVC 控制器的 Ajax 请求中的 CORS

java中vo与po的转换

为啥我的 API 中没有启用 CORS?

为啥 $.support.cors 在 IE 11 中为假?