How to prevent users to change url parameter in PHP? - php

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

Related

Is it unsafe to use query strings in the url?

Our PM has ordered us to implement security for a site we've been working on.
To display product details, I make use of query strings.
My URL looks like www.domain.com?index.php&product id=1&product-type-id=4
My colleague argued that this is unsafe, and that we should hide that information from the URL. They suggested that we use a session instead.
In my opinion, nothing is unsafe about the use of query strings as long as I do server side validation, pass the active user id to my query to make sure people can only access their products.
What vulnerabilities could a URL like this cause:
www.domain.com?index.php&product id=1&product-type-id=4
When deciding between $_POST and $_GET ask yourself this: Is there any reason the user shouldn't be able to see this? Using $_GET also allows the user to bookmark or share the url, so for a product page like this I would 100% recommend continue to use it in this way. $_GET is not inherently unsafe as long as you are sanitizing anything you receive from it. They both exist for a reason and have their uses.
The security problem isn't tied to the query string. The difference between get and post are just at the protocol level and either can be forged.
The security issue comes up when you don't properly validate variables and escape them as needed.
Never trust user input. Always validate it.

any security concerns with $_SERVER['REQUEST_URI'] and header('location: ...');

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.

Secure way to stop users from forging forms

How can I prevent users from forging forms on the PHP or jquery side, I am using Jquery's ajax functionality to submit the forms, and this means that tech-wise people can change some variables such as the value of something (that shouldn't be changed / is a user id or something like that) through the use of firebug or web inspector and likewise.
So how can I prevent users from changing these variables or making sure they are unchangeable through a secure and good way?
Thanks
As the others have already stated, you can't prevent the user from tampering.
You are receiving data from me, and I can send you anything I want, I can even do an HTTP request by hand, without even using a browser, and you can't do anything about it.
If you don't want a user to be able to alter an information, don't provide it to him.
You can store it in PHP's session, which is stored server side (do not use cookies, they too are sent to the user) or save it in a database, both of them are not accessible to the end user.
If you still want to pass the data to the user, compute some sort of hash (a secure hash, using a secure hashing algorithm and a secure message digest as Gumbo noted, this rules out algorithms like CRC32 or MD5 and MACs like your name or birthday) of the data and store it server side, then when the user submits back the data, check if the hashes match.
But do know that this solution is not 100% secure. Hashing functions have collisions, and bad implementation exists.
I would recommend to stick to the golden rule: if it's not there, it cant break / be tampered / be stolen / etc.
You cannot prevent users from doing so.
Store these variables in a Session.
You can never trust the client. Validate the form on the server to ensure the data is sane. This means checking that a given user ID has permissions to post their form, etc.
I'm going to go with... you can't. You never trust the user's data; client side verification is always only the first line of defense.

Is there any need to sanitize a $_POST value before using it in a PHP header (for redirecting)

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...

URIs vs Hidden Forms

I'm working in CodeIgniter, and I want to send requests to my controller/model that have several parameters involved. Is there a difference between passing those parameters via a hidden form (i.e. using $_POST) as opposed to passing them through URIs (e.g. 'travel/$month/$day/')? Are there any security concerns with this approach?
Example Security Concern:
URIs
http://www.example.com/travel/$month/$day/
Hidden Form:
form_hidden('month',$month);
form_hidden('day',$day);
Rule of thumb — GET requests should never change the state of things. So, if you actually change something or request — use hidden forms with nonce values (to prevent accidental resubmissions and CSRF attacks). Otherwise, there's no difference.
Auth should be decoupled from URIs and POST data — there are cookies, HTTP auth and SSL client certificates. Everyone knows that there is a 11th June in 2009, and a lot of people may know that you use /$year/$month/$day/ scheme in URIs (or "year","month" and "day" POST fields) on your site. But only those who are entitled to access should be able to see what's on this page (or POST data to this URI). And, yes, both GET and POST data can be easily tampered, so you obviously have to check for validity.
If you choose URIs, if the user bookmarks the URLs,
it brings security problem.
and if any user clicks any links ,
then the target web server can now know
HTTP_REFFER, and the server administrator
can know the link.
it means he can see the URI.
so my personal opinion is that
you better choose hidden form.
If you monitor your incoming-data (users are evil goblins, remember), and clean when necessary it's not going to make much of a difference. The difference only comes down to usability: if you want users to be able to access the same results without always having to go through a form, then use the URL method.
In all honesty, your example doesn't given enough data to determine which method (POST/GET) would be appropriate for you.
Suggested Reading: GET versus POST in terms of security?
I ran into this same issue recently. When anything additional is exposed in the URL, you run the risk of exposing website methods/data. After quite a bit of research, I elected to only show variables when absolutely needed or if the page was just a simple view. The more data you expose in your URL, the more checks you'll likely need to put in place (what if the user modifies the URL in x way).
Another consideration is the ability to bookmark or link to URLs (presumably views). One idea is to hide variables in the URL via an encrypted string. You could then store the encrypted string in your database and serialize as needed. I did this for a search engine and it gave me the best of both worlds. This was with CodeIgniter.

Categories