I know most of the answers will say use PDO/Mysqli but I'm trying to see if I can do it this way then move on to PDO/Mysqli still learning:
Will this function be enough to prevent mysql injection?
function anti_inject($sql)
{
$sql = preg_replace(sql_regcase("/(from|select|insert|delete|where|drop table|show tables|#|\*|--|\\\\)/"), "", $sql);
$sql = preg_replace("/[^a-zA-Z0-9]+/", " ", $sql);
$sql = mysql_real_escape_string($sql);
$sql = trim($sql);
$sql = strip_tags($sql);
$sql = addslashes($sql);
$sql = strtolower($sql);
return $sql;
}
Looking for a better replacement for this line $sql = preg_replace(sql_regcase("/(from|select|insert|delete|where|drop table|show tables|#|*|--|\\)/"), "", $sql);
As I do want to check for names that have "from" "select" "insert" gaming tags etc
I've disabled drop table from the mysql user
No. That's hopeless.
$sql = preg_replace(sql_regcase("/(from|select|insert|delete|where|drop table|show tables|#|\*|--|\\\\)/"), "", $sql);
This throws away data for no apparent reason
$sql = preg_replace("/[^a-zA-Z0-9]+/", " ", $sql);
This throws away data for no apparent reason
$sql = mysql_real_escape_string($sql;
If you hadn't lost the ), then this is the correct way to convert a piece of data for inserting into an SQL query.
$sql = trim($sql);
This throws away data for no apparent reason
$sql = strip_tags($sql);
This throws away data for no apparent reason
$sql = addslashes($sql);
This escapes data in a way inappropriate for an SQL query. Some data will be double escaped (and therefore broken) because you have already used mysql_real_escape_string.
$sql = strtolower($sql);
This mangles data for no apparent reason.
When using the obsolete, deprecated mysql_ library, mysql_real_escape_string is the only escaping function you should use. You then need to take the results and use them appropriately when bashing your string of SQL together.
Don't use mysql_ though. Use PDO and parameterised queries.
Strictly speaking, in terms of SQL injection protection this function is awfully useless and unusable at the same time. While it may serve you in some particular case of yours, it cannot be used as a general purpose solution. Yet even for such a case it is awfully redundant.
So, why not to use a solution already proved to be error-proof for all the (covered) cases - PDO prepared statements?
Related
I want to know if my code is 100% secure agasint SQL injection, it looks like this:
$table = $_GET['table'];
switch ($table) {
case 'data':
$sql = "select * from $table";
break;
case 'anothertable':
$sql = "select * from $table";
break;
}
$con = new mysqli($hostname,$username,$password,$db_name);
$result = $con->query($sql);
If $table is not matched by the switch, you haven't set $sql at all...
Otherwise, you have avoided the risk of injecting bad things via $table by whitelisting the acceptable table names.
One point I would make is that one has to read quite closely to see that $table has changed from an untrusted input to a validated table name. So anyone coming to your code in future may think
that you have a problem here that needs fixing, or
that interpolating variables into SQL queries is generally acceptable.
So probably worth going out of your way to explain in comments what you're doing, and (more importantly) why.
In your place I would avoid such a dynamical querying based on the user input, as it smells of a bad application design,
But in regard of SQL injection your code is safe, as it's rightfully implementing the only proper strategy possible - the whitelisting.
Your code is not safe. Here is an example of how you would make it safe with MySQL (PDO). I'm doing it in PDO because that is what I use often and not mysqli :)
$table = $_GET['table'];
$valid_command = FALSE;//value becomes true if you find your
//value in the following if conditional
if (($table==='table')||($table==='anothertable'))
{
$valid_command = TRUE;
}
if ($valid_command)
{
$sql = "SELECT * FROM table";
$sqlPrepared = $conn->prepare($sql);
$sqlPrepared->bindParam(':table', $table);
$sqlPrepared->execute();
}
If you wish to do this in mysqli, it is easy to adapt it. Hope that helps.
I've made a simple search-script in PHP that searches a mySQL database and outputs the result. How this works is like this:
User searches for "jack's" through a search-form.
My PHP-script GETs this search, and sanitizes it.
Then the script, with the use of SELECT and LIKE, gets the results.
The script then outputs the result to the user.
Lastly, the script tells the user that "jack's returned x results." with the help of escaping.
What I would like to ask is, am I doing it right?
This is how I sanitize before SELECTING from the database:
if(isset($_GET['q'])){
if(strlen(trim($_GET['q'])) >= 2){
$q = trim(mysql_real_escape_string(addcslashes($_GET['q'], '%_')));
$sql = "SELECT name, age, address FROM book WHERE name LIKE '%".$q."%'";
}
}
And this is how I escape before outputting "jack's returned x results.":
echo htmlspecialchars(stripslashes($q)) . " returned x results.";
Is this the correct way to do it?
By the way, I know that PDO and mySQLi is preferred as they sanitize themselves through the use of prepared statements, but I have no real experience with them whatsoever. But I would gladly take a look, if you guys could link me some newbie tutorials/explanations.
Furthermore, I heard that magic_quotes and charset could in some way or another lead to injections -- is this correct?
For some reason we need also escape a backslash too.
So, the proper code would be, I believe
if(isset($_GET['q'])){
$_GET['q'] = trim($_GET['q']);
if(strlen($_GET['q']) >= 2){
$q = $_GET['q'];
$q = '%'.addCslashes($q, '\%_').'%';
// now we have the value ready either for escaping or binding
$q = mysql_real_escape_string($q);
$sql = "SELECT name, age, address FROM book WHERE name LIKE '$q'";
//or
$sql = "SELECT name, age, address FROM book WHERE name LIKE ?";
$stm = $pdo->prepare($sql);
$stm->execute(array($q));
$data = $stm->fetchAll();
}
}
For the output, use
echo htmlspecialchars($_GET['q']);
stripslashes not needed here.
Furthermore, I heard that magic_quotes and charset could in some way or another lead to injections -- is this correct?
magic quotes won't harm your security if you won't use them.
charset is dangerous in case of some extremely rare encodings but only if improperly set. if mysql(i)_set_charset or DSN (in case of PDO) were used for the purpose - you are safe again.
As for PDO, a tag wiki should be enough for starter, I believe
The code below is written in php:
$user = addslashes($_POST['user']);
$pwd = addslashes($_POST['pwd']);
$query = "SELECT * FROM userdata WHERE UserName='$user' AND Password=PASSWORD('$pwd')";
the query will then be sent to mysql
Is there anything more I need to take care of?
Please point out.
No it's not safe, use mysql_real_escape_string at minimum:
$user = mysql_real_escape_string($_POST['user']);
$pwd = mysql_real_escape_string($_POST['pwd']);
And for better security go for prepared statements.
Best Options:
PDO
mysqli
You may ask which one to choose, check out:
What is difference between mysql,mysqli and pdo?
Nope.
The reason is that while a single quote ' is not the only char that break a sql query, quotes are the only chars escaped by addslashes().
Better: use mysql_real_escape_string
$user = mysql_real_escape_string($_POST['user'], $conn);
$pwd = mysql_real_escape_string($_POST['pwd'], $conn);
$query = "SELECT * FROM userdata WHERE UserName='$user' AND Password=PASSWORD('$pwd')";
Best: use PDO and prepared statements
$stmt = $dbh->prepare("SELECT * FROM userdata WHERE UserName=':user' AND Password=PASSWORD(':pass')");
$stmt->bindParam(':user', $user);
$stmt->bindParam(':pass', $pass);
No. You should not be using addslashes() to escape your data. That's been obsolete for years. You should be either:
using mysql_real_escape_string() as a replacement
using prepared statements with PDO or MySQLi
Plus using MySQL's Password() function is also poor pracdtive. Use hashes with salts. Bcrypt is my recommendation. Also, check out PHPass.
Protecting against SQL injection is easy:
Filter your data.
This cannot be overstressed. With good data filtering in place, most security concerns are mitigated, and some are practically eliminated.
Quote your data.
If your database allows it (MySQL does), put single quotes around all values in your SQL statements, regardless of the data type.
Escape your data.
Sometimes valid data can unintentionally interfere with the format of the SQL statement itself. Use mysql_escape_string() or an escaping function native to your particular database. If there isn't a specific one, addslashes() is a good last resort.
Read more: http://phpsec.org/projects/guide/3.html#3.2
I have been doing a bit of research on SQL injections and so far all I can see is when you are concatenating query strings with variables, you have problems.
My question(s) is/are:
If I have this code:
$query = "SELECT id, name, inserted, size FROM products";
$result = odbc_exec($conn, $query);
Am I subject to sql injection? I didn't think so but I found a post on stackoverflow that indicated that it was.
Now if I have this code:
$variable = "name";
$query = "SELECT"' .$variable. ' FROM products";
$reulst = odbc_exec($conn, $query);
Am I still stubject to injection? It seems to me that I have full control of that variable and the code is run on the server side so that would be safe. Is this correct?
Thanks in advance for any input!
SQL injection is usually a problem if you have input from a source you can't trust. Seeing as this is the case in neither of your examples, you're fine as far as malicious attacks go.
However, it is good practice to escape $variable before inserting it into the query string even if you control it.
You are prone to sql injection if you allow any user input into your queries at all. With the two examples provided, nothing is being input from the user, so these are both safe.
The first query is not subject to injection as there are no dynamic parts to it.
The second is. Even if you think you have full control over your variable, if you are using user supplied data (whether coming from form sumbit, cookies etc...), you can be vulnerable.
Always use parameterized queries through a SQL library that will ensure data is safely escaped.
The only case when a query can get exposed is when parts of it are passed from input.
$variable = $_GET["name"];
$query = "SELECT " .$variable. " FROM products"; // now things can get bad
$reulst = odbc_exec($conn, $query);
One correct way of using input variables inside a query would be to escape them:
$variable = addslashes($_GET["name"]); // sanitizing input
$query = "SELECT " .$variable. " FROM products"; // all good here
$reulst = odbc_exec($conn, $query);
The issue is "where do the values of your variables come from?" If you are using user-submitted data in a query, then you need to be careful how you use it. In your case, you're safe as far as I can tell.
For the first example, no, you won't be subject to any SQL injection because there is nothing a user could input to change your query.
In the second case, you're only subject to injection if $variable is derived from some user input.
Any time you take user input straight into your $query you are susceptible to sql injection. The first code you show is fine, its a straight query, there is no way for the user to input any harmful code.
$query = "SELECT id, name, inserted, size FROM products";
$result = odbc_exec($conn, $query);
But the second code snippet (if $variable is taken from a form ) anyone could enter in harmful code and kill your database.
$variable = $_POST['name']; **for instance, this would be bad!
$query = "SELECT"' .$variable. ' FROM products";
$reulst = odbc_exec($conn, $query);
How does $variable get its value?
here my code-
$things = serialize($_POST['things']);
echo $things;
require 'database.php';
$q = "INSERT INTO tblslider(src) values($things)";
mysql_query($q, $link);
if($result)
{
echo "Slider saved successfully.";
}
Output-
a:4:{i:0;s:10:"651603.jpg";i:1;s:11:"7184512.jpg";i:2;s:11:"3659637.jpg";i:3;s:10:"569839.jpg";}v
it means I am getting the record properly but why it it not getting saved in db??
You forgot quotes around $things:
$q = "INSERT INTO tblslider(src) values('" . mysql_real_escape_string($things) . "')";
The mysql_real_escape_string() is really the least you should ever do!
Also as #sanders mentions, you should always output your complete query (via print_r() or var_dump()) as a first step in debugging.
I prefer to build queries like this to enhance readability:
$q = sprintf(
'INSERT INTO tblslider(src) VALUES ("%s")',
mysql_real_escape_string($things)
);
That is, whenever I absolutely have to build and escape them myself. You should really have a look at PDO.
EDIT
Comments in this thread suggests that OP actually wants to insert 651603.jpg,7184512.jpg,3659637.jpg,569839.jpg into the database. In that case implode() could be used (provided that $_POST['things'] only contains items to insert!):
$q = sprintf(
'INSERT INTO tblslider(src) VALUES ("%s")',
mysql_real_escape_string(implode(',', $_POST['things']))
);
Note, that I'm using $_POST['things'] directly here. No serialize(). (I did, however, not realize this erro until just now.)
This question is quite old, but I feel like it's time for a little necromancy. The accepted answer by #jensgram is not wrong, but saying mysql_real_escape_string is the least you could do implies there is a much better solution. Well there is.
PHP Data Objects
PDOs. These bad boys provide an abstraction layer for your database access, so it works with a lot of other databases not just MySQL, and can improve performance when the same query is run many times. Nut this is not why you need them.
Security
Escaping stuff is hard. Either it is obscure how to do it in a specific context or you just forget to do it. The worst thing is that you will not get any errors from forgetting it, and just move on like nothing happened. And you just contributed to the sorry state internet security is in.
With using PDOs properly (e.g. no string concatenation) however will ensure that you will not mess up properly escaping stuff while building DB queries.
You will want to read this: (The only proper) PDO tutorial.
Basically you can prepare an sql statement BEFORE replacing ANY parameters in it. The SQL syntax will be fixed and cannot be broken by bad/no escaping or maliciously forged requests.
So how to do this
At first you need a connection, just like in the regular mysql driver.
$host = '127.0.0.1';
$db = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $pass, $opt);
As you can see there are settings, error modes, fetch modes. It worths reading what each setting does but for now just leave it as it is. At the end of it all, you have the $pdo variable you can use.
$query = "INSERT INTO tblslider(src) VALUES (?)";
$stmt = $pdo->prepare($query);
At this point we got our statement. Nothing came from external sources yet, it is an INSERT statement.
$things = serialize($_POST['things'])
$stmt->execute([ $things ]); //execute
There are other ways to bind the ?-s to parameters, also you can use named parameters too for clarity, but this suffices for now.
That's it: no fancy escaping but no possibility for SQL injection either.
Normally, I will serialize then base64_encode to eliminate surprises and "standardize" the input. For example:
$things = base64_encode(serialize($_POST['things']));
$insert_query = "INSERT INTO...";
Then, when you want to grab it, simply reverse the process.
$query_result = mysql_query("SELECT FROM ...");
$row = mysql_fetch_assoc($query_result);
$retrieved_value = unserialize(base64_decode($row['src']);
You are writing a string to the database, so don't forget to add quotes to your query:
$q = "INSERT INTO tblslider(src) values('$things')";
Also make sure to filter the string to avoid SQL-Injection Attacks.
place an var_dump($q) before mysql_query(...)
You can then examine your query.