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.
Related
How do prepared statements help us prevent SQL injection attacks?
Wikipedia says:
Prepared statements are resilient against SQL injection, because
parameter values, which are transmitted later using a different
protocol, need not be correctly escaped. If the original statement
template is not derived from external input, SQL injection cannot
occur.
I cannot see the reason very well. What would be a simple explanation in an easy English and some examples?
The idea is very simple - the query and the data are sent to the database server separately.
That's all.
The root of the SQL injection problem is in the mixing of the code and the data.
In fact, our SQL query is a legitimate program.
And we are creating such a program dynamically, adding some data on the fly. Thus, the data may interfere with the program code and even alter it, as every SQL injection example shows it (all examples in PHP/Mysql):
$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";
will produce a regular query
SELECT * FROM users where id=1
while this code
$spoiled_data = "1; DROP TABLE users;"
$query = "SELECT * FROM users where id=$spoiled_data";
will produce a malicious sequence
SELECT * FROM users where id=1; DROP TABLE users;
It works because we are adding the data directly to the program body and it becomes a part of the program, so the data may alter the program, and depending on the data passed, we will either have a regular output or a table users deleted.
While in case of prepared statements we don't alter our program, it remains intact
That's the point.
We are sending a program to the server first
$db->prepare("SELECT * FROM users where id=?");
where the data is substituted by some variable called a parameter or a placeholder.
Note that exactly the same query is sent to the server, without any data in it! And then we're sending the data with the second request, essentially separated from the query itself:
$db->execute($data);
so it can't alter our program and do any harm.
Quite simple - isn't it?
The only thing I have to add that always omitted in the every manual:
Prepared statements can protect only data literals, but cannot be used with any other query part.
So, once we have to add, say, a dynamical identifier - a field name, for example - prepared statements can't help us. I've explained the matter recently, so I won't repeat myself.
Here is an SQL statement for setting up an example:
CREATE TABLE employee(name varchar, paymentType varchar, amount bigint);
INSERT INTO employee VALUES('Aaron', 'salary', 100);
INSERT INTO employee VALUES('Aaron', 'bonus', 50);
INSERT INTO employee VALUES('Bob', 'salary', 50);
INSERT INTO employee VALUES('Bob', 'bonus', 0);
The Inject class is vulnerable to SQL injection. The query is dynamically pasted together with user input. The intent of the query was to show information about Bob. Either salary or bonus, based on user input. But the malicious user manipulates the input corrupting the query by tacking on the equivalent of an 'or true' to the where clause so that everything is returned, including the information about Aaron which was supposed to be hidden.
import java.sql.*;
public class Inject {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://localhost/postgres?user=user&password=pwd";
Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement();
String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='" + args[0] + "'";
System.out.println(sql);
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
}
}
}
Running this, the first case is with normal usage, and the second with the malicious injection:
c:\temp>java Inject salary
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary'
salary 50
c:\temp>java Inject "salary' OR 'a'!='b"
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary' OR 'a'!='b'
salary 100
bonus 50
salary 50
bonus 0
You should not build your SQL statements with string concatenation of user input. Not only is it vulnerable to injection, but it has caching implications on the server as well (the statement changes, so less likely to get a SQL statement cache hit whereas the bind example is always running the same statement).
Here is an example of Binding to avoid this kind of injection:
import java.sql.*;
public class Bind {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://localhost/postgres?user=postgres&password=postgres";
Connection conn = DriverManager.getConnection(url);
String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?";
System.out.println(sql);
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, args[0]);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
}
}
}
Running this with the same input as the previous example shows the malicious code does not work because there is no paymentType matching that string:
c:\temp>java Bind salary
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?
salary 50
c:\temp>java Bind "salary' OR 'a'!='b"
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?
Basically, with prepared statements the data coming in from a potential hacker is treated as data - and there's no way it can be intermixed with your application SQL and/or be interpreted as SQL (which can happen when data passed in is placed directly into your application SQL).
This is because prepared statements "prepare" the SQL query first to find an efficient query plan, and send the actual values that presumably come in from a form later - at that time the query is actually executed.
More great info here:
Prepared statements and SQL Injection
I read through the answers and still felt the need to stress the key point which illuminates the essence of Prepared Statements. Consider two ways to query one's database where user input is involved:
Naive Approach
One concatenates user input with some partial SQL string to generate a SQL statement. In this case the user can embed malicious SQL commands, which will then be sent to the database for execution.
String SQLString = "SELECT * FROM CUSTOMERS WHERE NAME='"+userInput+"'"
For example, malicious user input can lead to SQLString being equal to "SELECT * FROM CUSTOMERS WHERE NAME='James';DROP TABLE CUSTOMERS;'
Due to the malicious user, SQLString contains 2 statements, where the 2nd one ("DROP TABLE CUSTOMERS") will cause harm.
Prepared Statements
In this case, due to the separation of the query & data, the user input is never treated as a SQL statement, and thus is never executed. It is for this reason, that any malicious SQL code injected would cause no harm. So the "DROP TABLE CUSTOMERS" would never be executed in the case above.
In a nutshell, with prepared statements malicious code introduced via user input will not be executed!
When you create and send a prepared statement to the DBMS, it's stored as the SQL query for execution.
You later bind your data to the query such that the DBMS uses that data as the query parameters for execution (parameterization). The DBMS doesn't use the data you bind as a supplemental to the already compiled SQL query; it's simply the data.
This means it's fundamentally impossible to perform SQL injection using prepared statements. The very nature of prepared statements and their relationship with the DBMS prevents this.
In SQL Server, using a prepared statement is definitely injection-proof because the input parameters don't form the query. It means that the executed query is not a dynamic query.
Example of an SQL injection vulnerable statement.
string sqlquery = "select * from table where username='" + inputusername +"' and password='" + pass + "'";
Now if the value in the inoutusername variable is something like a' or 1=1 --, this query now becomes:
select * from table where username='a' or 1=1 -- and password=asda
And the rest is commented after --, so it never gets executed and bypassed as using the prepared statement example as below.
Sqlcommand command = new sqlcommand("select * from table where username = #userinput and password=#pass");
command.Parameters.Add(new SqlParameter("#userinput", 100));
command.Parameters.Add(new SqlParameter("#pass", 100));
command.prepare();
So in effect you cannot send another parameter in, thus avoiding SQL injection...
The key phrase is need not be correctly escaped. That means that you don't need to worry about people trying to throw in dashes, apostrophes, quotes, etc...
It is all handled for you.
ResultSet rs = statement.executeQuery("select * from foo where value = " + httpRequest.getParameter("filter");
Let’s assume you have that in a Servlet you right. If a malevolent person passed a bad value for 'filter' you might hack your database.
The simple example:
"select * from myTable where name = " + condition;
And if user input is:
'123'; delete from myTable; commit;
The query will be executed like this:
select * from myTable where name = '123'; delete from myTable; commit;
Root Cause #1 - The Delimiter Problem
Sql injection is possible because we use quotation marks to delimit strings and also to be parts of strings, making it impossible to interpret them sometimes. If we had delimiters that could not be used in string data, sql injection never would have happened. Solving the delimiter problem eliminates the sql injection problem. Structure queries do that.
Root Cause #2 - Human Nature, People are Crafty and Some Crafty People Are Malicious And All People Make Mistakes
The other root cause of sql injection is human nature. People, including programmers, make mistakes. When you make a mistake on a structured query, it does not make your system vulnerable to sql injection. If you are not using structured queries, mistakes can generate sql injection vulnerability.
How Structured Queries Resolve the Root Causes of SQL Injection
Structured Queries Solve The Delimiter Problem, by by putting sql commands in one statement and putting the data in a separate programming statement. Programming statements create the separation needed.
Structured queries help prevent human error from creating critical security holes.
With regard to humans making mistakes, sql injection cannot happen when structure queries are used. There are ways of preventing sql injection that don't involve structured queries, but normal human error in that approaches usually leads to at least some exposure to sql injection. Structured Queries are fail safe from sql injection. You can make all the mistakes in the world, almost, with structured queries, same as any other programming, but none that you can make can be turned into a ssstem taken over by sql injection. That is why people like to say this is the right way to prevent sql injection.
So, there you have it, the causes of sql injection and the nature structured queries that makes them impossible when they are used.
I'm very new to PHP and programming in general. I've come across an article about security, although not an issue yet in my case, I'm sure it will come up in the future at some point.
The article in question was about database input.
I'm using PDO most of the time while dealing with databases, however I'm confused about some parts. Perhaps someone can shed some light on a few things.
As I understand it, prepared statements in PDO for example:
SELECT <column> FROM <table name> WHERE <something>
Doesn't get execute right away(well, obviously) but only when execute(); is called. And gets interpreted as is.
So having something like
"SELECT <column> FROM <table name> WHERE" . <userinput> OR 1=1;
Lets say userinput is the username
And
<userinput> OR 1=1
is a user input variable via a form or whatever, will get interpreted exactly like that, meaning the username will be
userinput OR 1=1
And obviously no username OR 1=1 will exist in the database so an error will be returned.
That this mean that PDO is safe(a strong word, I know) from things like SQL injection? Or other 'hacking' methods?
What can I use/do to sanitize user input in general?
Yes it is safe, you can look at it as sandbox, if you have SQL like SELECT FROM books, it guaranties that input from user will not get out of boundaries (like modifying sql query), so it is safe from 1st order injection, but not from 2nd.
What i mean? Well PDO PREPARED statements(because you can use pdo without preparing statements in php) guaranties that you sql query is safe, but it doesn't filters the actual value.
Consider example: suppose we get some value from the form, the value will be 1); DROP TABLE books and we will save it in our database using our prepared statement INSERT INTO books VALUES(<value1>, ...),so the query will be executed successfully, value 1); DROP TABLE books will be saved in our database, but evil code will no be executed, no drop value. But if you then use our stored value in standard query, not prepared one. You will get hurt. But if you everywhere use PDO prepared statement your are safe. But i advice to filter values anyway.
Make use of Prepared Statements on PDO and you can stop worrying about SQL Injection.
I am sorry as this is the simplest answer i could give for this question.
Source
EDIT :
Found this answer on SO
Statement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();
If "user" came from user input and the user input was
Robert'); DROP TABLE students; --
Then in the first instance, you'd be hosed. In the second, you'd be safe and Little Bobby Tables would be registered for your school.
I am using mysql database for an application. I get some user details. Once user uses select keyword in his answer, the Insert query causes problems in mysql. I am using nearly 300 insert queries in my over all application. Select keyword makes problem.
How to solve it in easy way?
Thanks in advance
UPDATED:
$query = "INSERT INTO `feedback_entry_mailactivity_log` ( `subject`, `body_text`, `to_mail_id`, `from_mail_id`, `cc_mail_id`, `created_user_id`, `created_date_time`, `last_updated_user_id`, `last_updated_date_time`, `feedback_entry_id`, `feedback_id`, `account_id`, `section_id`)
VALUES ('".$subject."', '".$body_text."','".$to_mail_id."','".$from_mail_id."','".$cc_mail_id."','".$assign_to_userid."', NOW(),'".$assign_to_userid."', NOW(),'".$feedback_entry_id."','".$feedback_id."','".$this->account_id."','".$temp_sectionid."' );";
$this->db->execute($query);
In this case if $subject="select a tag";
Thus when I use keyword select insert query doesn't works
The problem is the use of string-generated SQL statement -- this can lead to incorrect escaping and injection attacks (or mis-behaviors) leading to errors like above. Imagine if one of the input variables -- the one with 'SELECT' in it -- contains the SQL string-escape character such as Wish this would' SELECT FAIL. (This might not be the exact problem in this case and the real problem could lay with some other layer trying to "protect" the use of the bad access method(s).)
To fix this problem correctly use PDO (or similar) and prepared-statements. (Jeremiah Willcock suggested mysqli_prepare).
The parameters to prepared statements don't need to be quoted; the driver automatically handles this. If an application exclusively uses prepared statements, the developer can be sure that no SQL injection will occur (however, if other portions of the query are being built up with unescaped input, SQL injection is still possible).
Note: Incorrect "solutions" include mysql_real_escape_string and similar. There are very few -- perhaps none for static DQL -- cases when "manual escaping with SQL string-building" approaches like this should be used.
Happy coding.
Historically, I've always used
mysql_real_escape_string()
for all input derived from users that ends up touching the database.
Now that I've completely converted over to MySQLi and I'm using prepared queries with bound parameters, have I effectively eliminated the possibility of SQL injection attacks?
Am I correct in saying I no longer need
mysql_real_escape_string()?
This is my understanding and the basis of a project of mine:
http://sourceforge.net/projects/mysqldoneright/files/Base/MysqlDoneRight-0.23.tar.gz/download
This is not something I want to get wrong though as now that I've released it, it could affect others as well.
All user provided input will now end up in bind_parms.
The queries provided in the prepare phase are static.
Yes. Using the prepared query will escape parameters.
It's not so simple. You can use bound parameters instead of interpolating application variables into SQL expressions in place of literal values only:
$sql = "SELECT * FROM MyTable WHERE id = ".$_GET["id"]; // not safe
$sql = "SELECT * FROM MyTable WHERE id = ?"; // safe
But what if you need to make part of the query dynamic besides a literal value?
$sql = "SELECT * FROM MyTable ORDER BY ".$_GET["sortcolumn"]; // not safe
$sql = "SELECT * FROM MyTable ORDER BY ?"; // doesn't work!
The parameter will always be interpreted as a value, not a column identifier. You can run a query with ORDER BY 'score', which is different from ORDER BY score, and using a parameter will be interpreted as the former -- a constant string 'score', not the value in the column named score.
So there are lots of cases where you have to use dynamic SQL and interpolate application variables into the query to get the results you want. In those cases, query parameters can't help you. You still have to be vigilant and code defensively to prevent SQL injection flaws.
No framework or data-access library can do this work for you. You can always construct a SQL query string that contains a SQL injection flaw, and you do this before the data-access library sees the SQL query. So how is it supposed to know what's intentional and what's a flaw?
Here are the methods to achieve secure SQL queries:
Filter input. Trace any variable data that gets inserted into your SQL queries. Use input filters to strip out illegal characters. For instance, if you expect an integer, make sure the input is constrained to be an integer.
Escape output. Output in this context can be the SQL query which you send to the database server. You know you can use SQL query parameters for values, but what about a column name? You need an escaping/quoting function for identifiers, just like the old mysql_real_escape_string() is for string values.
Code reviews. Get someone to be a second pair of eyes and go over your SQL code, to help you spot places where you neglected to use the above two techniques.
When you bind parameters to a prepared statement, it escapes the data automatically, so you shouldn't escape it before you send it through. Double escaping is usually a bad thing. At the very least, it produces ugly results with extra escaped characters later on.
Is the any difference between writing
{$_GET['id']}
and
'".$_GET['id']."'
in a sql statement? both works the same
Its always a bad idea to put data from a get request directly into SQL, and there are many easy ways to prevent SQL injection.
For the simple case where you know you want a numeric ID, then you can simply force the value to be numeric and then there is no chance of SQL injection. One way might be okoman's usage of sprintf(), maybe something like this:
$sql = "INSERT INTO table VALUES(".sprintf("%d",$_GET['id']) .")";
though I think its ugly and bad form. Something like this is nicer:
$sql = "INSERT INTO table VALUES(".(int)$_GET['id']) .")";
Which simply casts the value to an int - if its not a number that can be cast to int - you'll get a "0" which may or may not be what you want.
Other alternatives (and for when your data is not supposed to be a number) include using escaping functions such as add_slashes() or the above mentioned mysql_real_escape_string().
IMHO, the best way to use database access from within PHP and very easily protect from SQL injection is to use the new PHP PDO library ( http://php.net/PDO ). This allows you to write SQL strings that contain no data whatsoever, and have the data added later inside the database server itself. In this form there is absolutely no way to do SQL injection.
Here is some example code:
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
$stmt = $dbh->prepare("INSERT INTO table VALUES (?)");
$stmt->bindParam(1, $_GET['id']);
$stml->execute();
As you can see, the data is not added to the SQL query itself and so no need for escaping.
Using either of these directly in a SQL statement is a VERY BAD IDEA. It allows for SQL injections. Be sure to sanitize your inputs using something like mysql_real_escape_string.
The main difference between the two is that the top can only be used inside a string that uses double quotes. The bottom, however, can be used with either double or single quotes.
As far as I know there's no difference, but should you be doing that? You're allowing unsanitised input into your sql query which means if your website is internet facing you're leaving it wide open to sql injection attacks.
Here's a Q&A you should read before going any further:
How can I prevent SQL injection in PHP?
If you use a variable - especially an associative array - in a string, you can be quite sure that it will lead to errors. It's just bad style.
I - personally - don't like the second alternative either.
sprintf( '... %d ...', $_GET[ 'id' ] );
That's my favorite way of putting a variable into a string.