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
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).