For days now I try to get my head round how to write a secure web application in php, and it turns out to be particularly difficult. The more I read, the more I sink in deep swamps full of vulnerabilities which are not mentioned by kind people like Matt Robinson or Chris Shiflett.
For a few examples, take:
- http://sirdarckcat.blogspot.de/2009/10/couple-of-unicode-issues-on-php-and.html
- https://www.owasp.org/index.php/Double_Encoding
- Also see character consumption as in Rook's answer
In short,I see the following problems:
- When filtering input, it is not very clear how that data will be decoded later, and thus character encoding and escaping systems can bypass the input filtering. (such as double url decoding)
- When escaping output, one uses standard functions such as htmlspecialchars. It is all nice that htmlspecialchars has an encoding parameter, however that doesn't prevent you from sending UTF-16 input to it, and that could probably break the security value of the function.
It seems there is a mbstring module in php, but if it is vaguely as secure as it's documentation is comprehensible, than it 'll probably be useless even if I can figure out how to use it. Just a sample of the docs for illustration:
mbstring.strict_detection boolean
Enables the strict encoding detection.
Great, that's helpful.
Unfortunately the functions also depend on what you set in the configuration options... There seems to be a function called mb_convert_encoding
, but the docs say nothing about the security aspect and it seems you need to know the input encoding (a no go zone for security). There also is mb_check_encoding
. Which seems to be meant for the purpuse, but reading the user comments on the docs doesn't exactly inspire confidence.
So the question is, in the light of all this, how do you do secure input filtering? Something like this?
mb_convert_encoding
to utf-8mb_check_encoding
to reject invalid input- loop url_decode until the string stops changing
- Do your normal input filtering with text comparison and regex etc...
edit: note that 3 is problematic because your normal input filtering might introduce entities again that can be url decoded
edit
I found a partial answer here, from Shiflett. It seems that for htmlspecialchars using it's encoding parameter and making sure you set your character encoding header for the browser to the same would avoid that the browser interprets characters differently than htmlspecialchars does. That is all assuming that the input of htmlspecialchars is valid for the given encoding or that for every possible invalid input htmlspecialchars interprets the string in exactly the same way than every browser does. We know that if we find no way of sanitizing our input we cannot assure that the input of htmlspecialchars is validly encoded, because an attacker might cook up a string with invalid encoding. This leads us to the second possibity, that htmlspecialchars will behave identical as the browser for all possible inputs. This is a problem, since we cannot use the same tokenizer for escaping and using, since one happens on the server and one happens in the browser.
This is all similar to what msql_real_escape does for a database, although I think you can properly solve this problem for msql by using prepared statements instead.
A third problematic output is the filesystem when using php to do file uploads or other file system manipulations. About this last one there seems to be very little information available. I don't even know of a specific escape function, let alone one that is robust when it gets crooked input.
utf8_decode
ormb_*
) to begin with? Receive it as UTF-8, treat it as UTF-8, use the appropriate SQL and HTML escaping functions on it as UTF-8, inform the browser that it's UTF-8.