为啥在使用 setRequestHeader 制作 xmlhttprequest 时无法设置 cookie 和 set-cookie 标头?

Posted

技术标签:

【中文标题】为啥在使用 setRequestHeader 制作 xmlhttprequest 时无法设置 cookie 和 set-cookie 标头?【英文标题】:Why cookies and set-cookie headers can't be set while making xmlhttprequest using setRequestHeader?为什么在使用 setRequestHeader 制作 xmlhttprequest 时无法设置 cookie 和 set-cookie 标头? 【发布时间】:2013-02-18 08:16:26 【问题描述】:

我想知道为什么不能使用 setRequestHeader 设置 cookie 标头。是否有任何特定原因,或者仅仅是浏览器本身添加了它们,所以这些标头被禁用了?有什么安全问题吗?

--编辑

我正在研究 node.js 并使用了 xmlhttprequest 模块。以下是测试代码:

var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.withCredentials = true;
xhr.setRequestHeader('Cookie', "key=value");
xhr.send(null);

这里我需要将 cookie-header 设置为 node.js' xmlhttprequest,不要显式添加 cookie-header(就像浏览器那样)。尝试这样做时,xmlhttprequest 给出错误“Refused to set unsafe header”。

虽然我找到了一个补丁并且能够成功发送 cookie-header。但是想知道为什么禁用设置 cookie-header ?无论我在哪里阅读,都发现它是数据完整性和安全性所必需的,但是在这种情况下可以破坏哪些安全性,却没有提到任何地方。我想评估这个数据完整性问题是否也适用于 node.js 应用程序,如果我使用我的补丁。

【问题讨论】:

你能贴出让你这么想的代码吗?还是只是规范文件... @user395072 请查看已编辑的问题 【参考方案1】:

xhr.setRequestHeader('Cookie', "key=value"); 之前添加xhr._restrictedHeaders.cookie = false 但这是不好的方法,我不推荐使用它。

【讨论】:

【参考方案2】:

我认为这个答案不够完整。

正如所有人所说,由于安全完整性,您不能使用 xhr.setRequestHeader('Cookie', "key=value"); 发送任何数据(浏览器无法判断您添加的值是否是真正的 cookie)。

使用此特殊标头的预期方法是让客户端浏览器自动获取与您请求的站点相关的所有 cookie 并将它们放在“Cookie”标头中,您无需执行任何其他操作,如果您的 cookie 存在于您的浏览器中,它们将被发送。

...如果您想知道,存储在浏览器中的所有 cookie 都应该在每次来自您请求的服务器的响应向您发送回 Set-Cookie 标头时存储/更新。因此,在请求中添加“Set-Cookie”标头是没有意义的,因为它是仅为响应保留的标头,并且不需要在您的请求中添加“Cookie”标头,因为您的浏览器已经这样做了。

【讨论】:

【参考方案3】:

我相信你会通过working draft找到

上面的 headers 是由用户代理控制的,让它控制 运输的那些方面。

首先我们需要了解,这些标准作为不同浏览器之间功能互操作性的指南。它不是针对浏览器的强制要求,因此浏览器出于不同的原因对这个标准有不同程度的遵守。

其次,从技术上讲,您可以模拟用户代理,将您的程序视为浏览器,并且可以根据上述标准很好地设置这些值。

最后,禁止覆盖标头或为某些字段设置标头(例如 Content-LengthCookiesecure design approach )的意图。这是劝阻或至少试图劝阻HTTP Request smuggling。

【讨论】:

Manish,你能假设我可以硬编码在 javascript 提示符中询问的用户名和密码吗?我不能将其设置为假。我需要提供它。是否可以通过默认设置 cookie 来实现。感谢您的洞察力。【参考方案4】:

众所周知,对于浏览器,cookie(以及其他属性)需要仔细管理,以防止第三方窃取用户会话(或其他数据)。这是浏览器的问题,以及访问运行任意 Javascript 的网站的不受控制的性质。

当然,这种任意代码执行的风险对于 node.js 来说要么是低风险,要么是无风险,因为您只运行您编写的脚本,它可能会运行您计划的其他代码。

如果您查看 driverdan 的 XMLHttpRequest.js 的源代码,您会发现:

 // These headers are not user setable.   
 // The following are allowed but banned in the spec:   
 // * user-agent   
 var forbiddenRequestHeaders = [
    "accept-charset",
    "accept-encoding",
    "access-control-request-headers",
    "access-control-request-method",
    "connection",
    "content-length",
    "content-transfer-encoding",
    "cookie",
    "cookie2",
    "date",
    "expect",
    "host",
    "keep-alive",
    "origin",
    "referer",
    "te",
    "trailer",
    "transfer-encoding",
    "upgrade",
    "via"   ];

这回答了您的具体问题,即为什么限制特别适用于用于 node.js 的脚本 - 编码器遵循规范(尽可能接近),尽管感觉它可能不是节点中必需的安全预防措施.js。尽管如此,这个默认的安全级别还是很容易修改的。

正如 robertklep 指出的那样,您可以使用 setDisableHeaderCheck 方法禁用此默认预防措施。是的,这最后一点确实回答了您的问题或对您的问题做出了重大贡献,因为在您的问题中您说:

I have found a patch and successfully able to send the cookie-header

我们现在发现你不需要那个补丁。

祝你好运!

【讨论】:

【参考方案5】:

我能够使用以下 Gist 解决此问题: https://gist.github.com/killmenot/9976859

最初的想法取自这里:https://gist.github.com/jfromaniello/4087861

我遇到了几个问题:

    Source Gist 已过时,不适用于我。例如,“请求”库 API 已更改。 我可能会使用 socket.io-client 的“xmlhttprequest”库和 不要与 socket.io-client 安装在同一级别。 原来的“socket.io-client”(0.9.16)使用“xmlhttprequest”(1.4.2) 支持“setDisableHeaderCheck”方法(但 1.6.0 支持)。所以,我做 一个叉子并使用它https://github.com/intspirit/socket.io-client/tree/0.9.16+20140408120400

socket.io-client (1.0.0-pre) 使用使用正确版本的 xmlhttprequest 的 engine.io-client。我想将来我会使用 1.0.0 版本而不是我的 fork,指定“xhr-polling”传输并像原始 gist 那样模拟 XMLHttpRequest。

【讨论】:

在尝试跨源发送 cookie 时,没有多少补丁或库可以通过浏览器的限制。 gist 将 cookie 发送到自己的来源,这可以通过常规的 document.cookie 接口完成(参见 MDN)。【参考方案6】:

是的,它是数据完整性和安全性所必需的。要理解这一点,您必须了解 cookie 在 HTTP 请求方法中的作用。

Cookies 在识别用户、浏览器、连接等方面很重要,并存储在网络浏览器中。 JavaScript 允许您操作 cookie,但不是浏览器上的所有 cookie。 见HTTP cookies,这些只是浏览器设置的,所以用户不能滥用它(通过JavaScript)。

在受支持的浏览器上,仅使用 HttpOnly 会话 cookie 在传输 HTTP(或 HTTPS)请求时,从而限制访问 来自其他非 HTTP API(例如 JavaScript)。

当您发送 xmlhttprequest 时,它会读取 HttpOnly cookie 并通过 Cookie 标头发送到服务器。 现在,如果您执行 xhr.setRequestHeader('Cookie', "key=value"); ,您正在尝试篡改发送到服务器的 cookie。 setRequestHeader 将添加额外的 key=value,这可能会损害发送的 cookie 的完整性。

服务器使用这些来验证用户(会话、电子邮件帐户或任何帐户)。这实质上允许服务器防止滥用 cookie 来访问服务器。

【讨论】:

【参考方案7】:

您可以禁用此行为:

var xhr = new XMLHttpRequest();
xhr.setDisableHeaderCheck(true);
xhr.open(...);
...

【讨论】:

嗨@robertklep,您到底在哪里找到setDisableHeaderCheck 的规范?你能给我指个医生什么的吗?这也不起作用/未在 chrome 22 中实现。编辑:这不是 canari 中的事件 @MarcelFalliere 我们说的是node-XMLHttpRequest 库(它实现了it here),而不是浏览器中的XMLHttpRequest :) 你在开玩笑吗?没有这样的功能 XMLHttpRequest.setDisableHeaderCheck(true) @ShailendraSinghRajawat 再次查看 this piece of code。 @ShailendraSinghRajawat 正如我之前在 cmets 中解释的那样:我的答案与浏览器中的 XMLHttpRequest 无关,而是与 Node.js 模块 node-XMLHttpRequest 相关。 OP 对此模块有问题,我为该特定环境提供了一个可能的答案,而不是在浏览器中工作的通用答案。【参考方案8】:

文档提到这样做是为了保护数据完整性。 http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader%28%29-method

上面的 headers 是由用户代理控制的,让它控制 运输的那些方面。这保证了某些数据的完整性 程度。以 Sec- 开头的标题名称不允许设置为 允许铸造新的标头,保证不会来自 XMLHttpRequest。

【讨论】:

对不起,由于我在开发网络应用程序方面经验不足,无法正确获取。您能否举例说明 - 这样做可以保护什么样的数据完整性?

以上是关于为啥在使用 setRequestHeader 制作 xmlhttprequest 时无法设置 cookie 和 set-cookie 标头?的主要内容,如果未能解决你的问题,请参考以下文章

xhr.setRequestHeader() 合并我的标题

为啥javascript加载xml文件,在Chrome下不成功

为啥我的服务器会忽略来自 ajax 请求的身份验证标头?

ajax中的setRequestHeader设置请求头

为啥在 html5 中使用画布制作动画?

Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state mus