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.
Related
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)
I have done some researches on how to prevent fake cross-origin requests and have found a lot of useful information. However, none of them seems to directly resolve my concerns, and because my application has to deal with this specific situation, I would like to understand it completely.
I have a simple php mailing website: mailsite.com
This site will allow other pre-defined addresses, for instance, user.com, to send POST data to it, and process the information that contains to and mesaage; then send them an E-mail from mailsite.com to to with the message message.
Currently, I am using $_SERVER[ "HTTP_ORIGIN" ] and $_SERVER[ "HTTP_REFERER" ] to check where the requests come from; and process them if it is from the pre-defined domains. However, I've read some articles that say:
HTTP_ORIGIN is not even indexed in PHP documentation, because it is pretty much per-browser sort of thing, so browsers that refuse to send those information will not work. HTTP_REFERER is easy to fake.
Tokens are good in preventing CSRF.
However, the request I allow is coming from a third pre-defined website, how does Tokens work in this situation?
My question is: If I allow specific domains to POST data to my site, how can I make sure (or the most secured way) that those requests are coming from the sites I expected? Is HTTP_ORIGIN not even safe enough to use? I dare to think about allowing third website to POST data to my site because I've seen Facebook allowing people to access their database. There must be some possible solutions for checking where the requests come from.
It sounds like you have multiple solutions possible:
Use a token permission system. Give user.com a private token to add as a hidden value to the input form. Upon submitting this form, the browser will give your server the token, and the user shouldn't have to know about the token. You check the token against your own database. If you find the token, allow the mail to be sent.
Use CORS (Cross-Origin Resource Sharing). When an Ajax request is sent to your server from user.com, there should be multiple Access-Control headers. You check if these exist and what their values are using $_SERVER['HTTP_ACCESS_CONTROL_header'] where header is one of the Access-Control header names. If these values match up to your expectations, respond with multiple header('Access-Control-header: value'); calls so that the browser knows you accepted the preflight request, otherwise don't add any extra headers. The browser will send another request after the preflight, and this is when you'll actually send the mail.
If this is being sent from user.com's server rather than a visitor of user.com, most likely the server's IP address won't change (though it may or may not use a defined range of IPs, so be mindful of that.), so you could verify that the $_SERVER['REMOTE_ADDR'] matches a value in your database. You can keep a table of approved IP addresses in your database for this purpose. If you find the IP address in your table, allow the mail to be sent.
Hope this helps.
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
I have a webpage in which the user is awarded X points on clicking a button. The button sends a AJAX request(JQuery) to a PHP file which then awards the points. It uses POST.
As its client side, the php file, parameters are visible to the user.
Can the user automate this process by making a form with the same fields and sending the request ?
How can I avoid this type of CSRF ? Even session authentication is not useful.
You should handle that on the server-side, If you really want to prevent multi-vote or prevent the same people from voting several time on the same subject.
This is why real votes always use authenticated users and never anonymous votes.
By checking the request is really a XmlHttpRequest (with #Shaun Hare response code or with the linked stackoverflow question in your questions comments) you will eventually block some of the CSRF but you won't prevent a repost from the user, using tools like LiveHttpHeaders 'replay' and such. Everything coming from the client side can be forged, everything.
edit* if it's not a voting system as you commented, the problem is teh same, you nedd 'something' to know if the user is doing this action for the first time, or if he can still do this action. There's a lot of different things available.
You can set a token on your page, use that token in the ajax requests, and invalidate this token for later usage server side. This is one way. the problem is where to store these tokens server-side (sessions, caches, etc)
Another way is to check on the server side the situation is still a valid situation (for example a request asking to update 'something' should maybe handle a hash/marker/timestamp that you can verify with current server side state.
This is a very generic question, solutions depends on the reality of the 'performed action'.
Check it is an ajax call in php by checking
$_SERVER['HTTP_X_REQUESTED_WITH']
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();