In writing web applications PHP developers often find themselves repeatedly calling the The problem with this is a human one. Humans do make mistakes, and even those well aware of the consequences and solutions will eventually suffer from an oversight that results in an XSS vulnerability. How can we limit the possibility of creating vulnerabilities in such a situation?
We’ve seen a very fair share of approaches to mitigating XSS in PHP but one in particular seems to fly under the radar. PHP has a couple of configuration directives in php.ini which will automagically filter input by various sanitization and/or validation flags of your choosing. So, can we make it work like In your (recent) default php.ini file you will find the following: [filter] ; http://php.net/filter.default ;filter.default = unsafe_raw ; http://php.net/filter.default-flags ;filter.default_flags = Modify these as follows: [filter] ; http://php.net/filter.default filter.default = full_special_chars ; http://php.net/filter.default-flags filter.default_flags = 0 This will encode all $_GET, $_POST, $_COOKIE, $_REQUEST and $_SERVER values. (The original data can be accessed through the filter_input() function.) Example In Action
As a quick proof of concept I built a simple login form that does no sanitization or encoding. The first (Username) field is pre-filled with the data you submitted if an error occurs, such as not providing any password. To exploit the first form field, I entered Without the php.ini configuration changes:
The input data is parsed by the browser as code and the JavaScript alert is displayed, thereby proving the presence of an XSS vulnerability. Now, with the php.ini configuration changes:
The input data is safely output into the form field as content instead of code, thereby mitigating the XSS vulnerability. Common Questions
Not a Replacement for Defense in DepthWhile this approach can simplify output encoding and limit the risk of developer oversight, it should not be considered an end-all solution. You may have input data sources in your application other than PHP's superglobals. You should still consider the results of a SQL query or cURL request, for example, as potentially malicious. Finally, you should continue performing penetration testing and code reviews to catch that inevitable XSS vulnerability before they do. |
Alex Stanford 136 Posts Mar 27th 2014 |
Thread locked Subscribe |
Mar 27th 2014 6 years ago |
Something's gone pear-shaped with the email notification, because I have received 7 emails for this diary entry.
|
Dan 9 Posts |
Quote |
Mar 27th 2014 6 years ago |
Quoting Dan:Something's gone pear-shaped with the email notification, because I have received 7 emails for this diary entry. No doubt about it. Something went wrong in our notifications back-end. I've temporarily resolved the issue by suspending notifications as a whole while we seek out the underlying cause and a permanent solution. Sincerest apologies! |
Alex Stanford 136 Posts |
Quote |
Mar 27th 2014 6 years ago |
I like this in principal, BUT disaster waiting to happen, if the PHP.ini gets reverted or "tweaked".
Perhaps it makes sense to not use PHP superglobals within a program at all. Do the sanitization of inputs yourself in an automated way, when capturing the input from the superglobals, to application-specific variables. Because the system or local PHP.ini is totally separate from the program. It can be reverted if users don't follow directions, OR it's incompatible with other scripts the server must run; various scenarios can make php.ini customization go away. Therefore; it's not safe to rely on within the context of an application: it's similar to the magic_quotes idea. Do you have a suggested way to establish this AND couple this setting more tightly with the PHP application? Without having to rely on the user to make sure that PHP.ini has customizations, AND these customizations are working? If not... your application's security correctness (including: safety of inputs) should not be reliant on a PHP.INI setting! |
Mysid 146 Posts |
Quote |
Mar 27th 2014 6 years ago |
Quoting Mysid: Writing custom sanitization methods which account for the context is not a bad approach, and was my preferred approach prior discovering this one. However, I think that approach is still more likely to result in developer mistakes than relying on the core of PHP, a broadly reviewed codebase, to handle the task with only 2 directives. (and a couple lines of code to check that the directives are in place, as you pointed out and I will discuss next.) Not only more likely to result in developer mistakes when writing the custom sanitization methods, but also the issue of remembering to use those methods instead of superglobals in every case. (Including the case where it's an emergency hotfix and the pressure is on) Additionally, custom sanitization methods add extra learning curve overhead when adding a new PHP developer to the project as compared to utilizing superglobals which every PHP developer would be aware of. Quoting Mysid: Without having tested it (yet) I believe you could couple the application with the ini settings by utilizing the PHP core function ini_get to check whether the settings are in place as expected. Short of that, you could run die('Incorrect php.ini settings'); etc. I wrote that this may not be a good solution in distributed applications (especially which will run in shared environments), but is better suited to an environment where it's a custom web application running on a dedicated server. (So, I would not recommend this approach for say, Wordpress or WHMCS) Admittedly, you've made a very good point about coupling the application with the ini settings. I am going to verify my suspicion that ini_get will provide a solution and add it to the diary if so. Thank you very much for the feedback! P.S. I was never a fan of magic quotes. :) Update: I've verified that ini_get is a working solution and I've added it to the "Common Questions" section of this diary. For those who don't wish to scroll back up, you would add this code to the beginning of your application: if(ini_get('filter.default')!=='full_special_chars'||ini_get('filter.default_flags')!=='0') die('Missing and/or incorrect filter.default and/or filter.default_flags directives in php.ini'); |
Alex Stanford 136 Posts |
Quote |
Mar 27th 2014 6 years ago |
Sign Up for Free or Log In to start participating in the conversation!