How secure is HTTP_ORIGIN?
Asked Answered
G

7

43

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?

Gosney answered 30/12, 2010 at 21:24 Comment(5)
@RichardW11 where can i find info about $_SERVER['ORIGIN']? you sure is it correct?Poll
@GianpaoloDiNino Hi, I deleted my comment because I wanted to clarify. That day was busy, and the comment wasn't very accurate. Here is what I do know. When I was creating a javascript api, connecting via a php app. The mozilla browser wasn't accepting my request. When researching. It turned out that I was looking for HTTP_ORIGIN, however the browser was sending $_SERVER[ORIGIN]. To solve the problem I just created the script to look for either version. You can verify this on your end. It might also be the version of mozilla. Let me know if this helps.Drucilladrucy
@RichardW11 i did not find anything about that. We use the http_origin + http_host as fallback.Poll
@GianpaoloDiNino yes odd. Here is screenshot from Mozilla. i.imgur.com/9YEvpfj.png Oddly enough, other javascript request on the site, doesn't have that header being sent. What browsers will send the http_host?Drucilladrucy
@GianpaoloDiNino just doubled checked. When in the network view of mozilla, it shows Origin, but it turns out they are just cleaning up the headers to only show Origin. However, in reality it is sending http_origin. Thanks for challenging. Your help was appreciated.+1Drucilladrucy
H
64

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

Hardhearted answered 10/11, 2011 at 22:26 Comment(5)
Just a note that my Mac Chrome 18.0 says "Origin" in the header not "HTTP_ORIGIN".Militarism
@MauvisLedford: You mean the server side ? That code is php so "HTTP_ORIGIN" is php-only probably. Original header should be "Origin". That code was tested with Apache server, some of the $_SERVER keys might be missing or differ on other servers.Hardhearted
Checking the Origin header helps protect against XSRF but does not provide complete protection. Note that you report the the Origin header is not set for IMG tags meaning an attacker can use that to attack your site. Also you said that you only use Chrome. It's what browser your users use that matters. See j.mp/learn-xsrf to learn how to fully protect your app.Sollars
@Sollars Nobody said it is a complete protection for everyone. IMG tag could be used for an attack only if you do not follow good practices. You should never allow to modify sensitive data through GET requests.Hardhearted
I added the comment because I thought people reading through your comment might think that checking Origin was enough. I didn't mean that you thought that. Security bugs are frequently caused by developers not following good practices sufficiently. For example, a bug that allows data to be modified via GET request combined with insufficient XSRF protection when Origin header is missing = vulnerability.Sollars
F
32

HTTP_ORIGIN is neither sent by all browsers nor is it secure.

Nothing sent by the browser can ever be considered safe.

Flavourful answered 30/12, 2010 at 21:27 Comment(13)
Browsers play a vital role in enforcing web security. If you trust the browser, you can trust the HTTP_ORIGIN they send. There are instances when you don't want to trust any random HTTP client. In cases like that, your comment applies. Nothing from the browser can be trusted.Fargone
@Fargone You can never trust the browser.Flavourful
@Flavourful You can rely on the browser acting on the users best behalf. It won't protect you from the user, but it can help protect both developer and user from a third party (as in the case of CSRF/session-hijacking) when combined with HTTPS.Consubstantiate
@Consubstantiate Meaningless if true (you still have to distrust the user/browser input), and false anyways. The browser could be infected with malware that makes it send out malicious requests the user isn't aware of.Flavourful
@Flavourful If that's the case then the user's cookies have already been compromised and the user's session could be hijacked regardless. I'm not saying you should protect the server by relying on HTTP_ORIGIN, but you can protect the user from CSRF/session hijacking using it.Consubstantiate
@Consubstantiate You seem to be focusing on CSRF, but there are other issues at play. A developer might save HTTP_ORIGIN into the database and cause a SQL vulnerability, for example. It should be treated like any other piece of data a malicious user could control.Flavourful
@Flavourful I know there is more at play, and I never said it was a good idea to use it for anything else than CSRF protection. I just don't like blanket statements like "Nothing sent by the browser can ever be considered safe" when it's certainly safe for CSRF protection, it all depends on what you do with it. I don't say the server should trust the browser, I say that if the user uses a secure browser, then the server can use that to secure the user from attack. I still agree with the statement when used as a heuristic, but I find it slightly crude. Sorry if I'm nitpicking unnecessarily.Consubstantiate
Well, now days it is sentAllochthonous
@ThatRealtyProgrammerGuy Any malicious user can still modify it, and some clients, like curl, still won't send it. You simply cannot trust user-modifiable input; someone could send an Origin with SQL injection in it, for example.Flavourful
Indeed, that's why I only said "sent" -- at the time you wrote this answer, most browsers did not send Origin and now all of them do. That said ultimately, if you are serving a website; you have no choice but to trust user input. You don't have to trust it so far that you save the data, but at the very least you must use it to decide what resource to load from host and URI data in the request. That's what a request is, and what this question is about.Allochthonous
..continued. Ideally you match host with known whitelist, then do CORS handshake over HTTPS so you can rely on their SSL cert after that check. But to resolve what host to run it against you have to use some string(s) request opening. Once that process is complete you CAN trust the data from the browser as you have upgraded its authenticity.Allochthonous
@ThatRealtyProgrammerGuy No, that's not "what this question is about". Re-read it; I'll quote from it. "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." If OP is concerned with those specific attack models, an Origin header is similarly vulnerable.Flavourful
@Flavourful again, yes of course someone can use telnet to request a URL. The purpose of Origin is not to authenticate the client but to be capable of authenticating the requested host. I did not imply it was not vulnerable. Simply it is A) no longer true that Origin is not sent B) it's vulnerabilities can be cleaned prior to entering the application code C) proper use of Origin is component of a highly effective solution to secure, cross-origin resource sharing.Allochthonous
V
20

People here are thinking about this all wrong -- the 'CORS' standard isn't so the server doesn't get hacked, even if it helps that in addition to what it does. The purpose is to allow 'THE BROWSER' to have a way of easing up on requests that go against the same origin policy. If the client and the server are on the same page, then the 'CLIENT' can decide whether or not to allow the request.

Obviously by having the server participate in the decision you are helping in the security process.

But it won't protect the server from unauthorized access - that is what passwords and cookies are for.

The client can be (as someone mentioned) a telnet tool, where every single thing crafted is fake.

But one of Chrome's, and FF's, etc, selling points is that they will help you by not allowing Javascript to go outside of the same origin sandbox, which means the only thing by default that can be compromised is the stuff that is on the 'attackers' own website. Or other sites that decide to not be secure.

CORS is the technology that allows you to say -- hey, I want users to be able to consume my snazzy service from the javascript on this other site they use. So I'm gonna add this site to my exceptions. Which means you are helping your authorized users poke a hole in their browser security for that particular site. Which means a hole that a hacker can exploit. Thus the care with which you set up the service, right?

This means that any site that doesn't have CORS set up is by default secure from Cross Site Scripting from a compliant browser (barring bugs and hacks of course). The browser will ask if this service wants to participate in the origin site's javascript, and if the cross site says "I don't know nothing about this damn site", then the browser's javascript engine will close the connection and dump the data.

So just to summarize -- CORS doesn't help you make thing secure. It helps you make a hole in your browsers ability to make a user more secure. But hopefully in a managed way.. and only for particular sites..

Vanvanadate answered 11/10, 2015 at 2:7 Comment(2)
A very good summary of what CORS is doing. I'll argue however, that CORS is making the industry safer and this is the intended purpose. While a CORS request is ultimately allowing a gap in your security; much cruder methods of circumventing restrictions were afoot.Allochthonous
Just to be clear, I was talking about the protocol, and not the overall change. The overall change included shutting down cross site scripting except for simple requests.. and then having the scripted requests participate in a CORS protocol. Just like with ACL's: implicit DENY means by default deny everything, and ALLOW creates holes. It not that ALLOW is insecure - its part of a security protocol where the part it plays is to make a hole. I hope this makes sense, and I can change the answer if needed.Vanvanadate
C
17

HTTP is a plain-text protocol. The ENTIRE request header/body structure can be faked to say anything you want.

Causative answered 30/12, 2010 at 21:28 Comment(1)
What about HTTPS? Does it also apply to sites served via HTTPS?Diffractometer
B
9

Everything in the HTTP request can be faked.

Barros answered 30/12, 2010 at 21:28 Comment(3)
Except REMOTE_ADDR is not part of the HTTP protocol, and can't be effecively faked when using HTTP.Turkey
@MichaelBorgwardt what about proxy ?Gaeta
@nasirbest It's not fake in that case either, the request really did come from the proxy. That the proxy was forwarding the request from somewhere else is beyond the scope of this question and not really different from a case where the request is done by a browser instance running on a server but controlled via VNC by a user sitting in front of a completely different computer.Turkey
T
6

Upgraded:

function isOriginAllowed($incomingOrigin, $allowOrigin)
{
    $pattern = '/^http:\/\/([\w_-]+\.)*' . $allowOrigin . '$/';

    $allow = preg_match($pattern, $incomingOrigin);
    if ($allow)
    {
        return true;
    }
    else
    {
        return false;
    }
}

$incomingOrigin = array_key_exists('HTTP_ORIGIN', $_SERVER) ? $_SERVER['HTTP_ORIGIN'] : NULL;
    $allowOrigin    = $_SERVER['HTTP_HOST'];

    if ($incomingOrigin !== null && isOriginAllowed($incomingOrigin, $allowOrigin))
    {
        exit("CSRF protection in POST request: detected invalid Origin header: " . $incomingOrigin);
    }

Example:

  • http:// media.mydomain.com TRUE
  • http:// offline.mydomain.com TRUE
  • http:// domen1.mydomain.com TRUE
  • http:// domen_1.mydomain.com TRUE
  • http:// domen-1.mydomain.com TRUE
  • http:// ololomydomain.com FALSE
  • http:// mydomain.com TRUE
  • http:// pro.mydomain.com TRUE
  • http:// super.pro.mydomain.com TRUE
  • http:// super.pro.fakemydomain.com FALSE
  • http:// pro.fakemydomain.com FALSE
Tohubohu answered 26/9, 2012 at 10:42 Comment(0)
D
2

Update, as of 2021:

HTTP_ORIGIN is almost fully supported by all browsers, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin#browser_compatibility

Debacle answered 12/11, 2021 at 15:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.