PHP is insecure by default
When I say PHP is insecure by default is that if you just write PHP code to do something (just like they teach in the basic tutorials or in first year programming classes), then most likely the code is insecure. That is because in order to make PHP secure, the programmer has to actively write some extra code. Most beginners will not know what that extra code is. As long as it works as expected, they think they are done. And that is why there is so many unsecure PHP code out there.
As of this writing in 2015, PHP is over 20 years old. Back then, security was not such a big thing and PHP was not build with “secure by design” (as explained in the article PHP Security: Default Vulnerabilities, Security Omissions and Framing Programmers?) Now it is difficult to retrofit security into it with breaking a lot of backwards incompatibility.
To give you an example of how PHP is insecure by default. Take a look a this basic code to take a user’s name …
and greet the user with a “Hello”…
Insecure Code
This is something that you might learn in PHP 101 and the code might look something like this …
And it would work as expected. The problem is that it is insecure.
Cross Site Scripting Attack
For example, an hacker can run an inserted Javascript on the page simply by entering the script in the name field…
And the script would run on the page as you can see from the script alert box…
This is known as script injection. And they can make Javascript run a script from another server. This is called cross-site-scripting, or XSS attack.
You may say, so what is the big deal with an user being able to bring up an alert dialog? This is just an example to confirm that an user is able to inject Javascript to run in the browser. If Javascript is able to run, it can be made to run Javascript from another server (hence the name cross-site-scripting). And without giving you any details, that script can perform serious damage, including but not limited to key logging to get user password, prompt users to install browser plugins, and in certain cases get access to user system (if they clicked “allowed” to have certain browser plugins installed).
But the attack is on the attackers own machine? In this example it is. But it real life, the script tag that is posted is likely saved to the database. Then an user on another machine may be running the same web application which pulls information from that database field which contains the script tag. If the web page does not escape that script tag, that script will run on another person’s machine. This is known as “stored XSS attack”.
Or if we use GET instead of POST, then it is possible for attacker to put script tag to be in the URL query string. The attacker sends the query string to whole bunch of people. A few people who hover over the link in the email and check the domain name sees that it is a valid website might click on the link, unknowing that the website has vulnerability that just ran Javascript on his/her browser. This is known as “reflected XSS attack”.
But doesn’t the “same-origin policy” prevent this? No, both reflected XSS and stored XSS passes the “same-origin policy”. Because the script tag is generated from the server, the browser sees it as from same origin.
To Prevent Cross Site Scripting
The above example was run on Microsoft Edge browser. If you run it this particular attack on latest version of Chrome, it would fail, giving the following error on Javascript console because Chrome is smart enough to detect that is this a possible cross site scripting attack…
Not saying that Chrome prevents all cross site scripting attacks. But this particular example, it did. Nevertheless, you still need to add code to make this web app secure. Do you think a PHP beginner will know what code to write?
The way to prevent XSS attacks is to always “filter inputs” and “escape output”.
Filter Inputs
Because user provided data can never be trusted, you need to filter the inputs. Use PHP filter_var function. For example …
Even though the second parameter of filter_var function is optional, you need to always put in a filter flag. Otherwise, as quoted from the PHP Manual…
“If omitted, FILTER_DEFAULT will be used, which is equivalent to FILTER_UNSAFE_RAW. This will result in no filtering taking place by default.”
See what I mean when I say PHP is unsecure by default.
While this will prevent the attack by encoding the HTML special character of the brackets giving …
Escape Outputs
You should nevertheless also escape all outputs that is derived from user data.
Learn more with this book …
How prevalent are these vulnerabilities?
According to 2013 report, 86% of all sites tested by WhiteHat Sentinel had a serious vulnerability, with the most prevalent being “information leakage” and “cross site scripting”. And it writes …
“Every single Manufacturing, Education, Energy, Government, and Food & Beverage website had at least one serious vulnerability identified.”