5

Is there any risk of using $_SERVER['REQUEST_URI'] or $_SERVER['PHP_SELF'] as the action in a form or as the href in a link?

If so, what can be done to alleviate the risk?

user1032531
  • 24,767
  • 68
  • 217
  • 387

6 Answers6

4

You make a form on www.example.com/form.php. A year from now, you forget the URL is just grabbing whatever URL the page is loaded on.

At some point let's say you've added a 'delete everything' global option in your framework as part of a completely different (slightly odd) request.

Now, somebody sends you this link: www.example.com/form.php?delete_everything=true. Since you're just grabbing that URL and setting it as the action, that is now the action on your form. Oops. XSS attacks work essentially in this way.

Always assume that your code is going to be used (even by you, and especially by hackers) in ways that you don't expect when you first write it.

How do you get round it? Hardcode the URL! You can include a function which returns the URL. In effect, this is how frameworks like Symfony or CodeIgniter solve it.

Dan Blows
  • 20,846
  • 10
  • 65
  • 96
  • Thanks Blowski. Problem with hardcoding is not the URL, but the data in the URL. For instance, my URL is mysite.com?id=123 where 123 brings in special data. Can't hardcode every id. – user1032531 Jan 29 '13 at 15:02
  • Also, wouldn't www.example.com/form.php?delete_everything=true have the same effect if the user just put it in his clients browser? How does this deal with XSS? – user1032531 Jan 29 '13 at 15:03
  • In the case of URL parameters, you do something like `action="www.example.com/form.php?id="`. In terms of the `delete_everything=true` - it's a very simplistic example (crazy idea to have such a parameter anyway), but imagine that only the admin can pass that parameter - no problems right? But then one day, someone sends the admin an email with that parameter included, he's in a bit of a hurry, clicks the URL, submits the form... – Dan Blows Jan 29 '13 at 15:10
  • Still having a hard time! How does one client effect what $_SERVER['REQUEST_URI'] comes up when another client makes a request to a server? – user1032531 Jan 29 '13 at 15:17
  • A variety of ways, but the most common is social engineering. Imagine someone in the company has their email hacked. The hacker uses the account to send an email to the head of IT saying "Can you fill out this form please", with a link to the real site - but *the nasty parameters have been added to the end of the URL*. Now when the Head of IT submits the form it passes the parameters to the backend, and the damage is done. The point here is that it adds a huge amount of risk for very little gain - writing a function that constructs the URL honestly won't take long. – Dan Blows Jan 29 '13 at 15:25
  • Know of any good articles which explain this? Also, why not just use `
    `
    – user1032531 Jan 29 '13 at 15:36
  • @user1032531 To be honest, you could do that, and it will guard against 99% of the likely attacks. But 'defence-in-depth' is all about defending yourself in multiple ways (including defending against unknown unknowns). For example, what happens if there is an exploit on your web server which lets someone change the `$_SERVER['PHP_SELF']` value to `www.nastysite.com/form.php`? `htmlentities()` is not going to protect you there. In terms of URLs - http://shiflett.org/blog/2005/feb/more-on-filtering-input-and-escaping-output#comment-7 and the article with it. – Dan Blows Jan 29 '13 at 15:43
3

This is because $_SERVER['PHP_SELF'] and $_SERVER['REQUEST_URI'] can be manipulated in a way whereby, if you don't escape it properly, it can be used in XSS attacks.

Much this is made possible by the fact that a URL like this will work just fine:

/path/to/index.php/" onmouseover="alert('hi')

Let's use this code:

<form action="<?php echo $_SERVER['PHP_SELF']; ?>">
...
</form>

It calls /path/to/index.php, i.e. the SCRIPT_NAME, but when you just echo $_SERVER['PHP_SELF'] it will break your intended HTML.

<form action="/path/to/index.php/" onmouseover="alert('hi')">
...
</form>

Solutions

In many cases, using <form action=""> is enough to make the form post to the script itself. Otherwise, if you know the script is called "bla.php", then set action="bla.php".

Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • How can it be used in XSS attacts? I can see how someone might change it for their client PC, but not for others. How do you recommend escaping it? esc_url()? – user1032531 Jan 29 '13 at 14:57
  • @user1032531 Think about adding these links inside forums that many people visit? – Ja͢ck Jan 29 '13 at 14:59
  • Hello again Jack. I read your post 20 times and still don't get it. Any other clues would be appreciated. – user1032531 Jan 29 '13 at 15:18
  • Okay, maybe I get it. Bad guy adds a link or something to a forum. Good guy clicks the link and the URL included some JS which gets executed. Still fuzzy about how it relates to forms. – user1032531 Jan 29 '13 at 15:32
  • @user1032531 Doesn't relate just to forms, it can be applied to anything that has non-scrutinized values of those variables. – Ja͢ck Jan 29 '13 at 15:33
3

$_SERVER is vulnerable to XSS attacks, and should be cleansed using htmlspecialchars() prior to use.

An example injection:

   <form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>"></form>

Now call the form with the following with the injection:

http://www.example.com/form.php/%22%3E%3Cscript%3Ealert(‘xss attack’)%3C/script%3E%3Cbr%20class=%22irrelevant

Always remember to clean input data ... ALWAYS!

Joe Brown
  • 637
  • 3
  • 5
  • 1
    Thanks Joe, But wouldn't this just effect the individual with the client that hit that URL? How would it effect others? – user1032531 Jan 29 '13 at 15:04
  • So it's myabe a dumb question but why in all my tests I had a 403 error and the page had even not been loaded ? – user3292788 Dec 11 '15 at 22:33
2

I realize this is a pretty old post, but it's an issue that I struggled with as well some time ago. What I do now days is this:

$php_self = filter_input(INPUT_SERVER, 'PHP_SELF', 522);
define('PHP_SELF', $php_self);

With this, you can safely use the constant PHP_SELF as the form action. What this bit of code does is run the super global $_SERVER['PHP_SELF'] through a filter while assigning the result as the variable $php_self. The ID number 522 refers to FILTER_SANITIZE_FULL_SPECIAL_CHARS which removes the ability for someone to inject javascript and such.

You can see which filters are available with this bit of code here:

<table>
<tr><td>Filter Name</td><td>Filter ID</td></tr>
<?php
foreach(filter_list() as $id =>$filter)
{
  echo '<tr><td>'.$filter.'</td><td>'.filter_id($filter).'</td></tr>'."n";
}
?>
</table>

The same principle can be applied to most, if not all of the super global $_SERVER variables.

Below are some of my favorites to play with:

# FILTER_SANITIZE_STRING or _STRIPPED
$server_http_xrw = filter_input(INPUT_SERVER, 'HTTP_X_REQUESTED_WITH', 513);
# FULL_SPECIAL_CHARS
$server_request_method = filter_input(INPUT_SERVER, 'REQUEST_METHOD', 522);
$http_encoding = filter_input(INPUT_SERVER, 'HTTP_ACCEPT_ENCODING', 522);

So, anyway, by utilizing PHP's (now) inbuilt filters, we can use $_SERVER variables without too much worry.

I hope this helps someone who wanders onto this thread looking for answers.

Paul S
  • 33
  • 8
0

Don’t forget to convert every occurrence of "$_SERVER['PHP_SELF']" into "htmlentities($_SERVER['PHP_SELF'])" throughout your script.

How to Avoid the PHP_SELF exploits http://www.html-form-guide.com/php-form/php-form-action-self.html

smallbee
  • 233
  • 1
  • 4
  • 16
-1

No, as anyone can change the href of a link anyway (using a tool like Firebug). Of course, make sure you do not put any sensitive data in that link.

Always be sure to correctly validate and parse user data that you receive.

Bart Friederichs
  • 33,050
  • 15
  • 95
  • 195