HTTP_ORIGIN 的安全性如何?

2022-01-04 00:00:00 php dns http-request

我想查明来自第三方网站的传入 HTTP_REQUEST 调用是否来自我定义的域列表.

我知道可以使用 HTTP_REFERER 来查找第三方域的位置,但它不够安全.人们可以欺骗它或使用 Telnet 来伪造它.

那么,HTTP_ORIGIN 怎么样?它是从所有浏览器发送的吗?安全吗?

此外,人们可以在 HTTP_REQUEST 调用中伪造 REMOTE_ADDR 吗?

解决方案

HTTP_ORIGIN 是一种防止CSRF(跨站点请求伪造)请求的方法.目前它仅由 Chrome 实现(截至 2011 年 11 月).我测试了 Firefox 和 Opera,但它们都失败了.

它在请求头中的名字是Origin.在我的 PHP 脚本中的服务器上,我将其视为 $_SERVER 数组中的 HTTP_ORIGIN.此标头仅在某些情况下发送,当需要针对 CSRF 进行保护时(仅 POST 就足够了).这是所有请求的列表,无论是否设置:

https://wiki.mozilla.org/Security/Origin

  • 锚标记 - 否
  • 窗口导航 - 否
  • IMG - 没有
  • iframe、嵌入、小程序 - 是
  • 表单(GET 和 POST) - 是
  • 脚本 - 是
  • 样式表 - 否
  • 来自样式表的依赖加载 - 否
  • 重定向 - 是
  • XHR - 是

不幸的是,Origin 标头仅在 Chrome 中实现.它于 2010 年 1 月在 Google Chrome 的博客上首次宣布:

http://blog.chromium.org/2010/01/security-in-depth-new-security-features.html

<块引用>

通过源头的CSRF保护

<块引用>

Origin 标头是一项新的 HTML5 功能,可帮助您保护站点免受跨站点请求伪造 (CSRF) 攻击.在 CSRF 攻击中,一个恶意网站(例如 attack.com)会指示用户的浏览器向目标服务器(例如 example.com)发送 HTTP 请求,从而使 example.com 服务器混淆以执行某些操作.例如,如果 example.com 是网络邮件提供商,CSRF 攻击可能会诱使 example.com 将电子邮件转发给攻击者.

<块引用>

Origin 标头通过识别生成请求的网站来帮助站点抵御 CSRF 攻击.在上面的示例中,example.com 可以看到请求来自恶意网站,因为 Origin 标头包含值 http://攻击者.com.要将 Origin 标头用作 CSRF 防御,站点应仅在响应以下请求时修改状态:(1) 缺少 Origin 标头或 (2) 具有带有白名单值的 Origin 标头.

我只是在我的PHP脚本中实现CSRF保护,我个人使用Chrome,所以对我来说已经足够了,我希望其他浏览器能尽快赶上Chrome.

有趣的是 Mozilla 发明了该安全功能,因为您可以在其网站上阅读有关 Origin 标头的大量文档,但他们仍然没有时间实施它;-)

HTTP_ORIGIN 似乎只包含 protocoldomain,末尾没有斜线:http://www.example.com"- 即使您从http://www.example.com/myform/"提交表单.

PHP 脚本中针对 CSRF 的简单保护:

if ($_SERVER['REQUEST_METHOD'] == 'POST') {如果 (isset($_SERVER['HTTP_ORIGIN'])) {$address = 'http://'.$_SERVER['SERVER_NAME'];如果 (strpos($address, $_SERVER['HTTP_ORIGIN']) !== 0) {exit('POST 请求中的 CSRF 保护:检测到无效的 Origin 标头:'.$_SERVER['HTTP_ORIGIN']);}}}

此脚本仍可升级以支持 80 以外的 PORT(Origin 包含不同于 80 的端口)、HTTPS 连接以及提交来自不同子域的表单(例如 sub.example.com => 发布请求www.example.com).

I want to find out whether an incoming HTTP_REQUEST call from a third party website is coming from the list of domains that I defined.

I know that HTTP_REFERER can be used to find out where the third party domain is, but it is not secure enough. People can spoof it or use Telnet to fake it.

So, how about HTTP_ORIGIN? Is it sent from all browsers? Is it secure?

Also, can people fake the REMOTE_ADDR in a HTTP_REQUEST call?

解决方案

HTTP_ORIGIN is a way to protect against CSRF (Cross Site Request Forgery) requests. Currently it is implemented only by Chrome (as of Nov 2011). I tested Firefox and Opera, but they failed.

Its name in the request header is Origin. On the server in my PHP script I see it as HTTP_ORIGIN in the $_SERVER array. This header is sent only in some cases, when protection against CSRF is required (only POST should be sufficient). Here is list of all requests whether it is set or not:

https://wiki.mozilla.org/Security/Origin

  • Anchor tag - NO
  • Window navigation - NO
  • IMG - NO
  • iframe, embed, applet - YES
  • Form (GET and POST) - YES
  • SCRIPT - YES
  • stylesheets - NO
  • dependent loads from stylesheets - NO
  • Redirects - YES
  • XHR - YES

The Origin header is implemented only in Chrome, unfortunately. It was announced first in January 2010 on Google Chrome's blog:

http://blog.chromium.org/2010/01/security-in-depth-new-security-features.html

CSRF Protection via Origin Header

The Origin header is a new HTML5 feature that helps you defend your site against cross-site request forgery (CSRF) attacks. In a CSRF attack, a malicious web site, say attacker.com, instructs the user's browser to send an HTTP request to a target server, say example.com, that confuses the example.com server into performing some action. For example, if example.com is a webmail provider, the CSRF attack might trick example.com into forwarding an email message to the attacker.

The Origin header helps sites defend against CSRF attacks by identifying which web site generated the request. In the above example, example.com can see that the request came from the malicious web site because the Origin header contains the value http://attacker.com. To use the Origin header as a CSRF defense, a site should modify state only in response to requests that either (1) lack an Origin header or (2) have an Origin header with a white-listed value.

I am just implementing CSRF protection in my PHP script, I personally use Chrome, so that is sufficient for me, I hope other browsers will catch up with Chrome soon.

What is funny is that Mozilla invented that security feature, as you can read lots of documentation of that Origin header on its website, but they still didn't have time to implement it ;-)

HTTP_ORIGIN seems to contain only protocol and domain, without slash at the end: "http://www.example.com" - even if you submit the form from "http://www.example.com/myform/".

A simple protection against CSRF in PHP script:

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if (isset($_SERVER['HTTP_ORIGIN'])) {
        $address = 'http://'.$_SERVER['SERVER_NAME'];
        if (strpos($address, $_SERVER['HTTP_ORIGIN']) !== 0) {
            exit('CSRF protection in POST request: detected invalid Origin header: '.$_SERVER['HTTP_ORIGIN']);
        }
    }
}

This script could still be upgraded to support PORT other than 80 (Origin contains the port when it's different than 80), HTTPS connections, and submitting the forms from different subdomains (ex. sub.example.com => posting request to www.example.com).

相关文章