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.
Related
I have some form data that I'm writing to a database with PDO prepared statements.
This form data is santized and validated on the on the way in to the database with filter_var() functions and regular expressions and when any of this data is outputted to the site it escaped with htmlspecialchars().
To prevent SQL injections I'm using I'm using the code below. When I first learnt PDO this was what I saw in the tutorial and I personally find it very easy to read/understand.
I've noticed on the php.net site and in some other code I've saw recently they used bindparams(), whereas in the code below I've always done this inside an array in the execute() method.
Is my code below secure? Or must I use bindparams in the way that is shown in the second code example?
Here is some sample code using a firstname input from a webform
<?php
$firstname = $_POST['firstname'];
$firstname = filter_var($fname, FILTER_SANITIZE_STRING);
if(empty(trim($fname))){
$error[] = "First Name cannot be blank";
}
$sql = "INSERT INTO users (firstname) VALUES (:firstname)";
$stmt = $connection->prepare($sql);
$stmt->execute([
':firstname' => $firstname,
]);
In the php.net docs it does the above prepared statement using bindParam(), which seems a little verbose if you are updating a number of fields?
<?php
$sql = "INSERT INTO users (firstname) VALUES (:firstname)";
$stmt = $connection->prepare($sql);
$stmt->bindParam(':firstname', $firstname);
$stmt->bindParam(':lastname', $lastname);
$stmt->execute();
If it is more secure then I'll obviously have to do it the second way, but wanted to check if my prepared statements given in the first code block are secure ?
It's fine either way. The security benefit is from using placeholders at all. There are some cases (dynamically constructed queries) where it's beneficial to use bindParam separately from the execute call, and there are others where you would prefer to avoid the verbosity. Use what suits you.
I am started to learn coding start with HTML, CSS, and php. I created a basic form to test my skill. However, I got stuck with this. Can you help me on that?
I know that it is open to SQL injections, I am just trying to improve myself in coding and will use prepared statements and parameterized queries in real life.
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$mysql_host = "";
$mysql_username = "";
$mysql_password = "";
$mysql_database = "";
$conn = new mysqli ($mysql_host, $mysql_username, $mysql_password, $mysql_database);
$c_name = $_POST["club_name"];
$c_league = $_POST["league"];
$c_rank = $_POST["ranking"];
$c_prank = $_POST["previous_rank"];
$sql = "INSERT INTO `club_data` (`club_name`, `league`, `ranking`, `previous_rank`)
VALUES ('$c_name', '$c_league, $c_rank, $c_prank);";
mysqli_query($conn, $sql);
if ($conn->query($sql) === TRUE) {
echo "kayit islendi";
}
else {
echo "Error". $sql ."<br>". $conn->error;
}
$conn->close();
}
?>
Everytime I used the form I got this error.
ErrorINSERT INTO... etc.
You are missing quotes around your insert values, here's the fixed sql:
$sql = "INSERT INTO `club_data` (`club_name`, `league`, `ranking`, `previous_rank`)
VALUES ('$c_name', '$c_league', '$c_rank', '$c_prank');"
You were missing quotes around each value!
HOWEVER, this is an ill advised way of making database queries in production. Either use mysqli_real_escape_string to sanitize your strings(each of your variables will need this treatment) or use prepared statements.
Alternatively, and the way you should always use your DB is via the PDO wrapper. In this case you would use: PDO::quote. PDO offers a unified interface to the most popular databases there are. Here you can read more about PDO: http://php.net/manual/en/book.pdo.php
Coders prefer prepared statements to sanitizing their input. However this incurs extra communication with the mysql server vs writing a bit more code in php. Prepared statements are more involved then normal queries as they are cached on the SQL server and preprocessed waiting for data to be used, also having a miriad of question marks makes the code very hard to read especially if you start working in production and have a miriad of columns to fill. Here you can read more about the prepared statements:
https://dev.mysql.com/doc/refman/5.7/en/sql-syntax-prepared-statements.html
Main takeaway:
never, EVER, EVER save unsanitized data to the DB!!Use mysqli_real_escape_string or PDO::quote or prepared statements, depending on situation.
use prepared statements for what they have been created for not just as a wholesale sanitizer tool, use them when you have to execute the same query repeatedly. Especially if this query is not an insert in which case I suggest you do mass insert like so:INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9); read more here: https://dev.mysql.com/doc/refman/5.7/en/insert.html This has a caveat in that the maximum size of the sql with inserted values should never be larger then max_allowed_packet config.
You should use prepared statements. Not only does it prevent SQL injection attacks, it also avoids the pesky quoting issues you are currently facing
$sql = "INSERT INTO `club_data` (`club_name`, `league`, `ranking`, `previous_rank`)
VALUES (?, ?, ?, ?);";
$result = $conn->prepare($sql);
$result->bind_param('ssss', $c_name, $c_league, $c_rank, $c_prank);
echo $result->execute() === true ? 'kayit islendi' : 'Error'.$conn->error;
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 8 years ago.
I need some help and very very fast because my database was injected. I need at least a script that won't allow users to use :[Spaces, Sybols like ('*','=','/','.') and a list of words ('SELECT','FROM','WHERE')] in the text fields of my register form.
I heared something about mysql_real_escape_string(). What is this command doing? And don't post links to PHP: mysql_real_escape_string() Manual because I already read that.
There'a a right and a wrong way to approach this. The (usually) wrong way is to try and set up an input sanitation method (like a script) and hope that nothing gets through. It usually doesn't work.
What I recommend you to do is rewrite your PHP SQL queries to use MySQLi prepared statements. These are queries that are first converted from the common SQL syntax ("SELECT... WHERE...") to a statement your engine can work with, and only then are the fields replaced with your input, thus preventing SQL injection.
For example, the (very) susceptible SQL syntax:
"SELECT * FROM users_passwords WHERE user='" + user + "' AND pass='" + password + "'"
Can be converted to the following prepared statement:
"SELECT * FROM users_passwords WHERE user=? AND password=?"
And then, using the command bind_param(), you can safely replace the ? placeholders with your parameters after the statement is prepared. While the original SQL query allows you to use some basic injection techniques (like writing ' OR true OR '), prepared statements will not allow this.
Here's a working example:
// Create a new MySQLi connection object
$db = new mysqli('localhost','db_username','db_password','db_name');
// Create a new prepared statement
$stmt = $db->prepare('SELECT * FROM users_passwords WHERE user=? AND pass=?');
// Bind the parameters, in order, to the statement (s stands for string)
$stmt->bind_param('ss', username, password);
// Self-explanatory
$stmt->execute();
If you are in PHP then why don't you do it in your PHP script. sanitize all your user provided input in GET and POST and then move it forward to DB calls. That is the right way to do it.
I would strongly avoid constructing SQL query strings from any input even if you sanitize it.
The good way for security purposes and performance is to use functions to set the parameters:
for example:
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
see http://php.net/manual/en/pdo.prepared-statements.php
Ive read alot of different ideas lately on how to do this. Im running php 5.5 and mysql 5.6, and Im using PDO prepared statements.
PDO is supposed to not require sanitation beforehand, so why do I see so many references to filter_input and filter_var?
Is FIEO relevant with PDO? Below is a simple example of a query and echo. How should i ultimately set it up differently?
$name = "John";
$query = $db->prepare("SELECT `name` FROM `users` WHERE `name`=?");
$query->bindValue(1, $name);
try{
$query->execute();
$row = $query->fetch();
} catch(PDOException $e){
die($e->getMessage());
}
echo "Name is " . $row['name'] . ".";
Im looking forward to finally understanding proper coding for security.
filter_var isn't just for sanitizing input; there are also validation filters that can be used for type checking (http://www.php.net/manual/en/filter.filters.validate.php) and as processing instructions (http://www.php.net/manual/en/filter.filters.flags.php).
On a tangential note:
There's also the whole concept of using the stored data; just because you may be more or less safe against SQL injection doesn't mean your data can then be consumed safely. You still have to make sure your data doesn't contain malicious content (like, for instance, checking for encoded text that renders out as executable JavaScript when accepting HTML content from a user).
If you want to see some examples of things to watch out for in the example I mention above, I found the test suite for the HtmlSanitizer library very interesting: https://github.com/mganss/HtmlSanitizer/blob/master/HtmlSanitizer.Tests/Tests.cs
Variables passed as arguments to prepared statements will automatically be escaped by the underlying driver which helps to prevent SQL injection.
Although Prepared Statements helps in defending against SQL Injection, there are possibilities of SQL Injection attacks through inappropriate usage of Prepared Statements
String strUserName = //retrieved from webpage via text field
$query = $db->prepare("SELECT `name` FROM `users` WHERE `name`=strUserName ");
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.