suppose i have a query like this :
$std_id = $_POST['std_id'];
$name = $_POST['name'];
$family = $_POST['family'];
$sql = "insert into student set
std_id = $std_id,
name = '$name',
family = '$family'";
$query = mysql_query($sql,$conn);
i read in a php security book that if user enter a value for family field like :
ahmad';drop database test#
can delete database test;
but we know that the mysql_query() function only allow to execute one query .
i want to know how can this input to be unsafe
There are many delusions in your question.
Let's sort them out.
mysql_query() doesn't support multiple queries execution.
(so, it is useless to delete anything)
dropping tables in the separate query is not the only way of the SQL injection.
(so, it is useless to delete anything again)
To protect your query you have to follow some well-known techniques, not some handmade inventions of doubtful efficiency.
Just worrying about multiple queries is not enough to protect SQL Security ... There are so many questions / answers on SO for you to read about this subject ..
How can I prevent SQL injection in PHP?
GET parameters vulnerable to SQL Injection - PHP
php sql injection
Also good resources on php.net
http://php.net/manual/en/function.mysql-real-escape-string.php
http://php.net/manual/en/security.database.sql-injection.php
Using multiple queries separated by a semicolon is not the only way to exploit your queries, it is just a very simple example. It will work, when you are using mysqli_multi_query().
Related
My friend is new to PHP concepts(And so am I), and he developed the code below. I know it is vulnerable, and I told him I could do stuff on his database, like messing with other tables, Update other values etc.
The vulnerable part of the code is an INPUT, that he uses for a common search. This is not a login.
$email = filter_input(INPUT_GET, 'email');
if ($email != '') {
$stm = $db->query("SELECT * from clients WHERE email = '$email'");
$result = $stm->fetchAll();
}
The problem is I can't do it, because query() only allows one statement per query. Is there a way to mess with anything important on his database? (This is a challenge for me to prove IN PRACTICE his mistakes)
With your code it's very easy to modify conditions of an SQL query.
I can easily get ALL the clients, by making that condition is always true:
http://localhost/inject.php?email=Client 1' OR '1'='1
I can even read details from another table:
http://localhost/inject.php?email=Client 1' UNION SELECT * FROM articles WHERE '1' = '1
It all depends on what you do with results later, but as I shown on this two simple examples it's better to protect yourself.
A select query cannot modify data using any SQL injection, but it can be easily used to echo data from different tables (like usernames and passwords).
Read second and third example here:
PHP's manual regarding sql injection
There's a lot of warnings about SQL injections here on SO, but no one I've found doesn't really answer, how does it happen? In this question, I'm assuming it's MySQL and PHP.
The basic mysql_ doesn't accept a second query inside a query, right?
So, basically, this
$unsafe = "');DROP TABLE table;--";
mysqli_query($con,"INSERT INTO table (Column) VALUES ('$unsafe'");
doesn't actually do anything harmful? Correct me on this.
I've no experience working with mysqli_, so I'll skip to PDO, and "Prepared statements".
When I started working with PDO, I had a lack of information on it, and basically used it like this, thinking it's safe.
$stm = $pdo->prepare("INSERT INTO table (Column) VALUES ('$unsafe');
$stm->execute();
However, same thing with PDO as with mysql_. It doesn't support multiple queries out of the box, right? Again, correct me on this.
Then, this is consired safe, if I'm not wrong?
$stm = $pdo->prepare("INSERT INTO table (Column) VALUES (?);
$stm->execute(array($unsafe);
How does a malicious user with no access to the database inject malicious data, if multiple queries aren't even supported?
Or are they?
How does a malicious user with no access to the database inject malicious data, if multiple queries aren't even supported?
"SQL injection" is not equal to "second query".
Or are they?
Surely they are.
Second query is just an example. While it can be any valid SQL statement. SQl injection is an exploit of improperly formatted query. If a developer don't format SQL properly, there is a possibility to break from limits of literal and add code to the SQL body.
Is an SQL injection actually possible by adding a second query?
Yes, depends on the API you are using.
Two queries with mysql + php is a fallacy
Source: http://xkcd.com/327/
This will not work with mysql and php without deliberate steps to make it possible, since the normal query function will only execute the first query.
That doesn't mean it's not possible - only that it should be very obvious when it is.
SQL injection is very real
But the above means almost nothing in terms of sql injection. There is a huge, huge amount of information out there about sql injection including a large number of questions here on stack overflow. Taking the example in the question, this is an equivalent attack which would work:
$id = "123 OR 1 = 1 --";
mysqli_query($con,"DELETE FROM table WHERE id = $id LIMIT 1");
i.e. finding an interface to delete my own, e.g., comment, if the id is not escaped it would be trivial to delete all comments. But this example is just the very tip of an iceberg.
Executing arbitrary sql statements are exploitable
This code in the question:
$stm = $pdo->prepare("INSERT INTO table (Column) VALUES ('$unsafe')");
$stm->execute();
Has none of the benefits of using PDO - i.e. any exploit (of the truly massive number) that would work with the mysql/mysqli driver (used naively) will work with pdo used in this way.
Parametrized queries protect against sql injection
Using PDO with prepared statements with parameters escapes values appropriately preventing sql injection attacks, so yes this is safe from injection:
$stm = $pdo->prepare("INSERT INTO table (Column) VALUES (?)");
$stm->execute(array($unsafe));
How does a malicious user with no access to the database inject malicious data
Simply by finding a way to execute sql that either does what they want to do, or gives them the information to do it a different way.
For example:
function login() {
$username = "irrelevant' OR is_admin = 1 --";
$password = hash('irrelevant');
$query = "SELECT id from users where username = '$username' AND password = '$password'";
...
}
How did malicious user get access to the admin functionality on a system with no concern for injection? Very easily.
For general information about injection see the previous references.
I can see many discussions on why is better to use PDO bindValue vs bindValue. But what I could not find was precice information on why should I use that vs a simple variable in the query. Could anyone tell me? thanks
$sex = 'male';
$s = $dbh->prepare('SELECT name FROM students WHERE sex = :sex');
$s->bindParam(':sex', $sex);
$s->execute();
VS
$sex = 'male';
$s = $dbh->query('SELECT name FROM students WHERE sex = $sex'); // OR PREPARE, The question is how to pass the variable.
Like others have said, you want to use PDO to prevent SQL injection. Say a user with bad intentions types something like ';drop table students;-- into an input box on your site. Without PDO, the final query will look like this:
SELECT name FROM students WHERE sex = '';drop table students;--'
See what would happen? The select statement would run and not find any results (unless you have students in your table with no sex specified). Then, the drop statement would run, and your entire students table would be deleted.
This is just one example—there are all kinds of SQL injection attacks, many of them more dangerous than this. Using PDO prevents pretty much all of them. Internally, the bound variables are kept separate from the query itself.
The main reason is by using prepared statements and bound variables you protect yourself against the most common vector used for sql injection attacks.
A second reason is if you have multipe requests to run the same query statement, but with different variable values, you can save time by only having the server calculate the execute plan once, then run it on the the variables as you call the same statement over and over. Think about looping over the same statement several time. This is the concept of serverside prepared statements which mysql allows and PDO supports.
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
What is SQL injection?
XKCD SQL injection - please explain
I own a company and am wishing to know the runabouts of PHP while I am hiring for people to maintain and extend code for its websites, I was looing up on security on SQL injections and do not quite understand how these codes can affect the SQL database as they are in contained strings to the query.
How may one show the security flaw, so that I can see for myself what is happening?
Although much of this can be explained online, I have a feeling to explain this in a bit more detail.
If you can visualise what the string will become, you will understand the underlying risks of the script you are writing, in that it will become something else before it is actually ran.
A trivial malicious example:
$fromtheuser = "foo'; DROP TABLE affiliates; --";
$q = "SELECT id FROM affiliates WHERE website = '$fromtheuser'";
Can you explain what this will become? The developer couldn't.
"SELECT id FROM affiliates WHERE website = 'foo'; DROP TABLE affiliates; --'"
The key portions of this vector being '; to end the SQL string primitive, and --' to comment out the pushed quote.
What you would be looking for in the code written, is proper sanitization and filtering of the data before it is even placed in to the query. One important tool to help secure this front is some form of prepared query, in such you can bind the parameters to the query so that there is nothing to manipulate.
We can achieve this with prepared statements in either MySQLi (improved) or my personal favourite PDO. A quick rundown of what they look like.
mysql_real_escape_string (can handle encoding and quotes)
<?php
$clean = mysql_real_escape_string($q)
MySQLi:
<?php
$clean = $mysqli->prepare("SELECT id FROM affiliates WHERE website = ?");
$clean->bind_param('s', $website); //'s' for 'string'
PDO:
<?php
$clean = $pdo->prepare("SELECT id FROM affiliates WHERE website = ?");
$clean->bindParam(1, $website); //you can use :site rather than ? and 1
mysql_query("SELECT * FROM users WHERE username = '$username'");
Look what happens when we set the $username variable to something nasty:
$username = "' OR 1";
The query becomes:
SELECT * FROM users WHERE username = '' OR 1
An attacker can use improperly escaped variables to inject SQL into your query, effectively bypassing any (poor) security measure you have in place.
More info here
It's also worth noting that there are tools through which you can test whether your site is susceptible to injection attacks.
Take a look at
http://sqlmap.sourceforge.net/
The danger coming from the fact, that SQL query being a program.
So, malicious code can be injected in place of some operator.
string being delimited by quotes. if a delimiter inside of a string weren't escaped, it will actually close string statement and the rest going to be malicious code.
not only strings being dynamic. No delimiter will protect LIMIT $amount if $amount will contain malicious code, as well as ORDER BY $order.
somewhere while studying I juz found out something interesting.. It says something as follows:
$query = sprintf("SELECT firstname, lastname, address, age FROM friends
WHERE firstname='%s' AND lastname='%s'",mysql_real_escape_string($firstname),
mysql_real_escape_string($lastname));
using the query like this instead of
$query="select firstname, lastname, address, age FROM friends
WHERE firstname='".$_RETURN['name1']."', lastname='".$_RETURN['name2']."'";
does this seem reasonable.. have u tried this coding ever.. and how it helps prevent any malicious attacks..
First off, what this is about is called is SQL-Injection. It's basically just the possibility to alter queries against the database via user input.
Let's look at an example:
Query:
SELECT temp1 FROM temp WHERE temp2 = 'VAR1';
Now we'll assign VAR1 the value of: '; DROP TABLE *; --
And we'll get:
SELECT temp1 FROM temp WHERE temp2 = ''; DROP TABLE *; --';
With mysql_real_escape_string it would look like this:
SELECT temp1 FROM temp WHERE temp2 = '\'; DROP TABLE *; --'
mysql_real_escape_string 'secures' a string for usage within a query.
But in the end, you should stop using the mysql_* altogether. They're deprecated and considered as insecure when it comes to preventing SQL injection or other means of tempering with the queries.
You should simply stop concatenating queries together like this and start using prepared statements, which not only are easier to use, prevent SQL Injection by default but also can improve the speed of your application.
For PHP there are two extensions which are designed to close the whole mysql_* opened:
mysqli
PDO
And I say it again: Please stop using mysql_*!
As far as I'm aware, mysql_real_escape_string is one of the better ways to prevent SQL injection, short of using prepared statements with mysqli or PDO.
Using formatting functions like sprintf is purely a matter of taste; the big advantage in the first example is that the function mysql_real_escape_string prevents all SQL injections (explained in one of the other answers); unlike the somewhat iffy magic_quotes_gpc feature in PHP, which many people rely on instead.
magic_quotes_gpc automatically escapes things you receive in requests from clients... but it cannot detect so-called second-level injections:
You get a malicious query from a client and store its contents in the database. magic_quotes_gpc prevents SQL injection; the malicious string gets stored correctly.
Later on, you fetch this string from the database and include it in another query. Now the string didn't come out of a request, so magic_quotes_gpc doesn't escape the string. Voilà, SQL injection; your data is now probably gone.
Using some means of escaping yourself, either something like mysql_real_escape_string or a database abstraction layer with a query builder (e.g. Adodb), is definitely superior to just hoping for the best.