XSS protection in PHP

Viewing 16 reply threads
  • Author
    • #7525

      Hey everyone,
      Is there any way to implement input sanitation/validation/escaping/whatever in an existing PHP application without having to go through every point of input and include a filter function? I need to implement some sort of filtering, but it’s going to be a nightmare to go through thousands of lines of code…

    • #47008

      The programmer has to implement any filtering with every input or output.  There is no Anti-XSS flag that you can turn on to prevent all XSS.  If it was easy, XSS would be a non-issue already.

      It’s always harder to add security in after the fact than to build it in from the start.

    • #47009

      In this case, it might be more beneficial to start with a WAF. However, as noted above, that’s not going to instantly fix all your problems, and you’ll probably still need to do a lot of manual adjustments.

    • #47010

      Thanks for the input. I just wanted to check in case there was some good news for my developers, but I guess not! It always sucks to inherit someone else’s insecure system…

    • #47011

      Also, you could start with: https://www.fortify.com/ssa-elements/threat-intelligence/rats.html for free code scanning, and then move up to the commercial product if necessary.

    • #47012

      That’s a good idea. I hadn’t thought of that. I just tried it out on a few bits of code and it seems to be decent. We do have the full product for one of our other environments, but I’m not sure we have the license for this project as well. I’ll have to look into this.

    • #47013

      Keep in mind sanitizing like this may breakyour web application. (Most likely visually at some points.)
      1. You can search and replace $_GET with htmlentities($_GET, ENT_QUOTES). (Do NOT forget to put the ENT_QUOTES flag. This also goes for htmlspecialchars().)

      If you need to do this across many GET or POST variables, etc., use a regular expression where the contents of $_GET is matched like [a-zA-Z0-9], along with the linux scripting it can work.

      The second alternative may also break the web application, and I’m not sure this is possible, but try this for starters and for fun:
      $_GET = htmlentities($_GET, ENT_QUOTES)

      You may have to call all of the arrays at once or do a “for each” in the $_GET array, and then redefine it, but that may also work.

      Just keep in mind, that if some of your web apps needs unsanitized characters it’s game over.

      Also, when it comes to SQL Injection, htmlentities() and htmlspecialchars() can actually prevent some types of injections, but generally you should either use mysql_real_escape_string() or prepared statements.

      Keep in mind, that with at least mysq_real_escape_string() or your own custom function (which I can’t recommend you create as custom sanitization functions often has bugs), can still be vulnerable if implemented incorrectly.

      “SELECT id FROM users WHERE id = “. mysql_real_escape_string($_GET). “; is vulnerable to SQL Injection, as you can do blind injections like 1 OR 1=1. Same if you use htmlentities or htmlspecialchars in this case. Therefore, make sure you use encapsulation the right places, and if you’re using integers for input, make SURE you do it right like:
      “SELECT id FROM users WHERE id = “. intval($_GET) .”; (Keep in mind this is a signed integer, if you need larger numbers than what a 32-bit system can produce, use something like floatval() instead.

      This eliminates strings in user-input where you only want numbers. You can of course add regular expressions for your input, as long as you do NOT use the ‘e’ (evaluate as PHP) flag, as that can be quite dangerous to use, especially along with variables like this “$var” as that is evaluated too, compared to ‘$var’.

      If you have identified all vulnerabilities with a web scanner and you’re 99,9% sure of this, work your way from there and fix the vulnerabilities manually.

      Instead of using scripts like this: echo “Your name is: “. $_GET;

      Do it like this:

      $name = $_GET;
      echo “Your name is: “. $name;

      Then re-use the $name variable wherever you need it, and if you need to change the sanitization it uses, you can just change definition of the $name = $_GET; variable to e.g., $name = htmlentities($_GET);

      Now, all of this is nice, but what about:
      – Session management (are sessions and cookies secure (not easy to predict or steal) and being handled correct?)
      – Anti-CSRF tokens (If they don’t exist, these needs to be added to forms. If there’s a million forms, begin with those that relates to any administrative function (especially change password functions), and then work your way to normal user functions, then unprivileged functions even though the last one is not as important as the first two.

      Take a look in the web application hacker’s handbook vol. 2 in case you haven’t.

      I should note, that Owasp actually does have an input sanitizer application available, but you should be careful putting all your trust in one application. Do you trust your firewall 100%? I don’t trust mine, as I know it can be bypassed like any other firewall.

      My 2 cents for today  😉

    • #47014

      Wow, that was a great and insightful post. Thanks for the info.

      The only special character that this application should let through is an apostrophe for maybe a comment box or a last name. Other than that, it should only be alphanumeric characters.
      I had been thinking of htmlentities or htmlspecialchars for XSS prevention, but a simple regex like you mentioned may work in most cases as well.  And we already have something in place for SQL injection, so we should be good there.
      I had been looking at the OWASP stuff and see they have some PHP filters that may come in handy. I was interested in their ESAPI project, but it says the PHP version is not suitable for production.

      Unfortunately there are a lot of places where code would need to be edited to include all of this and we’re down to a few precious developers that are overloaded with work, so it’s going to take time. In the meantime I was considering deploying a WAF like ModSecurity to help in at least reducing the risk. It’s a temporary fix, but I’d like to have a WAF in place long term anyway and if it can help in this “limbo” phase, then I think it would be worth it. Any thoughts on that?

      As far as other vulnerabilities, I’m pretty positive that I have discovered nearly all of them – mostly with just manual testing. There are some other issues, but I’m trying to work from high risk to low risk. There seem to be a few issues besides XSS that would be resolved by input validation/sanitation, so I can take them all out with one blow.

      Oh, and my web application hackers handbook has been my trusty sidekick along the way  😉

      Thanks again for the input – I was able to get a lot out of that.

    • #47015

      Concerning WAF’s, I would check this one out: https://phpids.org/ (Mario Heiderich is one of the top folks in XSS), along with Suhosin (http://www.hardened-php.net/suhosin/), created by Stefan Esser (at least he has the copyright) and he’s one of the big guys in PHP security too.

      Keep in mind mod_security and even Suhosin too, may break your web application. Don’t use magic_quotes or safe_mode as this is removed from PHP 6, meaning you should sanitize properly instead and e.g., jail the Apache process too.

      There are of course, a few mentioned WAF’s here but I don’t know much about them: https://www.owasp.org/index.php/Web_Application_Firewall

      To be honest, a properly configured mod_security could function as a WAF too, if you go beyond default configuration that is. Make sure you test the functionality before sending it out into a production environment.

      Otherwise, test it locally first if you don’t have the option of testing on a beta / development server or for that sake close the production server down while you reconfigure the new waf, and then use it in the production environment knowing it works as intended. (Do a full test of functionality after the WAF is enabled.)

      As it seems like you got SQL Injection covered, I would like to note that if you need to allow apostrophes aka ‘ , make sure that you are NOT printing user-input in fields / code like below:
      echo “

      “. htmlentities($_GET) .”


      At first it may seem like, special characters are encoded to their entities so you can’t use “, > and <, but you can use '.

      As the tag looks like this when you enter O’Connor:


      you can see that it’s actually a vulnerability, as you can use eventhandlers in the


      This is why if you must allow apostrophes aka ‘ , only output it outside tags and NEVER inside javascript.
      echo “

      “. htmlentities($_GET) .”


      Is “safe”, even though here comes another problem that has nothing to do with special characters, it’s actually character-sets. Depending on which character sets you use, you can perform XSS too as you’re probably aware of. (This one isn’t widely used by attackers. Most can only inject ‘”>alert(0).)

      NEVER use blacklisting of words like as a security measure. You can use it as an extra measure, but always start with proper encoding first.

      Also as you said you need the apostrophes in e.g., names, keep in mind this has an entity too, so if it’s printed on a website like: ' , you will visually see an apostrophe.

      If you need it inside a database on the other hand and it must be the actual apostrophe, make sure you encapsulate input in quotes aka ” and NOT apostrophes. Otherwise, attackers can inject with e.g., 1′ OR ‘A’=’A
      (The web application will finish the query and add the remaining apostrophe for you.)

      Anyway, good luck with the project  ;D I’m sure you’ll fix all of the vulnerabilities one by one, and on the way there, you will probably discover a few smart ways to solve it. (But don’t use too much time trying to find a smart way, as you can easily use the same amount of time it would take to actually resolve the problems the old sequental way.)

      I should note one last thing about WAF’s, and that is, you must assess the type of legit data that comes in, and evaluate whether a firewall would deem it as “illegal traffic”. I run a forum that’s about hacking, imagine I implemented a firewall that gets triggered on words like (even in e.g., forum posts). I actually did that once and after a very short while I found out it wasn’t working out  🙂 (It was horrible, but if it’s a normal business website, I guess it’s relatively small amounts of or no data at all that a firewall may deem as illegal traffic.)

    • #47016

      A good brief tutorial on XSS protection in PHP.

    • #47017

      Definitely some more good information. I’ve also read some of shiflett’s stuff before and it’s really good. One thing he mentioned that I had been thinking about is filtering input and escaping/encoding output. That seems to be the most logical thing and goes along with what we’ve been talking about.

      On a quick side note, is using PHP’s quote_smart function sufficient for blocking SQLi? From what I can see, it uses magic_quotes, which means no. Is that right?

      Anyway, thanks for all the help – you’ve gone above and beyond on this one!

    • #47018

      @eyenit0 wrote:

      On a quick side note, is using PHP’s quote_smart function sufficient for blocking SQLi? From what I can see, it uses magic_quotes, which means no. Is that right?

      Anyway, thanks for all the help – you’ve gone above and beyond on this one!

      Why don’t you use mysql_real_escape_string() or prepared statements as I previously said? (Make sure you implement it correctly as I also stated.)

      magic_quotes is a no go, especially if you think about upgrading to PHP6 in the future, and addslashes() is a NO GO as well.

    • #47019

      Well, I was asking that question thinking more of some things that are already in place, not necessarily where I want things to go. Just trying to gauge where we stand in terms of SQLi  :-

      This thread has been very helpful and I’m looking forward to implementing some of these suggestions.

    • #47020

      Sounds great, about where you stand when it comes to SQL Injection; Well it depends on your application. This is plaussible even though I doubt your application is coded like this: All input is integers only, and all of them, are run through intval() or floorval(). In this you can’t really inject anything besides trying integer values out.

      If you’ve used preg_replace the right way, or preg_match, you may only be accepting [a-zA-Z0-9] for other alphanumeric input. In that case, you would stand pretty good, if you did that with all user-input.

      Where you stand, depends on:
      1) How much of the user-input is sanitized or filtered to disallow SQL Injection? If all user-input is, you stand pretty good.
      2) What kind of filter or sanitization is being used? If you’re using the recommended ways, pretty good, if you’re using your own way, it can range from poor / bad to good or even very good. (It depends on how you implemented it.
      3) Developer errors, how many are there of them approximately? (E.g., you’ve fixed user-input sanitization in one function, but not another using the same variable.)
      4) Are the developers aware of security holes such as XSS, CSRF SQL Injection, Session Fixation, etc. If no, you stand very bad. But if they do, you stand well / good.

      In essence. It’s hard to say when I have to guess, but as you know about the vulnerabilities, you stand at least “good”, as you know they’re there and that you have to fix them, at least the critical ones first. (LFI, RFI, RCE if any, then SQL Injection, then persistent (stored) XSS, then non-persistent / reflected XSS along with CSRF. Of course there’s more vulnerabilities than just these. Insecure File Upload, in case you allow file uploads, is in the LFI,RFI,RCE range too. I.e., even more critical than SQL Injection.)

    • #47021

      Well, after looking over what’s being done for SQLi, I’m actually pleasantly surprised that it’s more robust than I had anticipated. I’d go into more detail if I could, but I’ve already said too much. I don’t want to get burned for posting company intel!

      Luckily, I’ve been able to sit down with the lead developer and discuss the plan of action on certain items, and nail down the proper procedures. The developers are aware of the security holes, but until now have done nothing about them.
      Hopefully that changes soon! At least now the ball is rolling and I expect all issues to be closed soon. Maybe then I can sleep at night without nightmares of bots on my web servers…

    • #47022

      I’m sad to hear they already know about the vulnerabilities, but glad to hear they acknowledge them and that they should get fixed, plus they got you on the team as well  ;D Naturally it wouldn’t be smart to disclose any sensitive details about the application, so I understand completely  😉

    • #47023

      Well, they didn’t know specific vulnerabilities or the extent to which they could be exploited until I took the liberty to show them, so now they are finally getting some attention!
      Thanks again for the help you’ve given.

Viewing 16 reply threads
  • You must be logged in to reply to this topic.

Copyright ©2021 Caendra, Inc.

Contact Us

Thoughts, suggestions, issues? Send us an email, and we'll get back to you.


Sign in with Caendra

Forgot password?Sign up

Forgot your details?