How to protect against cross domain http requests? (server side) - php

I've read some questions on SO about denying cross domain requests but all just state to rely on the client side protection ( same origin policy ) . Are there any layers of protection that can be done server side ? Should i rely on header- origin , header - referer ? Some say header referer get's modified by some anti-spyware programs . Some say ff doesint include origin header option (but it does) , some say chrome doesnt and so on :) .
I know headers can be modified (referer can be modified even with setrequestheader method) , but , if you ever done any protection server side for this matter please share any ideeas .
P.S. : A possibility would be to tokenise each request (all type of requests , requests that only get data , requests that change data on server etc ) but that would be a pain in the ass ...
P.P.S. : omg don't spam about synchroniser token pattern ... as i said in the firs P.S. yea that would be a solution , any other ideeas?

Mayor question is against which kind of attacks you want protect?
If you want protect against CSRF, then you need process form with random security token.
Like
<input type="hidden" name="token" value="random value generated on server side for each request" />
After form will submitted you need compare token from request and token stored in session on server side.
If you want deny load some kind of resources from other domains (like loading images or scripts on evil.com from you server), then you can add to each resource similar token.
Like
<img src="/images/mysuperimg.png?token=<token>" />
etc.

I suppose you have heard of CSRF?
here's an overview CSRF works and how it's prevented:
anyone can request a page from your site, the same way anyone can also POST on your site. let's say you have a registration form. one can copy your form, and put in any HTML page, remove the JS validations, and spam you infinitely. sounds like a threat right?
however, you can prevent this by using a session id. this is a unique string (usually MD5 or SHA-1), that is stored on a session variable in PHP before rendering the page. this session id is also rendered in a hidden input form on your form. now when the form is submitted, PHP checks if that session id sent with the form is a match with a the session id stored in the session variable. if it's valid, you proceed, and the one stored in the server is nullified so that it wont be reused.
also, if a certain time has elapsed, that session id should expire. so lets say if a user has lingered on a form for more than your 15 min expiry. using that form will be invalid. you'd have to refresh the page to get a new session id
now you might ask how to use this on page requests rather than forms?
i know of 2 ways to send over session ids to the server, and that is either by cookie or via appending your sessionid in the url.
for cookie, it works the same way. if your page is generated by your server, the page creates the session id on your server and sends a copy as a cookie. the next page request, you read the cookie of the request, get it's session id, compare with the one on the server, and if equal, request is valid, you proceed. otherwise, it's invalid.
for those who have disabled cookies, you can append the sessionid in the url of every link you have on the page. notice that on some sites, they have a url parameter of sid, or sessid and so on? that's how they pass it. every link in your page will be appended this id. and upon clicking the link, all the server does is get that session id from the url, and compare it with the server.
quite long answer :D

Related

PHP security, only allow $_REQUEST from specific URL

I have a simple PHP script which accepts a $_REQUEST from a javascript Ajax call and adds a post to the DB
But I need to ensure that only javascript requests from my domain is allowed, to prevent someone from submitting thousands of junk posts to my DB.
My question is, how do I ensure that my script only accepts $_REQUEST from my domain?
Thanks
The short answer is: You can't.
It sounds like you need to introduce the usual defences against CSRF (i.e. to generate a random security token and store it in a cookie (or session) as well as in your HTML document. You then submit the token as part of your request and compare it to the one in the cookie. If they match, then it is an intentional post from the user and not their browser being tricked into making the request by another site).
This won't stop people submitting "thousands of junk posts" though. You also need to authenticate users and check they are authorised to make a submission before allowing it to go through.
You can consider also including rate limiting checks and spam filtering.
You use a 'secret' key, a response and a remote IP to validate.
Google has provided this for you
https://developers.google.com/recaptcha/docs/verify
https://developers.google.com/recaptcha/docs/display
https://developers.google.com/recaptcha/docs/invisible#auto_render
works like a charm.
Once you implement you get an ADMIN panel here:
https://www.google.com/recaptcha/admin
At which time you set the Domains to be ONLY your URL's.
Which will do what you want and make sure the form validates from your domain using both keys from server side and client side integration. If someone try's to generate the "key" using their domain recaptcha will detect it as spam.
(see the verify link above)

Preventing CSRF with tokens in a AJAX based application

I'm using tokens to prevent CSRF attacks in my application. But this application is single page and heavily AJAX based, so I need to find a way to provide a valid token for N actions in a single page:
e.g. A document fragment loads with 3 possible actions, each action needs a token to work properly but server side has just one valid token at time...
Since each token is just a encrypted nonce (the value isn't based in a specific form), I came with the idea of automatize the token assignation for each action with something like this:
The App intercepts an AJAX call, and check if it's a sensitive action (i.e. delete a user)
A token is requested to the server before the action proceed
The token is generated and then added to the action request
The action in executed since the request included a valid token
Do the same for any subsequent actions executed via AJAX
I believe that method isn't effective enough because the attacker can use a script that does exactly the same my App does (retrieve token and append to the request).
How can I improve my method to be effective against CSRF attacks?
Additional info: My backend environment is PHP/Phalcon and the tokens are generated using Phalcon.
A simpler method than using tokens for an AJAX only might be to check headers that can only be present in an AJAX request from your own domain.
Two options are:
Checking the Origin Header
Checking the X-Requested-With header
The Origin header can also be used for normal HTML form submissions, and you would verify that this contains the URL of your own site before the form submission does its processing.
If you decide to check the X-Requested-With header, you will need to make sure it is added to each AJAX request client side (JQuery will do this by default). As this header cannot be sent cross domain (without your server's consent to the browser first), checking that this is present and set to your own value (e.g. "XMLHttpRequest") will verify that the request is not a CSRF attack.
I had to deal with something similar awhile ago. Requesting nonces with ajax is a super bad idea – IMHO, it invalidates the whole point of having them if the attacker can simply generate it without reloading the page. I ended up implementing the following:
Nonce module (the brain of the operation) that handles creation, destruction, validation and hierarchy of nonces (e.g., child nonces for one page with multiple inputs).
Whenever a form / certain input is rendered, nonce is generated and stored in a session with expire timestamp.
When the user is done with an action / form / page, the nonce with it's hierarchy is destroyed. Request may return a new nonce if the action is repetitive.
Upon generating a new nonce old ones are checked and expired ones are removed.
The major trouble with it is deciding when the nonce expires and cleaning them up, because they grow like bacteria on steroids. You don't want a user to submit a form that was open for an hour and get stuck because the nonce is expired / deleted. In those situations you can return 'time out, please try again' message with the regenerated nonce, so upon the following request everything would pass.
As already suggested, nothing is 100% bullet proof and in most cases is an overkill. I think this approach is a good balance between being paranoid and not wasting days of time on it. Did it help me a lot? It did more with being paranoid about it compared to improving the security dramatically.
Logically thinking, the best thing you could do in those situations is to analyse the behaviour behind the requests and time them out if they get suspicious. For example, 20 requests per minute from one ip, track mouse / keyboard, make sure they are active between the requests. In other words ensure that requests are not automated, instead of ensuring they come with valid nonces.

Is there a way to load another website login page, wait for it to be submitted, then read the location querystring?

I need to load the login page of another website (different domain), wait for the user to fill it in and submit it, then read the URL/Location/Querystring for a token parameter to my site and close the login page.
Don't want the username or password, only interested in the returned token (http://www.othersite.com/?token=blahblahblah), which will then be passed as a querystring to a page on my domain (http://www.mydomani.com/loadtoken.php?token=blahblahblah).
Currently, a user has to do this in a separate page, copy and paste the token into my page, since these tokens only have a short life, it's somewhat irritating practice, and if it can be done behind the scenes by the site instead it would make it simpler for everyone.
Reading around on iframes, divs and ajax suggest this is not possible due to security policies, cross site scripting, etc.
Is it possible? What should I be looking for or concentrating on, or can you give some examples.
Thanks for your help.
Edit: Should have said, I understand that it's possible to take the username and password and do a POST behind the scenes, but I really want to avoid making the users give my site their login details to another site, for obvious reasons.
The simplest method is to present the login form on your own site. The form posts to your server, and the handling script then does a CURL request to do its own request to the other server. This sends the login response (which presumably contains that token) to your server.
However, if this token takes the form of a cookie, and the cookie's required for the user to do further operations on their own on this other site, then this won't work. There is absolutely no way for your server to accept the cookie on the user's behalf, then send the cookie to the user in such a way that it appears to have been set by the other server.
The easiest way would be for you to post that form's information to the remote host and have that site send the token to a callback script on your own host.
I need to load the login page of another website (different domain), wait for the user to fill it in and submit it, then read the URL/Location/Querystring for a token parameter to my site and close the login page.
You can't do that
What should I be looking for
OAuth / XAuth (which will require the co-operation of the site you are trying to log in to)

Can we ever determine if the request was sent from another domain?

I've read these webpages:
PHP Form Security With Referer and http://www.mustap.com/phpzone_post_62_how-to-bypass-the-referer-se
So basically my question is how do we determine for certain that the request was sent from our own domain? Or is there no way at all?
(Question targeted at any server side language including but not limited to PHP/JSP/ASP.Net etc)
My Problem: I have a page at http://me.com/login and on form submit, it will post to itself the login particulars. So far so good. until someone else can simply do this
<form action="http://me.com/login">
<input name="password" value="p">
<input name="username" value="u">
</form>
and they can send a request to login to my application through their domain. I do not want this. I need a way to make sure that if my page receives a post, its from my domain. Else i will reject it.
Besides, I'm abit shock when i read this: There are plugins for Firefox that allow the user to specify whatever value they want to be supplied as the REFERER. source: http://www.phpbuilder.com/board/showthread.php?t=10324100
So we don't even need a hacker to break it now. Just about anyone could do it.
I need a solution to make sure that i reject ALL requests not from my domain.
So basically my question is how do we determine for certain that the request was sent from our own domain? Or is there no way at all?
You are asking the impossible. There is no way to know for certain that a submit button on a page on your domain generated the request.
You say it's not about CSRF, so I don't know why you are concerned. But the solutions are the same.
Check the HTTP_REFERER header anyway. If it isn't your domain, then reject the request. You'll probably need to accept missing headers though since some people disable it. This doesn't prevent people who mess with their browser settings from spoofing the value though. But it does prevent people who are tricked into submitting the form from another site (assuming they haven't disabled HTTP_REFERER).
Use a "nonce" or temporary token that is only valid for one request. Hence, the person who submits the request must visit your website at least once per request. This is basically the same thing as ensuring that the request originated from your website. You can also tie a nonce to an IP address or session to prevent people from querying your site and relying the token along to another computer.
There's no way to make sure where's the origin of the request. This is the nature of HTTP state-less protocol.
In common Referrer HTTP header is used as the source of request, but it can be manipulated easily.
Use a hidden input with an encrypted key that is held on your server, and make it change frequently (I give 30 seconds before it changes!). This wont stop it but will minimise the risk, also, log the failed attempts per IP and block that IP/user after the 4th failed attempt until re-verified via email.
If the username that had the failed attempts doesn't match the DB after the 4th time, block the IP and give an email to contact.

Jquery $.post and PHP - Prevent the ability to use script outside of main website

I have a PHP script setup using Jquery $.post which would return a response or do an action within the targeted .php file within $.post.
Eg. My page has a form where you type in your Name. Once you hit the submit form button, $.post is called and sends the entered Name field value into "mywebsite.xyz/folder/ajaxscript.php"
If a user was to visit "mywebsite.xyz/folder/ajaxscript.php" directly and somehow POST the data to the script, the script would return a response / do an action, based on the submitted POST data.
The problem is, I don't want others to be able to periodically "call" an action or request a response from my website without using the website directly. Theoretically, right now you could determine what Name values my website allows without even visiting it, or you could call an action without going through the website, by simply visiting "mywebsite.xyz/folder/ajaxscript.php"
So, what measures can I take to prevent this from happening? So far my idea is to ensure that it is a $_POST and not a $_GET - so they cannot manually enter it into the browser, but they could still post data to the script...
Another measure is to apply a session key that expires, and is only valid for X amount of visits until they revisit the website. ~ Or, just have a daily "code" that changes and they'd need to grab this code from the website each day to keep their direct access to the script working (eg. I pass the daily "code" into each post request. I then check that code matches in the ajax php script.)
However, even with these meaures, they will STILL have access to the scripts so long as they know how to POST the data, and also get the new code each day. Also, having a daily code requirement will cause issues when visiting the site at midnight (12:00am) as the code will change and the script will break for someone who is on the website trying to call the script, with the invalid code being passed still.
I have attempted using .htaccess however using:
order allow,deny
deny from all
Prevents legitimate access, and I'd have to add an exception so the website's IP is allowed to access it.. which is a hassle to update I think. Although, if it's the only legitimate solution I guess I'll have to.
If I need to be more clear please let me know.
The problem you describe is similar to Cross-Site Request Forgery (CSRF or XSRF). To protect you against this you could put a cookie into the browser and have the cookie value sent in the post form too (by hidden field or just add it to $.post). On server side check both those fields, if they match the request probably came from your site.
However the problem you describe will be quite hard to protect against. Since you could easily make a script (or use Crul) to forge all kinds of requests and send to your server. I don't know how to "only allow a browser and nothing else".
Use the Session variable as you say plus...
As MyGGAN said use a value set in a cookie (CVAL1) before rendering the submit forms. If this cookie is available (JS Code Check will verify) then submit.
On the server side:
If this cookie value exists and the session variable exist then the HTTP Request came from your website.
Note: If the script (form) is to presented under another domain DO NOT allow the cookie value (CVAL1) to be set.
Do not allow HTTP Requests on the Server Side Scripts if extra Http Headers Are not available (like x-requested-with: jquery). JQuery sends a request with an X-* header to the server.
Read more on Croos-Site Request Forgery as MyGGAN suggests.
I am not really sure REMOTE_ADDR would work. Isnt that supposed to be the end users IP addr?
Firstly, you could make use of
$_SERVER['HTTP_REFERER'], though not always trust-able.
The only bet that a valid post came from your page would be use a captcha.
try to use HTTP_SEC
// SECURITER
if ($_SERVER[HTTP_SEC_FETCH_SITE] != "same-origin")
die();
if ($_SERVER[HTTP_SEC_FETCH_MODE] != "cors")
die();
if ($_SERVER[HTTP_SEC_FETCH_DEST] != "empty")
die();

Categories