My website has a header, footer, and main content. If the user is not logged in, for the main content a login form may be displayed instead of the actual content.
On that login form I write the $_SERVER['REQUEST_URI'] in the session variable $_SESSION['redirect'].
My login form posthandler, which will log the user in, will send the user after successfully loggin in to this link via header('location: http://myserver.com'.$_SESSION['redirect']);
So if I go to myserver.com/somesite.php?somevar=10 it will show the proper site if you are logged in. Otherwise it will show the login form, however the URL in the address bar in the browser still says myserver.com/somesite.php?somevar=10
Then you enter your credentials and you are redirected to myserver.com/somesite.php?somevar=10, which will then - since you're now logged in - fully display.
I do not use the REQUEST_URI value for a form action or as a link href.
Also, any $_GET variables I use I first check if they match a regular expression (usually the variable will be a sha1 string or a otherwise randomly generated string of numbers and letters only, no special chars), and I always use prepared statements if the get variable is used in a db query.
My question is if there are any security concerns with that? Any ways to exploit this, enter something malicious into the url and then send it to another user for example...? Should I escape something somehow somewhere along the process?
The key-rule is that you always check your input/outputs and see what you can and cannot control (and thus, what can be controlled by a user). On the basis of that, you apply security/sanitization measures.
If I understand your scenario correctly, you display the page, unless a user is not logged in. In that case you show a login box, and after succesful login you send the user back to the page he was trying to visit using the $_SERVER['request_uri'] (stored in a session).
So the user obviously can control this variable, he can browse to your page with some awkward characters. Thus you need to sanitize that. As #Wayne mentions in the comments, users can traverse your directory tree for instance.
Thus, like your $_GET variables, you will need to sanitize the $_SERVER['request_uri'] as well.
There are many ways to do this. The most secure is arguably to check if the request_uri is an existing page, after sanitizing with html_entities() or something like that. Note that special directory traversal methods such as ../, // and ./ might slip through conventional sanization methods such as the aforementioned html_entities()
And to answer literally: Should I escape something somehow somewhere along the process?
- Yes, everything, at the beginning of each process.
------ EDIT # 12-12-2013 -----
(too long an answer for a comment, so I'll expain here how potentially a user can use directory traversal, incl. potential dangerous situations)
from the PHP manual:
$_SERVER['REQUEST_URI']: The URI which was given in order to access this page;
for instance, '/index.html'.
So, say I want to go to yourdomain.com/posts/post.php?../../../ssh your webapp will notice that i'm not logged in, store post.php?../../../ssh in a session and process logging in, after which it sends me back to the url. Because of the ../../../ssh part, I won't be send to post.php, but to a directory on your server named ssh which is below your webroot. For your convenience you've stored your SSH keys there. This seems safe, because it's out of the webroot no webuser should be able to access it.
Yet, I can because of my ingenious addition to your url.
Although this is a little far-fetched, a properly configured http-server, chrooting environment etc. will prevent this, this example does show you that if you allow these characters to be added, they might make users access locations they are not supposed to.
Depending on your implementation, blindly adding $_SERVER['request_uri'] might also mean unwanted stuff gets added to a session, and if you store that session in a database, it will also get added to the database. I'm not really up-to-date how (in)secure PHP is, but I can imagine this allows for breaking out of session variables and potentially injecting stuff into your database.
Although not everything might be possible, and the example might not be really possible, it's better and not that hard to prevent this behaviour.
-- Small after thought: maybe the header('location'... stuff is insecure, but this: Is this PHP redirect insecure? shows its not really. Yet, like a commenter states over there: it's not that difficult to type urlencode()
There are numerous security concerns with putting ANYTHING online. Having an identifiable pattern in post/get requests are a concern, but it depends on a lot of factors, mainly... what can a user get from messing with your site, and how liable are you for malicious intent of site users.
You should do some research in sanitizing your input, using session tokens would be the first thing you could do to ensure traffic to your login script is actually being generated by users on your site. These two common practices are the first steps in protecting agains sql injection, and cross-site scripting attacks.
proper steps to ensure your data is protected, both through good database design, and good code design.
One of my favorite techniques is to configure my application to use custom http headers, and any script that receives data from a Super Global checks to ensure the custom header(s) are correctly supplied as on component of my security. These headers can be seen and sniffed easily by any hacker, but many attacks of a malicious nature are first performed by a script, and it's just one more step that's easy enough to deploy that makes you a harder target for these types of attacks.
A quick google search on fortifying a php based site turned up this article, which has some good tips: http://www.noupe.com/php/php-security-tips.html
You'll never be 100% secure. You can have a look at OWASP Top Ten. These are the main security issues.
I think you should have a token (random number) associated to each user in $_SESSION, instead of $_SERVER['REQUEST_URI']. You could pass the REQUEST_URI by GET and token by POST (in a hidden input), and then validate it. If user login is needed to this URI, ensure that the received user token is equal to the session user token.
You are redirecting to a relative URL, which is good because this means that an attacker cannot use a method such as this to poison the session variable using session fixation with a redirect to their own domain. You should not do any encoding on this value because it is a direct copy of the original URI and it is also the exact URI that you wish to redirect the user to. You should check that the PHP version that you are using is not vulnerable to header injection though. It appears that it was fixed in PHP:
4.4.2 and 5.1.2 This function now prevents more than one header to be sent at once as a protection against header injection attacks.
The other answers regarding path traversal should not be a concern here because there is no extra risk than the user typing the path directly in their address bar. The fact that they are being redirected using the location header does not increase this risk. However, you should ensure your server platform is not vulnerable but keep in mind this is nothing to do with your method of redirection as location simply tells the client to load another address.
Make sure to call exit after setting your header, otherwise an attacker would be able to see your page contents by viewing the raw HTTP response:-
<html>
<?php
/* This will give an error. Note the output
* above, which is before the header() call */
header('Location: http://www.example.com/');
exit;
?>
I cannot comment on every vulnerability your site may have, but in essence the way you propose to do the redirect should be safe. You should however make sure that your site is only accessed over HTTPS which will encrypt the connection and ensure it is safe from MITM attacks. You should also set the secure flag on your session cookie to ensure it cannot be leaked over a non HTTPS connection.
Related
Do I always need to validate user input, even if I'm not actually saving them to a db, file, or using them to include files etc..
Say I just wanted to echo out a request variable or I was using it to send email, is there any need to validate or sanitise it? I've always heard people say that all user input should be checked before doing anything with it, but does it actually pose any threat, if I'm not doing any of the above?
I wouldn't recommend it.
my rule is - NEVER TRUST USER'S INPUT.
lets say that your'e working on a team.
as you wrote, you build a simple form that submit the data to php file and than mail it.
after 3 weeks another team mate wants to use that form.
he's assuming that the data in the php file is clean . he dont know that you dont filtered it.
this is a crack for troubles.
Do I always need to validate user input, even if I'm not actually saving them to a db, file, or using them to include files etc..
Everything you are going to do with user supplied data depends on the context in which you are going to use it. In your single sentence you are already talking about 3 different contexts (db, file, include). Which all will need a different strategy to prevent things for that specific context.
Say I just wanted to echo out a request variable or I was using it to send email, is there any need to validate or sanitise it?
There are more things you can do besides validating and sanitizing. And yes you should handle this case (which is another context btw). Basically you should handle all user data as if it is malicious. Even if you are "just echoing it". There are numerous things I could do when you are "just echoing".
Considering we are in the context of a HTML page I could for example (but not limited to) do:
<script>location.href='http://example.com/my-malicious-page'</script>
Which can be for example an exact copy of you website with a login form.
<script>var cookies = document.cookie; // send cookieinfo to my domain</script>
Which can be used to get all your cookies for the current domain (possibly including your session cookie). (Note that this can and imho should be mitigated by setting the http only flag on the cookies).
<script>document.querySelector('body')[0].appendChild('my maliscious payload containing all kinds of nasty stuff');</script>
Which makes it possible to sideload a virus or something else nasty.
<!--
Fuck up your layout / website. There are several ways to do this.
I've always heard people say that all user input should be checked before doing anything with it
This is mostly wrong. You only need to decide how you are going to handle a piece of data once you know what you are going to do with it. This is because you want to prevent different things in different situations. Some examples are (but not limited to): directory traversal, code injection, sql injection, xss, csrf.
All above attack vectors need different strategies to prevent them.
but does it actually pose any threat, if I'm not doing any of the above
yes totally as explained above. All data that is coming from a 3rd pary (this means user input as well as external services as well as data coming out of the database) should be treated as an infectious disease.
I am developing a site where I am sending parameters like ids by url. I have used urlencode and base64encode to encode the parameters.
My problem is that how can I prevent the users or hackers to play with url paramenters Or give access only if the parameter value is exist in database?
I have at least 2 and at most 5 parameter in url so is this feasible to check every parameter is exist in database on every page?
Thanks
You cannot stop users from playing with your QueryString.
You can only validate them in your script before you do anything with them.
This also applies to POSTed variables as well, they can be hacked almost as easily.
So Validate, validate, validate.
In general if you concern about internal data put them in a session variable. But remember always everything out there is evil. You alway have to check if any input contain SQL injections.
If you use session cookies make sure that hey are http only. So no JavaScript can copy the session cookies and if possible never put them in the url itself. It's quiet easy to copy the url and hijacking a existing session.
This depends a bit on what you are using the parameters for. If they are private and should not be accessible to other users, you should link the data to a specific user and deny access to everyone who isn't authenticated as the correct user.
Also, always remember to sanitize user inputs, which includes URL parameters. Use prepared statements when passing user inputs to a database and encode it before serving it back to other users.
The best I would to is to validate on server side for the user entered paramters. Also I would check if the requests originated from my site (XSS & CSRF). Transmitting data post would be good but provides minimal security IMHO.
Therefore, validate and authenticate the originating location to ensure that it does not come from an outside source
im relatively new to php and was hoping you could help me understand why you should sanitize html when 'echo'ing , specially if data is from cookie..
i.e instead of
<h3>Hello, <?php echo $_COOKIE['user']; ?>!</h3>
you should do
<h3>Hello, <?php echo htmlspecialchars($_COOKIE['user']); ?>!</h3>
this is what i understand.
cookies are stored on client side, hence are a security risk since the data in them can be manipulated/changed by evil users (lol # evil) .
but since the cookie is stored on client side, it means a client can only change his own cookie, which means if he adds some kind of malicious code to $_COOKIE['user'] , when the cookie does run, the malicious code will only be shown to one user (who changed the cookie in the first place) and no one else!? so whats the problem?
You're assuming that the user changed his own cookie. Cookies can be changed by a third-party (Edit: Using additional software. Third-party websites cannot change the cookie directly). This would enable someone to inject malicious code into the user's browser, changing their user experience and potentially posing an additional security risk for your code.
Instead of just looking security aspect, there is a user experience aspect. The code you present is not really useful for security because risk are very poors in this case BUT if username can contains quote or < > signs, the user will not understand why its login is not displayed correctly.
Using such a code garanties that you will display correctly the username (and add extra security), no matter what kind of characters you allow during the registering process.
It's not really a risk in that situation - but this is rarely the actual situation. You should do it anyway.
Consistency - don't put it in now, and when you change it to something else, you might open up a security hole.
User experience - just because a cookie contains HTML doesn't mean it was an XSS injection attempt. What if somebody's name were &? I've been thinking of changing my name to &.
A user could inject a script into your page by changing the cookie. That fact alone should be enough to make you pause for thought.
Imagine you are creating a really by website where many data is stored in the user cookies.
Maybe some of the data in the cookie is used by your website to build an SQL statement, which could result in errors if the user or another website modifies your cookie in a bad way.
If you don't check the cookie data for injections, and even if, something could be written in the cookie that could harm your data consistence, e.g. a String in a varchar column where only hexadecimal numbers should be inserted.
The best way to deal with that problem is to either use Sessions where possible and only store the minimum amount of required data in the cookie as possible.
but since the cookie is stored on client side, it means a client can only change his own cookie, which means if he adds some kind of malicious code to $_COOKIE['user'] , when the cookie does run, the malicious code will only be shown to one user (who changed the cookie in the first place) and no one else!? so whats the problem?
Well, it depends on your implementation and what you use cookie's data for. An evil user could inject SQL through your cookies, change his permisions, impersonate another user, etc.
That's why you should always code thinking about the worst scenario
Can I use a posted value in a PHP redirect header safetly without checking it:
header( "Location: $base".$_POST['return'] ); // $base is set to the base of the site
(If the user would somehow manipulate return to a file that doesn't exist it would simply return a nice 404 message)
Is there any danger in doing this? Is there anything the user can set it to that can compromise the system or in any way do damage?
The header() function is no longer vulnerable to HTTP Response Splitting. The only vulnerability you have to worry about is OWASP a10 - unvalidated redirects and forwards.
Providing a $base of anything other than the null string will prevent an attacker from forwarding a user to a remote domain, which could be useful for Phishing. Redirecting to the same domain could be useful to the attacker if are checking the referer as a form of CSRF prevention, but that is a weak form of protection that you really shouldn't be using anyway. Even with a base, the attacker can change the path by supplied a value like: /../../../admin.php, but this is still relative to the originating domain which in most cases is safe.
One great way to deal with unvalidated redirects is to avoid the problem entirely by not using a REQUEST variable. Instead store it in a $_SESSION['redirect'], and use that for the next request. To be a bit more robust, you could say $_SESSION['redirect_checkout'], or something page specific.
Another option is to use a white list, create a list of all values you would like to accept, and make sure the user supplied value is in your list.
Yes, absolutely! Don't trust any $_GET or $_POST values anytime!
Suppose a third party site posts the form. It may post whatever address.
A simple solution would be not to include the address, but a md5() hash of the address into the form. Once the form gets posted, it's the task of your script to map the hash to an actual address and then emit the Location header.
My other post might be of interest.
You might argue, that your app is bullet-proof. Why shouldn't I pass an URL directly?
In fact, even well-designed applications aren't that bullet-proof. Step back and try to remember your last 'Ah, I forgot something. Let's fix it' event.
Did you check at each point control each and any condition?
User clicks on a web-form submit-button twice. Thus controller runs twice.
User presses F5 an resubmits the last updating controller twice.
User somehow manipulated parameters and a controller gets called with off values passed in.
Therefore, I propose to not pass links or other parameters directly or unprotected / unvalidated.
#Col. Shrapnel: I'm fully aware, that any URL at any point could be submitted to a web-app. That's trivial.
Nevertheless, at a given point of control flow, there are certain acceptable next states of control flow.
To ensure, that only those next control-flow states get reached, I propose to validate.
A more general approach
In fact, my recently updated internal framework never passes any parameters as GET or POST parameters from request to request. All parameters are saved and retrieved from a user session [inside a so called Flow, a part of a bigger control flow].
Using the framework, only one single parameter - the FlowID - gets passed around. If the framework doesn't find the FlowID in the session's flow-store, the framework throws an exception and the dispatcher emits an error message.
I upvoted Stefan's answer.
I also have this to add. I wrote a nice class for building and parsing URLs. You could use it for validation, if you'd like.
See Url.php and UrlTest.php for usage.
https://github.com/homer6/altumo/tree/master/source/php/String
Hope that helps...
I have a php site that lets registered users login (with a valid passord) and sets up a session based on their UserID. However I'm pretty sure thisis being hijacked and I've found "new" files on my server I didn't put there. My site cleans all user input for SQL injections and XSS but this keeps happening. Has anyone got any ideas on how to solve this?
A session cookie hijacking should NOT allow an attacker to create new files on your server. All it could do is given access to an authenticated user's session. It'd be up to your code, and/or the server's configuration that would allow uploading arbitrary files to the site's webroot.
To check for remote compromise hits, get the file creation times of the suspicious files (searches.php, 7.php.jpg) etc..., then comb through your server's logs to see what was happening around that time. If you're logging the session ID along with the rest of the hit, you could trivially see if the session was hijacked, as it would be used from two or more different IPs during the session's lifetime. It'd be especially obviously if the original user logged in from one ISP, then suddenly appeared to jump to a completely different ISP.
And of course, how are your sessions implemented? Cookies? PHP trans_sid (passing the session in hidden form fields and query strings)? trans_sid is especially vulnerable to hijacking, as the mere act of sharing a link to something your site also transmits the session ID, and any external links on your site will have the session ID show up in the HTTP referer.
The solution that PHP experts have come up with is to use unique keys/tokens with each submission of the forms, have a look at the idea here at net-tutes.
Don't forget have a look at the PHP Security Guide.. It covers topics including XSS, Form Spoofing, SQL Injection, session hijacking, session fixation and more.
Remember, always use proper data types in your queries, for example use the int or intval function before numbers and mysql_real_escape_string function for the string values. Example:
$my_num = (int) $_POST['some_number'];
$my_string = mysql_real_escape_string($_POST['some_string']);
You may also use the prepend statements for your queries.
Popular Project To Secure PHP Applications:
XSS Filtering Functions by Christian Stocker (Also used by Kohana framework)
HTML Purifier (Also used by Kohana framework)
OSAP PHP Security Project
I'll have ago and say that your 'cookie' is easy to guess.
Some sites, when the user logs, just create a cookie and the authentication code just checks for the EXISTENCE of a cookie.
Now, if I register and login to your site and then cut your cookie open and notice that you just store my user id then I can manipulate the value to some other user id and voila!
You get the idea.