I need to construct a form who's action takes you back to the exact same page - GET parameters included. I'm thinking I can say something to the effect of:
echo '<form action="'.$_SERVER['SCRIPT_NAME'].'?'.$_SERVER['QUERY_STRING'].
'" method="post">'
This seems to work, and testing passing a couple XSS attacks seems to be successful, as the output of QUERY_STRING seems to be URL encoded. However the PHP documentation does not mention this, so I'm not confident I can trust this behavior.
Is it safe to use QUERY_STRING the way I am above? If not, what can I do instead? References to documentation would be appreciated.
Update switched to SCRIPT_NAME, just mixed up which one was ok and which was bad in my head, thanks for catching me. action=""
does resolve my specific issue nicely, but I'm still curious if QUERY_STRING is pre-processed so it is safe to use or not, since there are other times you might want to re-use the query string, assuming it's safe to do so.
You should never trust $_SERVER['QUERY_STRING'] as it can be used for XSS attacks.
In your case, one could exploit the vulnerability with:
http://your.server.com/your_script.php?"><script>alert(111);</script>
Note that the code above works on IE; FireFox and Chrome efficiently encode the query string before sending it to the web server.
I would always wrap it with htmlentities (mind the double_encode parameter) as with every user input.
Good luck!
If it's exploitable by XSS, first you need to know which attack. In the code posted here there is just one simple attack using the PHP_SELF.
But, to avoid any problem you could just leave the form action in blank. This will send the form to the same page including the query string.
First of all, you can not trust $_SERVER['PHP_SELF'] (1) - use $_SERVER['SCRIPT_NAME'] instead.
As for $_SERVER['QUERY_STRING'], you should treat it as any other user input. Filter it before using it in your output. I would not recommend some sort of a general filter in this case. It would be better to reassemble the query string from specific pieces you expect to be there.
I can't think of any attacks that would work off-hand, but PHP_SELF
itself is vulnerable and you're using QUERY_STRING
without any filtering whatsoever, which seems odd.
Why not just leave the action
parameter blank and let the browser decide? You can use Javascript to properly enforce this behaviour on the client-side if you want to be doubly sure.
This is another one of those instances where using PHPs filter_input
is the way to go. My IDE NetBeans (hate it or love it) always complains whenever I open code that accesses $_POST
, $_GET
, $_SERVER
and $_COOKIE
directly without going through filter_input
.
This is because of the reasons stated above - you're saying that you trust external data, when, if it can entered or manipulated by users, you cannot.
filter_input(INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT);
filter_input(INPUT_SERVER, 'QUERY_STRING', FILTER_SANITIZE_STRING);
Read more here