26

I want to create an API, and to authenticate API consumers, I will provide an API KEY, App-id and App-Secret. The problem is that I want to know where the http Request is coming from, so that I can know if the Host that is making que request is the registered Host. For example : www.someone.com has an app-id :0001, app-secret:1200 and api-key:458. If this credentials are used to make A request, I want to know if the requester is really www.someone.com

m_junior
  • 591
  • 1
  • 8
  • 19
  • 2
    For origin use this `header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN'] . "");` and then check credentials from GET or POST variable – hex494D49 Aug 27 '14 at 06:15
  • 3
    Using the origin as a security measure is beyond useless. This header can easily [be faked](https://requestable.pieterhordijk.com/imCuvc). Instead you might want to work with a callback to pass some "request token" (think about how the oauth flow works). – PeeHaa Aug 27 '14 at 07:57
  • Using HTTP_ORIGIN or HTTP_REFERER without checking them is "in essence" the same as doing "*" which can open up subtle security holes so is discouraged, see http://stackoverflow.com/questions/12001269/what-are-the-security-risks-of-setting-access-control-allow-origin – rogerdpack Apr 14 '17 at 19:03
  • An answer to the actual question **"How to get http request origin"** can be found here: https://stackoverflow.com/questions/41326257/how-i-can-get-origin-of-request-with-php#answer-41335048 – Martin Schneider Jul 03 '17 at 17:24

7 Answers7

26

Generally, this header should do the job. Having the domain name in this header

header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN'] . "");
// use domain name instead of $_SERVER['HTTP_ORIGIN'] above

but if you want to check for more info, use something like the following snippet

$allowed = array('domain1', 'domain2', 'domain3'); 

if(isset($_SERVER['HTTP_ORIGIN']) && in_array($_SERVER['HTTP_ORIGIN'], $allowed)){
    // SELECT credentials for this user account from database
    if(isset($_GET['api_key'], $_GET['app_secret'])
        && $_GET['api_key'] == 'api_key_from_db' 
        && $_GET['app_secret'] == 'app_secret_from_db'
    ){
        // all fine
    }else{
        // not allowed
    }
}else{
    // not allowed
}

If the users have to pass more data to your service, use POST instead of GET

Martin Schneider
  • 14,263
  • 7
  • 55
  • 58
hex494D49
  • 9,109
  • 3
  • 38
  • 47
  • If the $_SERVER['REMOTE_ADDR'] variable returns me the Client_IP and not the website address, How am I supposed to autheticate the website?? – m_junior Aug 27 '14 at 14:12
  • @m_junior `$_SERVER['REMOTE_ADDR']` returns the IP address of the server under which the current script is executing. – hex494D49 Aug 27 '14 at 14:18
  • 1
    @m_junior The `$allowed` array from above may look even this way `$allowed = array('domain1' => '1.2.3.4', 'domain2' => '5.6.7.8', 'domain3' => '2.4.6.8');` and then you can use `gethostbyname('domain')` and compare returned IP of the host with the IP in your array. – hex494D49 Aug 27 '14 at 14:42
  • Does it mean that If an website has a javascript that makes a post to my API, once I receive the request the $_SERVER['REMOTE_ADDR'] WILL be filled with the website IP and not the client IP??? sorry for the ignorance level! – m_junior Aug 27 '14 at 14:50
  • @m_junior No worries, feel free to ask :) If you need the IP of the host (where the website is hosted) use `gethostbyname('www.your-client.com')` but if you need the IP of the computer from where the request came from, use `$_SERVER['REMOTE_ADDR']` – hex494D49 Aug 27 '14 at 14:57
  • Instead of putting every possible origin in, which is bad by default, you could also use `*`, which is not better. This answer introduces a security problem. – Daniel W. Jun 16 '16 at 14:14
  • @DanFromGermany Pointing to something that might seem to you wrong and at the same time not providing any other, maybe a better solution, is by default a very bad, selfish and even childish attitude. – hex494D49 Jun 17 '16 at 11:49
  • @DanFromGermany how is having a white-list of permitted origins a bad thing? – Mike Willis Sep 09 '16 at 13:48
  • Not all user webservers will set this, and some provide the ability to modify HTTP_ORIGIN as a feature. In short, it cannot really be trusted. – LeonanCarvalho Feb 03 '17 at 10:58
  • @DanFromGermany @LeonanCarvalho : `Access-Control-Allow-Origin` header doesn't introduce a security problem. There is no difference in security on the server side if that header is set ot not. This header is only there for adding security on the end-user-side. So no malicous website may use your API and receive user session data (cookies). And this only if the user is using a common browser that listens for this header and hasn't been manipulated (by virus etc). To secure the server side, other measures must be taken. – Martin Schneider Jul 03 '17 at 16:49
  • Anyway it is better to only set `header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN'] . "");` within the first `if` statement. – Martin Schneider Jul 03 '17 at 17:01
  • 1
    @hex494D49 why do you rejected my edit? Your code has 4 syntax errors and isn't optimal formatted for SO. – Martin Schneider Jul 03 '17 at 21:37
  • 1
    I am not sure anymore what happened when I commented like a year ago. Important is the array `$allowed` and that makes it a good answer. – Daniel W. Jul 04 '17 at 07:36
  • @MA-Maddin As a reason for editing, you mentioned "improved formatting" and you didn't mention any syntax errors. I personally don't like spaces after each keyword, so I thought your editing actually isn't an improvement. But since you're right about syntax errors, I left them so you can correct them (again) and I'll accept your edit. Sorry and thanks :) – hex494D49 Jul 04 '17 at 07:53
  • @DanFromGermany Just wanted to thank you for your last comment :) – hex494D49 Jun 29 '18 at 14:33
  • I have a question. Can't the `HTTP_ORIGIN` value be spoofed/faked? – Rotimi Feb 06 '19 at 11:22
12

Laravel 5: in request method controller:

$origin = request()->headers->get('origin');
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
  • 2
    to get all headers: `request()->headers->all();` – Kamil Kiełczewski Apr 11 '19 at 13:41
  • Can't an unauthorized person simply change the request headers in his client to send a domain of an authorized domain and this way circumvent the check? – Aleksandar Feb 04 '20 at 10:49
  • I just found the answer on a different thread: https://stackoverflow.com/a/21058346/4688612 – Aleksandar Feb 04 '20 at 10:53
  • 1
    `origin` is not sent with GET – mangusta May 27 '20 at 01:45
  • @mangusta browser add `origin` header for CORS requests - [more here](https://stackoverflow.com/a/59353387/860099) - if you don't send CORS request then browser not add this header and probably php not set it too (or probably set some default value - but I don't check this on php side ). – Kamil Kiełczewski May 27 '20 at 10:10
5

Use $_SERVER['HTTP_REFERER']. It is the address of the page (if any) which referred the user agent to the current page. This is set by the user agent. Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature.

For further restrictions you can perform the following. example.com should be changed to your domain.

IIS set below in web config:

add name="Access-Control-Allow-Origin" value="http://www.example.com"

Apache set below in httpd.conf/apache.conf

Header add Access-Control-Allow-Origin "http://www.example.com"
jww
  • 97,681
  • 90
  • 411
  • 885
Sunit
  • 403
  • 1
  • 5
  • 6
  • 18
    The referrer and the origin are two different things. – Daniel W. Jun 16 '16 at 14:15
  • Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. In short, it cannot really be trusted. – LeonanCarvalho Feb 03 '17 at 11:00
  • A better answer to that question can be found here: https://stackoverflow.com/questions/41326257/how-i-can-get-origin-of-request-with-php#answer-41335048 – Martin Schneider Jul 03 '17 at 17:23
  • 1
    As @DanFromGermany touched on, ORIGIN and REFERER are two different things - `HTTP_ORIGIN` is the better in this case than `HTTP_REFERER`; if `HTTP_ORIGIN` is missing then you may wish to fall back to using `HTTP_REFERER`, but I would advise against this for security (it's easier to change the referer than the origin, as origin is listed as a "forbidden" header and browsers *should* prevent any changes to origin from taking place). – SteJ Apr 23 '18 at 09:59
5

Technically neither origin nor referer are required HTTP headers, all of these answers are based on specific browser headers sent, and basing your system on different behaviors of clients is a bad idea.

The correct answer is you can't reliably get the client origin on every request because it isn't required as part of the HTTP specification.

slothstronaut
  • 921
  • 1
  • 13
  • 15
3

Using a var_dump you can see all that the request has to offer.

var_dump($_REQUEST);

Do a var_dump on the server global as well. It contains alot of usefull information.

var_dump($_SERVER);
Peter
  • 8,776
  • 6
  • 62
  • 95
  • 1
    I use this one on my front end server and I forgot to remove it and the server got hacked. Very dangerous for a lot 'useful information' – MaXi32 Nov 09 '19 at 03:57
2

I think what you mean is that you want to access the "Origin" header in the request headers (as opposed to setting it in the response headers).

For this the easiest way is to access the built in getallheaders() function - which is an alias for apache_request_headers() - N.B. this is assuming you are using php as a module.

This returns an array so the Origin header should be available like this:

$request_headers = getallheaders();
$origin = $request_headers['Origin'];

If you are using php via something like fastcgi then I believe it would be made available in the environment - usually capitalised and prefixed by "HTTP_" so it should be $_SERVER['HTTP_ORIGIN'].

Hope that helps anyone else looking for this :)

Paolo Gibellini
  • 310
  • 13
  • 21
sensadrome
  • 472
  • 2
  • 7
0

in laravel 7 this worked for me

request()->headers->get('referer');

Ar0010r
  • 11
  • first check it with request()->headers; then you can add "->get(' ..needed parameter.. ');" – Vit Apr 03 '20 at 12:48