I want to know if the use of bindParam is mandatory to prevent SQL injection using PDO and MYSQL.
Example:
$username=$_POST['username'];
$password=$_POST['password'];
$cryptpass=hashFunction($password);
$sth=$dbh->prepare("INSERT INTO users(username,password) VALUES(?,?)");
$sth->execute(array($username,$cryptpass));
Is it a safe and proper way to write this code? Omitting bindParam makes shorter code.
This is still binding the values to a prepared statement. You are doing the same thing as if you were using the bindParam function. So the answer is yes it is just as safe. bindParam just allows for more functionality than simply binding with the execute function for example:
$sth=$dbh->prepare("Select * from users where status=:v1");
$sth->bindParam(':v1',1,PDO::PARAM_INT);
$sth->execute();
This allows you to specify the data_type by default with execute everything is sent as a string. Also you can look at the answer to this similar question: PDO bindParam vs. execute
All that matters is that you use parameters rather than substituting directly into the query string. It doesn't matter whether you bind the parameters with bindParam or with an array argument to execute, they're equivalent.
Related
I have an application that takes data via a POST request. I am using this data to insert a new row into the database. I know that using mysql_real_escape_string() (plus removing % and _) is the way to go for strings, but what about integer values? Right now, I am using the PHP function intval() on them.
However, I wanted to make sure that intval() is perfectly safe. I can't see a way of an attacker preforming a SQL injection attack when the variables are run through intval() first (since it always returns an integer), but I wanted to make sure this is the case from people that have more experience than I.
Thanks.
Yes, intval() is safe. There is absolutely no way to perform an SQL injection when the parameter is converted to integer, because (obviously) the format of an integer does not allow putting SQL keywords (or quotes, or whatever) in it.
The easiest way to prevent SQL injection is to always use prepared statments. Use the mysqli libraries or better yet an ORM such as doctrine etc.
Your queries then become something like:
$stmt = $db->prep_stmt("select * from .... where userid = ? and username = ?");
/* Binding 2 parameters. */
$stmt->bind_param("is", $userid, $username);
$userid = 15;
$username = "don";
/* Executing the statement */
$stmt->execute( ) or die ("Could not execute statement");
I always do
$var = (int)$_POST['var'];
to make sure $var is handled as an integer in all circumstances, and never look at $_POST['var'] again. Looking at the manual, intval() does exactly the same.
Whichever way you go, in subsequence $var will be an actual integer, which is quite safe to handle.
Prepared statment is best way to deal sql injection.
or use PDO
otherwise, intval is better than is_numeric
I am new to the PDO class, I have been using MYSQLI since just now and I am kind of confused. This question is rather simple but I cannot find the answer in straight text anywhere in the manual. So calling $pdo->query(some query) will automatically escape the query and will not leave any room for potential injections of any kind. Is this true?
NO, this is NOT true.
To avoid any risk of mysql injections you will need either prepared statments or to escape properly your variables (which would involve you to manually escape each variable before submit). I would suggest to use prepared statements because they are way easier to use. Please read this post How can I prevent SQL injection in PHP?. You can either have those with mysqli OR PDO, a nice example of PDO prepared statments, token from stackoverflow
$id = 1;
$stm = $pdo->prepare("SELECT name FROM table WHERE id=?");
$stm->execute(array($id));
$name = $stm->fetchColumn();
You can learn more here about PDO prepared statements. I would also like you to have a look here How can prepared statements protect from SQL injection attacks?
the query function is not safe.
you better use prepare of the PDO object.
e.g.
$sth = $dbh->prepare("select * from mytable where myattr = :attr");
the $sth handler can be used to set the placeholder in your query (e.g. :attr in this example)
you have two choice :
either you use an array directly in the execute function of the handler :
$sth->execute (array ('attr', $myattr));
or the bindParam function of the handler then execute
$sth->bindParam ('attr', $myattr);
$sth->execute();
The method provide a good way of escaping the single quotes in your arguments.
note : also take a loot at Why you Should be using PHP’s PDO for Database Access (net.tutsplus.com)
No, PDO::query is just as vulnerable as mysql_query or any other raw query method.
If you do
$sql = "SELECT foo FROM bar WHERE baz = '$var'";
and $var is
Robert'; DROP TABLE users; --
so the result is
SELECT foo FROM bar WHERE baz = 'Robert'; DROP TABLE users; --'
then no API can help you, because no API can tell the difference between what the query part and what the user value is. This difference is only clear to the API when you use prepared statements or escape special characters in the value properly.
Read The Great Escapism (Or: What You Need To Know To Work With Text Within Text).
The php manual seems to be a little light regarding the mysqli extension and I am not finding any information poking with Google.
When I create a mysqli prepared statement, should the order of calls be
mysqli::prepare()
mysqli::stmt::bind_param()
mysqli::stmt::execute()
mysqli::stmt::store_result()
mysqli::stmt::bind_result()
or
mysqli::prepare()
mysqli::stmt::bind_param()
mysqli::stmt::execute()
mysqli::stmt::bind_result()
mysqli::stmt::store_result()
Furthermore, if I then want to change the parameters and reexecute the statement, should I use
mysqli::free_result()
mysqli::stmt::execute()
mysqli::stmt::store_result()
mysqli::bind_result()
or can I simply use execute() again and then use free_result() once I am finished using the statement?
It is not PHP manual but mysqli extension itself being unclear and ambiguous.
However, to clear your confusion
You can call store_result() anywhere you wish between prepare() and fetch(). As a matter of fact, bind_result() is just a supplementary function for fetch().
In PHP you rarely need to free anything in general, and especially in cases like this, when result going to be overwritten in the next call. So - yes, you can simply call execute() again (with bind_param() first).
Also note that some installations will let you call get_result which makes all that process with fetching variables at least sensible. But is isn't always available
Also note that neither bind_param() nor bind_result() will let you easily bind an arbitrary number of variables, which will make code even more bloated.
So, looking at all that mess I'd still suggest you to use either PDO or manually implemented placeholders, like safeMysql does.
here is an example that works:
$query="SELECT service_ip,service_port FROM users WHERE username=? and password=?";
$conn=connection();
$stmt = $conn->prepare($query);
$stmt->bind_param('ss', $user,$pass);
$ans=$stmt->execute();
$service_ip=false;
$service_port=false;
$stmt->bind_result($service_ip,$service_port);
$stmt->fetch();
mysqli_free_result($ans);
$stmt->close();
$conn -> close();
Here is proper code:
$query="SELECT service_ip,service_port FROM users WHERE username=? and password=?";
$stmt = $conn->prepare($query);
$stmt->execute(array($user,$pass));
$data = $stmt->fetch()/fetchAll()/fetchColumn();
// whoops! that's all
// ...in case you want to execute again
$stmt->execute(array($user2,$pass2));
$data = $stmt->fetch()/fetchAll()/fetchColumn();
// and again...
$stmt->execute(array($user3,$pass3));
$data = $stmt->fetch()/fetchAll()/fetchColumn();
Note that you already have all required data. Feel the power of PDO
I understand the right way to protect a db from SQL injection is by using prepared statements. I would like to understand how prepared statements protect my db.
For starters, are prepared statements the same thing as "parameterised queries"?
As an example, I'm pasting below my code for the insertion of a new user in a user table. Is that secure? How does PDO work to make it secure? Does anything more needs to be done to secure the db from injection?
In 'Class_DB.php':
class DB {
private $dbHost;
private $dbName;
private $dbUser;
private $dbPassword;
function __construct($dbHost, $dbName, $dbUser, $dbPassword) {
$this->dbHost=$dbHost;
$this->dbName=$dbName;
$this->dbUser=$dbUser;
$this->dbPassword=$dbPassword;
}
function createConnexion() {
return new PDO("mysql:host=$this->dbHost;dbName=$this->dbName", $this->dbUser, $this->dbPassword);
}
}
In 'DAO_User.php':
require_once('Class_DB.php');
class DAO_User {
private $dbInstance;
function __construct($dbInstance){
$this->dbInstance=$dbInstance;
}
function createUser($user){
$dbConnection=$this->dbInstance->createConnexion();
$query=$dbConnection->prepare("INSERT INTO users (userName, hashedPassword, userEmail) VALUES (?,?,?)");
$query->bindValue(1, $user->userName);
$query->bindValue(2, $user->hashedPassword);
$query->bindValue(3, $user->userEmail);
$query->execute();
}
}
Thanks,
JDelage
Ok, I found the answer to my question in this related question: Are PDO prepared statements sufficient to prevent SQL injection?
Thanks to Haim for pointing this Q to me.
In non technical terms, here is how prepared statements protect from injection:
When a query is sent to a data base, it's typically sent as a string. The db engine will try to parse the string and separate the data from the instructions, relying on quote marks and syntax. So if you send "SELECT * WHERE 'user submitted data' EQUALS 'table row name', the engine will be able to parse the instruction.
If you allow a user to enter what will be sent inside 'user submitted data', then they can include in this something like '..."OR IF 1=1 ERASE DATABASE'. The db engine will have trouble parsing this and will take the above as an instruction rather than a meaningless string.
The way PDO works is that it sends separately the instruction (prepare("INSERT INTO ...)) and the data. The data is sent separately, clearly understood as being data and data only. The db engine doesn't even try to analyze the content of the data string to see if it contains instructions, and any potentially damaging code snipet is not considered.
Here's my somewhat limited view on the matter...
A prepared statement is compiled on the DB server with placeholders for variable input.
When you bind a parameter, you're telling the DB which values to use when you execute the query. It will then pass the value to the compiled statement.
The difference between binding parameters and plain old string injection is that with the former, the value is not interpolated but rather assigned. During execution, the DBMS hits a placeholder and requests the value to use. This way, there's no chance of quote characters or other nasties sneaking their way into the actual statement.
Without using prepared statements, you could not use placeholders (?) in your query.
Instead, you would need to include the value you want to insert directly into the SQL statement. This would result in a different SQL statement for every insert (bad for performance) and if you are not careful about what strings you put into the statement you may also end up with a statement that does something else then what you intended to (for example SQL injection could happen).
This situation is somewhat similar to having a Javascript function that does some fixed code with variable input parameters, versus pasting the input parameters into the Javascript source and then eval'ing it.
your source is secure from sqli attack.
it's example and not secure when you select one the user from your database.
// example: localhost/user.php?username=admin
$getdata = $_GET['username'];
$dbConnection=$this->dbInstance->createConnexion();
$query=$dbConnection->prepare("SELECT * FROM users WHERE username=".$getdata.");
// PHP simple
I use mysql_real_escape_string() to validate all user inputs before I insert them in a sql database. One of the fields is name, and we've had issues with users with names like O'Reilly. Is there any way to use mysql_real_escape_string() to block injections but allow these names in the db?
The problem is most likely that the apostrophes get quoted twice: first by the evil and deprecated in 5.3 magic quotes and then by mysql_real_escape_string().
What you can do is either disable magic quotes or run stripslashes() on your input values before feeding them to mysql_real_escape_string()
Brief explanation of the problem:
the user enters O'Reilly
magic quotes automatically turn it into O\'Reilly
the script feeds the string through mysql_real_escape_string() which escapes both the backslash and the apostrophe (again) yielding O\\\'Reilly
the query is executed, the quoting is processed and the database understands that you want a backslash and an apostrophe since they where both escaped, and records O\'Reilly
As already mentionned : mysql_real_escape_string is not meant for input validation. If you want to validate inputs, use your own functions or the filter functions from php.
If you have too many slashes added automatically by php, disable magic quotes.
To prevent SQL injection, use parameterized queries with either PDO or mysqli.
+1 for using PDO. I've been using PDO in favour of a MySQL class acting as a database abstraction layer for a few months now and it's a breeze.
Traditionally, developers would use the stripslashes() function on data before applying a function like mysql_real_escape_string(). It's still a good idea to remove slashes from input data, but you can then either use the PDO method for escaping data (PDO::quote($data)) or binding the parameter.
Your query block would then look something like this:
$pdo = new PDO(DSN, DB_USER, DB_PASS);
$sql = "INSERT INTO table (field1, field2) VALUES (:value1, :value2)";
$smt = $pdo->prepare($sql);
$smt->bindParam(':value1', $value1, PDO::PARAM_STR);
$smt->bindParam(':value2', $value2, PDO::PARAM_STR);
$smt->execute();
$rows = $smt->rowCount(); // returns number of rows affected
I hope this helps somewhat. Take a look at http://php.net/manual/en/book.pdo.php for more information on PDO in PHP.