Two related questions that should be easy, though my searching has come up empty.
I have a from in PHP. If a field has a semi-colon in it, and I do a dump of $_POST in the action page, the field value is truncated at the semi-colon. I'm guessing this is related to SQL injection security? But legitimate semi-colons need to be allowed. Is there a setting that allows this to go through? Or do I need to escape it, and if so, how?
To catch actual SQL injections, I don't need to allow multiple statements in one query... like "SELECT * FROM table;DROP table". Is there a setting that disables this, either in PHP or MySQL, but without stopping legitimate semicolons?
semi-colons does not cause any problem.
Use prepared statements.
In mysqli:
$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
$stmt->bind_param('s', $name);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
In PDO:
$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
$stmt->execute(array(':name' => $name));
foreach ($stmt as $row) {
// do something with $row
}
Use mysql_real_escape_string
$unsafe_variable = $_POST["user-input"];
$safe_variable = mysql_real_escape_string($unsafe_variable);
mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
Check this question for more information How can I prevent SQL injection in PHP?
Ok, silly me. Yes, I am using prepared statements, escaping, etc. But I also wanted to sanitize the input before it even gets that far. So I have a global function that checks all parameters, taking out anything following apostrophes and semicolons. Works fine for GET values, but I forgot that I needed to update that to handle POST parameters differently, and had forgotten this was there, as I hadn't type a semi-colon until now. :) But thanks for the responses.
Related
My code has to pass a security check but it didn't because of a sql injection risk. They have requested that I use parameters which I thought I already used, so now I wonder how to make my code better?
$imgId = $_POST["imgId"];
$stmt = $link->prepare("SELECT * FROM my_table WHERE image_id = ?");
$stmt->bind_param("s", $imgId);
$stmt->execute();
$result = $stmt->get_result();
$stmt->close();
This is one of my sql statements, each and every one is structured like this one.
So my question is first of all is my code susceptible to sql injections and secondly how do I make it more secure?
maybe you should try regular expressions on your IDimg if u know what the expected input to be, and pregmatch it
How do you delete all contents of a table in PHP MySQL using prepared statement? Do I have to use prepared statement to be safe or does using $deleteall = mysqli_query($conn,"DELETE FROM mytable;"); works with no difference?
Is this how it's supposed to be done:
$stmt = $conn->prepare("DELETE FROM mytable");
$stmt->execute();
There's no point in using prepared statements when you don't have parameters.
Prepared statements exist to make if efficient to execute a statement multiple times, possibly with different arguments. They also help with SQL injection prevention: you don't have to remember to apply quoting and escaping manually. But if you're going to run something only once there are no parameters, don't bother with prepared statements.
You may want to delete records with criteria parameters so the best way to do it:
$sqlQuery = "DELETE FROM TABLE_NAME WHERE id=?";
$statement = $conn->prepare($sqlQuery);
$statement->bind_param("i", $memberId);
$statement->execute();
Use this way, it is working fine on me. Hope it will help you.
$stmt= 'DELETE from mytable';
$result = $conn->prepare($stmt);
$result->execute();
From experience and also having been told constantly the benefits of using prepared statements and binding my parameters, I have constantly used those two techniques in my code, however I would like to understand exactly the purpose of each of those two techiques:
From my understanding of prepared statements:
$sql = "SELECT * FROM myTable WHERE id = ".$id;
$stmt = $conn->prepare($sql);
$stmt->execute();
The previous code should create a sort of a buffer in the database with the query I proposed. Now FROM MY UNDERSTANDING (and I could be very wrong), the previous code is insecure, because the string $sql could be anything depending on what $id actually is, and if $id = 1; DROP TABLE myTable;--, I would be inserting a malicious query even though I have a prepared statement.
FROM MY UNDERSTANDING this is where binding my parameters com in. If I do the following instead:
$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->execute();
The database should know exactly all the parts of the sql statement before hand:
SELECT these columns: * FROM myTable and WHERE id = "a variable that was input by the user", and if "a variable that was input by the user" != a variable, the query fails.
I have been told by some my understanding is correct, and by others that it is false, could someone please let me know if I am wrong, correct, or missing something? And elaborate as much as you want, all feedback is greatly appreciated!
You're correct that the first case is insecure. It's important to understand though, that preparing a statement only has value if you are using variable data, and/or executing the same query repeatedly. If you are executing plain statements with no variables, you could simply do this:
$sql = "SELECT * from myTable WHERE this_column IS NOT NULL";
$result = $conn->query($sql);
And end up with a PDOStatement object to work with, just like when you use PDO::exec().
For your second case, again, you're largely correct. What's happening is the variable passed to the database is escaped and quoted (unless you specify otherwise with the third argument to PDOStatement::bindParam(), it's sent as a string which is fine for most cases.) So, the query won't "fail" if bad data is sent. It behaves exactly as if you had passed a valid number that didn't exist as an ID in the database. There are, of course, some edge cases where you are still vulnerable even with a correctly prepared statement.
Also, to make life easier, you can use prepared statements like this, to do implicit binding:
$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->execute([":id"=>$id]);
Or even like this, with un-named parameters:
$sql = "SELECT * FROM myTable WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->execute([$id]);
Naturally, most of this has been explained in the comments while I was typing up the answer!
I am starting a very basic site that uses a single line form to post into a database and then later echo that $comment variable on the page. I don't know PDO, but am willing to learn if I truly need it for something this simple.
else
mysql_query("INSERT INTO posts (postid, post_content)
VALUES ('', '$comment <br />')");
}
mysql_close($con);
Above this code I have basic strpos commands to block out some of the things I don't want posted.
Am I going to experience any issues with injections down the road from how I am doing this?
No, it's not safe, you need to use mysql_real_escape_string to escape $comment.
But, PDO is nothing difficult and make your code stronger.
// create the connection. something like mysql_connect/mysql_error
try {
$dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
// create the prepared statement.
$stmt = $dbh->prepare("INSERT INTO posts (postid, post_content) VALUES (?, ?)");
// execute it with parameters.
$stmt->execute(array('', $comment.'<br>'));
Yes this is dangerous. All someone has to do is put a single quote then the SQL code they want after. Use $comment = mysql_real_escape_string($comment) before this statement if you want to fix it the old way or use PDO prepared statements as the newer way. Here is a basic example from the documentation:
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
// insert another row with different values
$name = 'two';
$value = 2;
$stmt->execute();
?>
This is susceptible to sql injection as your $comment is input from the user they may as well enter some SQL command and your PHP code will end up executing the same.
Consider $comment value is set to 'TRUNCATE TABLE USERS;' the USERS table could be anything which might be critical for your app.
In PHP I believe you safeguard against sql injection by using mysql_real_escape_string(). Read up on it.
Refer this doc for details abt SQL innjection: https://docs.google.com/document/d/1rO_LCBKJY0puvRhPhAfTD2iNVPfR4e9KiKDpDE2enMI/edit?pli=1
Binding form input data to mysql query is the perfect solution to the sql injection. Use binaParam method for this purpose.
No, judging only by the code you’ve posted here, you are not protected against SQL injections. Here’s a simple example for $comment:
'), (null, (select concat(user(),':',password) s from mysql.user where concat(user,'#',host)=user() LIMIT 1) --
This will add another row containing the login credentials of the current user. With LOAD_FILE he could also be able to read files from your file system. He could also write arbitrary files on the file system:
' + (select '<?php echo "Hello, World!";' into dumpfile '/path/to/your/document_root/foobar.php')) --
With this technique the attacker could upload arbitrary files to your server, e. g. a web shell to run arbitrary commands on your system.
So you definitely must protect yourself against SQL injections whereby automatic escaping using prepared statements or parameterized statements is favored over manual escaping using functions like mysql_real_escape_string.
I am a newbie, just to be clear. I hear a lot about escaping data to prevent XSS attacks. How do I actually do that?
This is what I am doing currently -
$s = mysqli_real_escape_string($connect,$_POST['name']));
Is this enough? Thanks
If you output the data to html you should use htmlspecialchars()
else, if you're storing the data in a database you should escape strings using mysqli_real_escape_string() and cast numbers (or use prepared statements for both)
and protect identifiers/operators by whitelist-based filtering whem.
Both these methods are all you need if you use them the correct way.
You should use htmlspecialchars for output rather than mysqli_real_escape_string.
If you are just starting to fix your code against attacks (meaning SQL Injection attacks), you will be better of checking out parameterized queries. What you basically do with these is separate your content (input) from the commands (sql), so you can never have them confused by a possible mallicious user-entered piece of information like the name.
You can try starting with using the PDO class:
You can start reading the PDO manual here: http://php.net/manual/en/book.pdo.php and this page has a nice example: http://php.net/manual/en/pdo.prepared-statements.php
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
// insert one row
$name = 'one';
$value = 1;
$stmt->execute();
// insert another row with different values
$name = 'two';
$value = 2;
$stmt->execute();
?>
However, you don't need to use PDO, you can use mysqli also, see http://php.net/manual/en/mysqli.prepare.php
<?php
/* Script A -- We are already connected to the database */
$stmt = mysqli_prepare($link, "INSERT INTO table VALUES (?, ?, 100)"); /* Query 1 */
mysqli_stmt_bind_param($stmt, "si", $string, $integer);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt); // CLOSE $stmt
?>
Because the name is a separate value, it can never be an SQL command, so you will be safe automatically.