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?
Source: Tips4all, CCNA FINAL EXAM
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.
ReplyDeleteProviding 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!
ReplyDeleteSuppose 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.
XSS and SQL injection rules go here.
ReplyDeleteYour URL contains a base, but that doesn't mean an attacker can craft a form that redirects to some page where you display or process data from the URL, or to a page where you use the URL as database input.
I upvoted Stefan's answer.
ReplyDeleteI 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...