what is the usage of the following function? - php

Take a look to this function please
function CheckHost()
{
$url = parse_url($_SERVER['HTTP_REFERER']);
$host = $url['host'];
if($host == $_SERVER['SERVER_NAME'])
return true;
return false;
}
i saw it somewhere, but can't understand it's usage.
is it for security reasons, or what?(as i see, it just verify is the last request from the same server as the script)
Thanks for attention

I suppose it's a simple check against cross-site request forgeries (CSRFs), or as others say, hotlinking. The PHP script calling this function would have to be executed on every HTTP request to the server in order to check for hotlinking, though.

It looks like its checking to see that the referrer is the same host name as the request. This is probably used for something like preventing other sites from directly linking to images or other content.

This can be used for CSRF protection. The Referer will always be of a differnt domain and thus CheckHost() will return false.

It checks whether the referer is equal to the script location, basically its function is probably to prevent hotlinking.

Related

$_SERVER['REQUEST_URI'] reliability?

In one of my websites I use $_SERVER['REQUEST_URI'] to establish whether a non-registered user can see the content of a page or not.
In the manual there is written about $_SERVER['REQUEST_URI']:
The URI which was given in order to access this page; for instance,
'/index.html'.
My question is, is it in any client side way possible for a client to access eg. index.php even though $_SERVER['REQUEST_URI'] contains a different value?
I know that $_SERVER['REQUEST_URI'] contains the page that the client asked and that the server returns but if I don't ask myself these kind of questions once in a while I'm not happy
Also is it considered good practice to use $_SERVER['REQUEST_URI'] in this way?
EDIT: I included the script I use as it was too generic
list($c_page) = explode('.',substr($_SERVER['REQUEST_URI'],1));
define('C_PAGE',$c_page ?: 'index');
define('LOGGED',$_SESSION['user']['id'] ?: 0);
if(in_array(C_PAGE,array('page_1','page_2','page_3')) && !LOGGED){ header('Location: login.html'); exit; }
You should really track their entrance with a session variable (or a cookie). Either of these could be blocked...but they are closer to "foolproof". That said, anything can be forged...so use a combination and/or strong unique strings if security is of the utmost importance.
Depending on the serverside softwarestack you use this variable is set by the webserver or the fastcgi wrapper.
URL rewriting and non-transparent proxies in your hardware/software stack can influence the value you see within your script.
e.g. Nginx could rewrite the URL from /test.html to /index.php?action=test, then pass it to your webserver. User would have called /test.html while your application sees /index.php?action=test
Conclusion: REQUEST_URI is the URI passed to the webserver and can be used as a reference for URL-based access controls.
EDIT:
just to avoid confusion, because I've seen the other responses...
Your question as I understood:
You want to check wether your currently requesting and already password-authorized user has enough permissions to access specific URLs. Again, yes you can use the request uri as a reference value
Personally, I find it more reliable to declare one or more groups (classes) of users that should have access to a file, and then include a page that returns a 401 error if the logged in user if not in any of those groups. e.g.
session_start();
...
$access = 'admin';
include 'inc/guard.php';
Sounds like in your case you want 'public' and 'logged-in' which is slightly different, but is a case also covered by my guard script. There, I simply check that the $_SESSION variable is empty (I insert stuff into it upon log-in):
if($access != 'public' && empty($_SESSION)) {
header('HTTP/1.1 401 Unauthorized', true);
include 'inc/login.php';
exit;
}

PHP script only allow traffic from a certain domain?

Is there a simple script that would only allow visitors if they originate from a website of my choice?
Checking the referrer is the most reliable way to accomplish this, but you should be aware that not all user agents (aka browsers) send a complete or correct referrer.
Something like this:
$target_site = 'http://www.google.com';
if (isset($_SERVER['HTTP_REFERER']) && preg_match("/$target_site/",$_SERVER['HTTP_REFERER'])) {
// do something with people from google.com
} else {
// do something else with everyone else
}
Read more about it: http://www.electrictoolbox.com/php-http-referer-variable/
PHP manual on $_SERVER superglobal: http://php.net/manual/en/reserved.variables.server.php
You can use the $_SERVER['http_referer'] but that can be easily faked.
If you get their referrer information you could check it against a list of accepted website origins and redirect them back to the site they came from if you don't want them.
$_SERVER["HTTP_REFERER"]

How to check if a request if coming from the same server or different server?

How can I check whether a request being received is sent from the same server??
Say, I've my domain at www.domain.com. Now I've php processing files which will process forms hosted through this domain. This processes will be executed only if the requests are sent from within the domain ie. www.domain.com and any other requests sent from other domains will be discarded.
Basically : you cannot.
With the HTTP protocol, each request is independent from the others.
A first idea would be to check the Referer HTTP header, but note that :
It can be faked (it's sent by the browser)
It is not always present.
So : not a reliable solution.
A possible, and far better than the Referer idea, solution could be to use a nonce :
When displaying the form, put a hidden input field in it, containing a random value
At the same time, store that random value into the session that correspond to the user.
When the form is submitted, check that the hidden field has the same value as the one that's stored in session.
If those two values are not the same, refuse to use the submitted data.
Note : this idea is often used to help fight against CSRF -- and integrated in the "Form" component of some Frameworks (Zend Framework, for instance).
this will check if there is a referer, then it will compare it with current domain, if different then it is from outside referer
if ((isset($_SERVER['HTTP_REFERER']) && !empty($_SERVER['HTTP_REFERER']))) {
if (strtolower(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST)) != strtolower($_SERVER['HTTP_HOST'])) {
// referer not from the same domain
}
}
I know this is an old thread, but some one else can probably find it relevant.
The answer is: Yes you can. But it depends if your Apache/nginx server is set to populate the $_SERVER variable with the required information. Most the server are, so probably you can use this approach.
What you need to do is to extract the HTTP_REFERER from the $_SERVER variable and compare with your domain.
<?php
function requestedByTheSameDomain() {
$myDomain = $_SERVER['SCRIPT_URI'];
$requestsSource = $_SERVER['HTTP_REFERER'];
return parse_url($myDomain, PHP_URL_HOST) === parse_url($requestsSource, PHP_URL_HOST);
}

Is an X-Requested-With header server check sufficient to protect against a CSRF for an ajax-driven application?

I'm working on a completely ajax-driven application where all requests pass through what basically amounts to a main controller which, at its bare bones, looks something like this:
if(strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
fetch($page);
}
Is this generally sufficient to protect against cross-site request forgeries?
It's rather inconvenient to have a rotating token when the entire page isn't refreshed with each request.
I suppose I could pass and update unique token as a global javascript variable with every request -- but somehow that feels clumsy and seems inherently unsafe anyway.
EDIT - Perhaps a static token, like the user's UUID, would be better than nothing?
EDIT #2 - As The Rook pointed out, this might be a hair-splitting question. I've read speculation both ways and heard distant whispers about older versions of flash being exploitable for this kind of shenanigans. Since I know nothing about that, I'm putting up a bounty for anyone who can explain how this is a CSRF risk. Otherwise, I'm giving it to Artefacto. Thanks.
I'd say it's enough. If cross-domain requests were permitted, you'd be doomed anyway because the attacker could use Javascript to fetch the CSRF token and use it in the forged request.
A static token is not a great idea. The token should be generated at least once per session.
EDIT2 Mike is not right after all, sorry. I hadn't read the page I linked to properly. It says:
A simple cross-site request is one that: [...]
Does not set custom headers with the HTTP Request (such as X-Modified, etc.)
Therefore, if you set X-Requested-With, the request has to be pre-flown, and unless you respond to pre-flight OPTIONS request authorizing the cross-site request, it won't get through.
EDIT Mike is right, as of Firefox 3.5, cross-site XMLHttpRequests are permitted. Consequently, you also have to check if the Origin header, when it exists, matches your site.
if (array_key_exists('HTTP_ORIGIN', $_SERVER)) {
if (preg_match('#^https?://myserver.com$#', $_SERVER['HTTP_ORIGIN'])
doStuff();
}
elseif (array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) &&
(strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'))
doStuff();
I do not believe that this is safe. The same origin policies are designed to prevent the documents from different domains from accessing the content that is returned from a different domain. This is why XSRF problems exist in the first place. In general XSRF doesn't care about the response. It is used to execute a specific type of request, like a delete action.
In the simplest form, this can be done with a properly formatted img tag. Your proposed solution would prevent this simplest form, but doesn't protect someone from using the XMLHttp object to make the request.
You need to use the standard prevention techniques for XSRF. I like to generate a random number in javascript and add it to the cookie and a form variable. This makes sure that the code can also write cookies for that domain. If you want more information please see this entry.
Also, to pre-empt the comments about XMLHttp not working in script. I used the following code with firefox 3.5 to make a request to google from html running in the localhost domain. The content will not be returned, but using firebug, you can see that the request is made.
<script>
var xmlhttp = false;
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
try {
xmlhttp = new XMLHttpRequest();
} catch (e) {
xmlhttp = false;
}
}
if (!xmlhttp && window.createRequest) {
try {
xmlhttp = window.createRequest();
} catch (e) {
xmlhttp = false;
}
}
xmlhttp.open("GET", "http://www.google.com", true);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {
alert("Got Response");
alert(xmlhttp.responseText)
}
}
xmlhttp.send(null)
alert("test Complete");
I do not think this offers any kind of protection. An attacking site could still use xmlhttprequest for its cross-site request bypass your check.
Short answer : no. Any attacker would just use Ajax himself to attack your website.
You should generate a random token with a short but not too much lifetime which you would update during each ajax request.
You'd have to use an array of tokens in javascript as you may have multiple ajax request running at the same time.
What you are doing is secure because xmlhttprequest is usually not vulnerable to cross-site request forgery.
As this is a client side problem, the safest way would be to check the security architecture of each browser :-)
(This is a summary; I am adding this answer because this question is very confusing, let's see what the votes say)
No this can be easily bypassed ,
By making A Cross-domain-Flash request to the server that contains this header and the request with it's credentials ,
see this : https://www.geekboy.ninja/blog/exploiting-json-cross-site-request-forgery-csrf-using-flash/?unapproved=6685&moderation-hash=91554c30888cfb21580f6873e0569da0
The best way to protect against CSRFs is to make Header or Parameter contains a secret key for each request ,

Website security question with PHP? (Probably applies to ASP/Rails/etc.. too)

Say, I have "index.htm" and "routines.php".
"index.htm" will call eventually call "routines.php" using JS (AJAX).
So, my question is, how can "routines.php" verify that the request came from the same local server and not outside? Is there a global variable I can check at PHP level or HTTP level?
Edit 1: Using AJAX
You may forget about the Ajax part as it's not really part of the problem. You should read about Cross Site Request Forgeries (CSRF) and CSRF tokens. Some links:
http://en.wikipedia.org/wiki/Cross-site_request_forgery
http://shiflett.org/articles/cross-site-request-forgeries
To answer your question with another question: how would you invoke getdata() using a browser?
(So: no need to worry.)
If the call is made in JavaScript (i.e., on the client), you really can't do anything to definitely prevent someone from simulating a request from index.htm, even if you check the Referer (sic) header.
If the request is made on the server side, you could use some kind of key.
You can of course generate a key on the client side too, but this security measure can be imitated by anyone to simulate a request from index.htm.
you could use a session key:
index.htm
<?php
$_SESSION['safe_key'] = true;
?>
javascript code here
routines.php
<?php
if (!isset($_SESSION['safe_key'])) {
die('from outside');
}
function getdata() { ... }
?>
Basically what happens is when index.htm is called a session safe key is created. Sessions are serverside only. In routines.php if the safe key does not exist, the code was not called from index.htm. If it does exist, run code.
As others pointed out, it would be pretty difficult given your original specification. However, if you can change the index.htm to be index.php and have it output the same content as index.htm, you can also put in additional tokens for session management (e.g. Cookies - yes I know they are easy to spoof too :) and reject the call to getdata() if the tokens don't match.
Use the HTTP_REFERER server variable:
echo $_SERVER['HTTP_REFERER']
With this you can know if the request comes from the server you want.

Categories