views:

146

answers:

5

After seeing this awesome guide on Stack and needing a practical PHP/MySQL security checklist in-house, I have decided to pay homage to the original guide.

What I need is a practical security checklist for PHP and MySQL. The contents here can function as the checklist, while the answers should function as the guides.

By practical I mean that each answer should avoid superfluous security theoretics and focus on real results. Most of us don't need to know about RFC3174 when you're suggesting to secure passwords using a SHA-1 hash. We just want to make passwords secure.

I will go through the entries from time to time and tidy them up so they have a consistent look and feel and it's easy to scan the list. Feel free to follow a simple "header - brief explanation - list of instructions - gotchas and extra info" template. I'll also link to the entries from the bullet list below so it's easy to find them later.

Procedural note: PLEASE pick one and only one of the below topics and answer it clearly and concisely. Don't try to jam a bunch of information into one answer. Don't just link to other resources - cut and paste with attribution if copyright allows, otherwise learn it and explain it in your own words (that is, don't make people leave this page to learn a task). Please comment on, or edit, an already existing answer unless your explanation is very different and you think the community is better served with a different explanation.

PHP


Validate user input
Guard your file system
Guard your sessions
Guard against XSS vulnerabilities
Guard against invalid POSTs
Guard against CRSF
Stop using $_REQUEST
Stop using register_globals


MySQL


Avoid SQL injection

Use mysql_real_escape_string to protect against SQL injection


Keep in mind that the above list is only a starter, and that many of the above topics will likely become sub-headers and are too broad to write on. Try to distill something smaller like "Stop using register_globals" rather than, say, trying to write an answer on XSS as a whole. Over time I hope everyone can add many more things.

A: 

Stop using $_REQUEST

$_REQUEST combines $_GET, $_POST, and $_COOKIE.

Why is this dangerous to use?
The inclusion of $_COOKIE is what makes this dangerous. If any of your form parameters have the same name as a cookie, things can start breaking in ways that become difficult to debug.

How can you avoid this?
You can avoid this behavior in one of three ways:

  1. PHP 5.3 has the request_order config, which you can set to GP (as opposed to GPC). The default php.ini configuration now excludes the C for cookies.
  2. Don't use $_REQUEST in your code. Instead, choose either $_GET or $_POST, or
  3. Create your own $_REQUEST using a combination of $_GET and $_POST in your application's bootstrapper like so:
    $_REQUEST = array_merge($_GET, $_POST);
Josh Smith
I don't see how cookie makes $_REQUEST dangerous. I don't use $_REQUEST because it isn't clear where the input is coming from.
Rook
PHP as a project removed this from the default php.ini config just because cookies make them dangerous in this way. Your reason is just one more not to use it
Josh Smith
@Josh I highly doubt this was removed due to security concerns. Can you post supporting evidence?
Rook
+1  A: 

Use mysql_real_escape_string() to protect against SQL injection

You can use:

mysql_real_escape_string()

to make data safe before sending a query to MySQL, this will secure your queries from SQL injections.

Gerard Banasig
Edited to improve formatting some. Thanks for adding!
Josh Smith
+2  A: 

While mysql_real_escape_string is fine, you really should be using PDO to query your databases. http://php.net/pdo.

benjy
Would you mind expanding slightly on this, for example "Why you should make the switch to `PDO`"? Don't try to write about `PDO` as a whole, just outline the benefits of switching, e.g. being able to swap between `SQL` databases.
Josh Smith
Look at how I edited the other answer for some thoughts on where to go.
Josh Smith
A: 

Check out the PHP Security Guide, and the OWASP Top 10.

But in all reality your security check list should be the entire CWE system. There are over 1,000 vulnerabilities in this list. Weather or not you have to take these into consideration depends what you are doing.

Security isn't a check box, it isn't a mechanical set of rules to follow. As an exploit writer I attack the developers perception of the systems they are using. As an attacker my job is about creativity and persistence.

Rook
Perhaps your answer would be better suited as a comment or a revision to the community wiki above? I see what you're saying, but the intent here is to find a *practical* checklist that suits the needs of the vast majority of web application developers out there. True enough that there is no one size fits all solution, but there are certainly ways to distill the most common and necessary best practices.
Josh Smith
@Josh Smith Not really, what you are asking for is the php security guide, owasp and the cwe system. But in all reality you are oversimplifying the problem and this extremely damaging. If you don't understand how systems are exploited, you are just accidentally preventing vulnerabilities.
Rook
+1  A: 

Avoiding SQL injection

Use prepared statements with bound parameters. When parameters are bound they are sent to the MySQL server outside the SQL and the server doesn't parse them as part of the SQL. The content of the parameters can therefore never be injected into your SQL to compromise your server.

This is safer than mysql_escape_real_string which relies on PHP detecting and escaping relevant characters.

http://www.php.net/manual/en/mysqli-stmt.bind-param.php
http://uk2.php.net/manual/en/pdostatement.bindparam.php

Mike
when you use the word never, it makes me incredibly wary. Would you be willing to put your application on the line for people to try? If the answer is no, then please don't say never.
Woot4Moo
It's implied by the use of bound parameters when using php/mysqli. The SQL statement (? marks and all) is sent first, the parameters sent second. The server parses the SQL statement without parameter substitution during parsing and checks parameters for type only. The parameters are NEVER parsed as potential SQL, there can be no SQL injection unless the PHP module or MySQL server code are screwed. Correctly done bound parameters need cooperation from the server so you still need to check if PDO is really using bound parameters (check docs) or just mimicking by escaping strings (e.g. SQLite).
Mike
http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html
Mike