![]() |
sql injection prevention advice
hi
i've got some old mainstream sites that were getting hacked with sql injection (only turkish script kiddies), as a temporary measure i removed some functionality of the site to prevent it happening again. i want to get the sites working properly again. i found this code snippet while i was searching for a solution, is this all i need to prevent an sql injection attack using post or get happening again? Code:
//This stops SQL Injection in POST vars thanks in advance |
Yes, that will help. However, all the values should be validated if you want to stop all potential issues as it will also depend on how the sql statements are done.
You want to do something like this on the post values. And I think it needs to be done after you're connected to the database for mysql_real_escape_string to work. Code:
foreach($_POST as $key => $val){ |
Using mysql_real_escape_string() is a good start but it is far from being enough. Next you should make sure that you use ' around all values in SQL, both strings and numbers. Remove words such as UNION, SELECT, DROP, LOAD, BENCHMARK # -- /* and so on.
There are so many possible ways of injection that it is close to impossible to make it really bulletproof. You should make a read-only SQL user with only read rights (for that particular database) which you use for your SELECT statements. Never use the root mysql user. Then have one user with write-only rights for UPDATE. Delete-only for DELETE. etc If you are even more paranoid you could lock certain SQL commands to certain tables to mitigate the potential damage. Doing this approach with multiple sql-connections can be difficult on premade scripts. I am sure there are many more things to do. But for sure you are not protected if you only rely on that PHP code. Maybe someone else can chime in with more and better suggestions. :thumbsup |
Quote:
e.g. You have pagination that uses GET parameters like: /models?page=1&hair=blue While the user may not have had the option of typing in "blue" they could still override the GET param with some sort of SQL injection string... so it needs to be escaped. The proper solution... and here is why the MVC Model/View/Controller design pattern is so damned handy ;) is to escape each field being queried for or updated using the aforementioned real escape string function/method. If your code base is MVC your Model (the database) logic will be split out so adding in this check for each field should be simple. If you're using something procedural or even OO and the Model is not split out correctly you'll be doing a LOT of search/replace action to find every place one of the queries is done and escape each individual field... I WOULD NOT recommend doing something on every POST field unless each field is not used anywhere else in the code base. Otherwise you'll end up with lots of issues with variables no longer matching was was expected... Imagine $modelName="April O'niel" vs = "April O\'Neil"... Long story short it can either be a huge pain in the ass or not that big of a deal depending on the competency level of the developer who originally wrote the script :P Hope that helps clarify that a bit for you ;) |
Quote:
Best practices dictate a MySQL user should ONLY have the finite privileges it requires. All other privileges should be revoked for that user. Those privileges should also only apply to the DB(s) that user needs to access (they should not be global privileges). |
You should sanitize $_GET, $_POST and $_COOKIE and also be paranoid about values from HTTP Headers (if you use them in SQL, for example HTTP_REFERER)
Good luck ;) |
And one more thing, make sure that neither PHP nor MySQL is allowed to give error messages. No error message should be sent to the screen. It makes it harder for the attacker to see what he is doing as he will have to operate blindly.
|
You can also move some of the logic to PHP instead of MySQL. For example you can compare values in PHP arrays instead of sending them to MySQL.
SQL for authentication (unsafe) Code:
SELECT 1 FROM users WHERE username='$username' AND password='$password' SQL to preload PHP array Code:
SELECT username, password FROM users Code:
if ($passwords[$username] == $password){ |
|
Quote:
Also for putting quotes around integers, that is not a great idea either. While MySQL has advanced to the point it doesn't make a huge speed difference anymore, it still does slow-down queries on extremely large tables or involving complex joins and it still slows queries down quite a bit in PostgreSQL. The proper thing to do would just be to properly sanitize all variables that are involved in your queries. If everything is sanitized, there will be no injection. For example, instead of putting quotes around an integer like age, you can verify it's of the proper type and within a specific range. The rest of your advice I can agree with though :) |
Quote:
|
Oh, I almost forgot one important thing.
MySQL accepts both ASCII and HEX values. Someone could write their payload as 0x6e6f7468696e67206865726520746f20736565 That string could contain anything... Such strings could possibly go undetected by type-validation as all the ASCII chars look harmless. Making proper sanitation is really hard, and there is always the risk that you have missed something. In my opinion one should be extra paranoid with databases. They are like Swiss cheese.. |
Quick tip: if the value you're expecting should be an integer, you can force PHP to treat it as such like this:
$val = 0 + $_POST["variable"]; |
Quote:
$val = intval($_POST['variable']); And always use single quotes unless you need special escaped chars... Every time you use double quotes for a string in PHP you cause the string interpreter to parse the entire string looking for variables, special chars, etc... Using single quotes instead ensures that doesn't happen... :2 cents: |
if you use wordpress, this is prevented by default on their CMS.
. |
Quote:
As for the int thing, let's all argue about how best to handle them lol... I actually do a preg_match on all values that are supposed to be pure integers so I can catch invalid data. i.e.: preg_match('/^[+-]?\d+$/', (string)$value) |
someone forward this thread to CCBill :1orglaugh:1orglaugh:1orglaugh
|
Quote:
same goes for the split() function, which is very common across people's code so better off with explode in most cases. |
Quote:
I've got a lot of sites using variations of this (very old) script, its not suported anymore and i don't have the time to find an alternative and switch to that. so i've just got to try and patch it up as best as possible. they were using something along the lines of this to hack the script: Code:
page.php?id=-999999999+union+select+concat(login,0x3a,password),1,2,3,4,5+from+adminlogin/ |
PHP's website has good examples for you.
php.net/manual/en/security.database.sql-injection.php :thumbsup |
Quote:
CONCAT is also a naughty word as you found out. |
Quote:
|
A safer practise is to use parameterized SQL queries. It also has performance benefits.
The negative thing is that makes your code more complex, and thus less pretty. See example here (note MySQLi and not MySQL) http://www.php.net/manual/en/mysqli.prepare.php |
Use a mysql class. I've been using the mysql class at ricocheting.com/code/php/mysql-database-class-wrapper-v3 and modified it a little bit to add some functionality that I needed. It's good protection for lazy coders like me.
|
All times are GMT -7. The time now is 02:39 AM. |
Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2025, vBulletin Solutions, Inc.
©2000-, AI Media Network Inc123