2

I write

http://www.mysite.com/form.php/%22%3E%3Cscript%3Ealert('hacked')%3C/script%3E

on URL. Now I press enter and the URL is:

http://www.mysite.com/form.php/"><script>alert('hacked')</script>

Now I post the form. When using $_SERVER['PHP_SELF'], htmlspecialchars works, with REQUEST_URI not. Why?

When and why should I use action="" or action=<?=$_SERVER['PHP_SELF']?> or action=<?=$_SERVER['REQUEST_URI']?>?

Here the result of the posts:

$_SERVER['REQUEST_URI']:
  /form.php/%22%3E%3Cscript%3Ealert('hacked')%3C/script%3E

htmlspecialchars($_SERVER['REQUEST_URI']):
  /form.php/%22%3E%3Cscript%3Ealert(&#039;hacked&#039;)%3C/script%3E

$_SERVER['PHP_SELF']:
  /form.php/"><script>alert('hacked')</script>

htmlspecialchars($_SERVER['REQUEST_URI']):
  /form.php/&quot;&gt;&lt;script&gt;alert('hacked')&lt;/script&gt;

I think, the second should also be as the last...?

Perocat
  • 1,481
  • 7
  • 25
  • 48
  • To answer the action part. I prefer to use `$_SERVER['SCRIPT_NAME']` over `PHP_SELF`/`REQUEST_URI` or any others because it only contains `/folder/form.php` and nothing after `.php` so you won't get any XSS content like you are trying with script tags. If you need parameters after `.php` I'd recommend creating a script that prints safe values. `action=""` when used is sent to the current page which might be safer but `SCRIPT_NAME` works fine. – Class Jan 19 '14 at 06:18

1 Answers1

3

It sounds like you're confusing htmlspecialchars with urlencode.

htmlspecialchars replaces characters with special meaning in HTML with &-escaped entities. So, for example, ' becomes &#039;. It doesn't turn %22 into &quot;, however, because %22 has no special meaning in HTML, so it's safe to display it without modification.

urlencode replaces characters with special meaning in URLs with hexadecimal character codes using %. So, for example, " becomes %22.

If you want a form to be handled by the same URL that is used to display it, always use action="" rather than action=<?=$_SERVER['PHP_SELF']?> or action=<?=$_SERVER['REQUEST_URI']?>. As you've already figured out, there are serious risks of cross-site scripting (XSS) if you use either of the $_SERVER variables, because they contain user input and therefore cannot be trusted. So, unless you have a good reason that you need to tweak the URL somehow, just use action="".

elixenide
  • 44,308
  • 16
  • 74
  • 100
  • Thank you for your detailed reply. I'd like to know what could be a good reason to tweak the URL with $_SERVER[...] insted using action=""? Thank you – Perocat Jan 19 '14 at 16:40
  • Sometimes, you may have no choice. The tough cases are those in which you have to redirect somebody, such as after a user logs in and you need to send them to the page originally requested. That can be hard. – elixenide Jan 19 '14 at 19:26
  • Thank you... on my website I have this situation I solved this way: 1) user request `www.mysite.com/admin/page.php` 2) user not logged is redirected to `/admin/login.php` but before that I set a $_SESSION with the page originally requested. 3) user log in and if $_SESSION is setted user will be send to the page originally requested else to `/admin/index.php`. Is the way you write be better/more proper? Thank you – Perocat Jan 20 '14 at 01:38
  • Either is fine. Using `$_SESSION` instead of `action="..."` has the advantage that it doesn't echo the URL directly into the HTML, so at least XSS doesn't work that way. You still need to watch out for CSRF and some other attacks, though. Check out the [OWASP PHP Security Cheat Sheet](https://www.owasp.org/index.php/PHP_Security_Cheat_Sheet#CSRF_Cheat_Sheet). – elixenide Jan 20 '14 at 03:48