I have the following code that is presenting a 'word-of-the-day',
As I am relatively new to php coding, I wanted to make sure that there weren't any
security issues for how I am selecting from my database from the cookie value. Thanks.
if ($word_of_the_day) {
$wotd = $wpdb->get_results("SELECT term,definition FROM glossary WHERE term = '{$word_of_the_day}'");
foreach ($wotd as $term) { }
}
elseif ($_COOKIE['WOTD']) {
$word_of_the_day = htmlspecialchars(addslashes($_COOKIE['WOTD']));
$wotd = $wpdb->get_results("SELECT term,definition FROM glossary WHERE term = '{$word_of_the_day}'");
foreach ($wotd as $term) { }
}
else {
$wotd = $wpdb->get_results("SELECT term,definition FROM glossary ORDER BY RAND() LIMIT 1");
foreach ($wotd as $term) {
setcookie("WOTD", $term->term, time()+86400);
}
}
Well if $word_for_the_day comes from user input, there's your first problem. Do this before you use it:
$word_for_the_day = mysql_real_escape_string($word_for_the_day);
Your cookie actually looks OK. The htmlspecialchars() and addslashes() calls, in the context you're using them, don't appear vulnerable to SQL injection or XSS attacks.
You should check out mysql_real_escape_string: "Escapes special characters in a string for use in a SQL statement". You don't have to do the stuff that you're doing with htmlspecialchars and addslashes manually. Are you familiar with SQL injection security risks? If the variable that you're including in the SELECT statement, $word_of_the_day, comes from the user, then you have a potential SQL injection problem.
addslashes is extremely weak. First thing, run everything you query from the db through mysql_escape_string to prevent sql injection. That's just the basics.
if($word_of_the_day){
$word_of_the_day = mysql_escape_string($word_of_the_day);
$wotd = $wpdb->get_results ("SELECT term,definition FROM glossary WHERE term = '{$word_of_the_day}'");
Also, cookies in general aren't very secure no matter how secure code you write. For a much more secure solution, I recommend you use PHP sessions ($_SESSION). You can store variables in this superglobal variable and it will stay there between page loads.
http://www.php.net/manual/en/session.examples.basic.php
After that, you may want to protect against session hijacking or poisoning if you're really going for it
Another option you could consider would be to store the id of the word, instead of the word itself in the cookie. That way, it can only ever be an integer. Of course, using the word is fine too, as long as you mysql_real_escape_string it first, I just wanted to offer another option.
One of the safest ways is to use the PDO MySQL functions, which implements parameters:
$db = new PDO('mysql:host=hostname;dbname=defaultDbName', 'username', 'password');
$stmt = $db->prepare('SELECT term,definition FROM glossary WHERE term = :wotd');
if ($stmt) {
if ($stmt->execute(array(':wotd' => $word_of_the_day))) { //This is safe for any input method
$info = $stmt->fetchAll();
foreach($info as $row) {
//Whatever
}
}
}
The PDO drivers does the correct escaping / quoting according to the data type in the table.
Where does $word_of_the_day come from? If it comes from user input, you are open to SQL injection.
Related
This question already has an answer here:
How to prevent SQL Injection in Wordpress?
(1 answer)
Closed 6 years ago.
My website was recently got Hacked/Compromised. Via google I have learnt it is a victim of site injections. I believe I have cleaned and hopefully secured my website but I'm looking for ways to prevent it from ever happening again. I came across a code (see below) and wanted to know whether it will
1) work to prevent such attacks in the future? and
2) where should I add this code as my website is built in WordPress.
Any help or even better codes anyone can provide will be greatly appreciated, I'm new to programming.
Code:
<?php
if(isset($_REQUEST["id"])){
if(!is_int($_REQUEST["id"])){
//redirect this person back to homepage
} else {
$id_raw = trim(htmlentities($_REQUEST["id"]));
$id_secure = mysql_real_escape_string($id_raw);
$sql = "SELECT * FROM databasetable WHERE id='".$id_secure."'";
}
}
?>
PDO is an acronym for PHP Data Objects.
PDO is a lean, consistent way to access databases. This means developers can write portable code much easier. PDO is not an abstraction layer like PearDB. PDO is a more like a data access layer which uses a unified API (Application Programming Interface).
You basically have two options to achieve this:
Example:
$qry = $con->prepare('SELECT * FROM student WHERE name = :name');
$qry->execute(array('name' => $name));
foreach ($qry as $get) {
// do something with $get
}
Setting up database using PDO
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDBPDO";
A DSN is basically a string of options that tell PDO which driver to use, and the connection details... You can look up all the options here PDO MYSQL DSN.
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username,$password);
Note: If you get an error about character sets, make sure you add the charset parameter to the DSN. Adding the charset to the DSN is very important for security reasons, most examples you'll see around leave it out. MAKE SURE TO INCLUDE THE CHARSET!
You can also set some attributes after PDO construction with the setAttribute method:
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("SELECT id, firstname, lastname FROM MyGuests");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
foreach(new TableRows(new RecursiveArrayIterator($stmt->fetchAll())) as $k=>$v) {
echo $v;
}
The way injection type attacks work, is by somehow getting an interpreter (The database) to evaluate something, that should have been data, as if it was code. This is only possible if you mix code and data in the same medium (Eg. when you construct a query as a string).Parameterised queries work by sending the code and the data separately, so it would never be possible to find a hole in that.
SQL Injection is a type of vulnerability in applications that use an SQL database. The vulnerability arises when a user input is used in a SQL Statement.
$n = $_GET['user'];
$sql = "SELECT password FROM tbl_login WHERE name = '$n' ";
As you can see the value the user enters into the URL variable user will get assigned to the variable $n and then placed directly into the SQL statement. This means that is possible for the user to edit the SQL statement.
$name = "admin' OR 1=1 -- ";
$query = "SELECT password FROM tbl_login WHERE name = '$n' ";
The SQL database will then receive the SQL statement as the following:
SELECT password FROM tbl_login WHERE name = 'admin' OR 1=1 -- '
To prevent SQL injections we will have to use something called prepared statements which uses bound parameters. Prepared Statements do not combine variables with SQL strings, so it is not possible for an attacker to modify the SQL statement. Prepared Statements combine the variable with the compiled SQL statement, this means that the SQL and the variables are sent separately and the variables are just interpreted as strings, not part of the SQL statement.
Prepared Statements with mySQLi.
Using the methods in the steps below, you will not need to use any other SQL injection filtering techniques such as mysql_real_escape_string(). This is because with prepared statements it is not possible to do conventional SQL injection.
mySQLi SELECT Query.
$n = $_GET['user'];
// Prepare the statement
if ($sql = $mysqli->prepare("SELECT password FROM tbl_login WHERE name=?")) {
// Bind a variable to the parameter as a string.
$sql->bind_param("s", $n);
// Execute the statement.
$sql->execute();
// Get the variables from the query.
$sql->bind_result($pass);
// Fetch the data.
$sql->fetch();
// Close the prepared statement.
$sql->close();
}
You will need to understand this:
Nothing is 100% secure.
All you can do is increase your level of security, by
implementing different security measures like filtering user input
before querying databases, using prepared statements.
Using a secure connection for server interaction by encrypting
the data using SHA or MD5 or some other salt encryption.
Using captcha in your forms to filter out bot attacks.
As far as your above code is concerned :
it is just checking whether the request id is an integer or not.
It is filtering out the special characters and then running the
query.
I would like to suggest you to check the below link :
https://www.owasp.org/index.php/PHP_Top_5
It will give you an insight of how to implement security in an application.
Any way to prevent malicious sql statements without using prepared statements and parameterized queries?
Example after simplify:
<?php
$con = mysqli_connect($_POST['db_server'], $_POST['db_user'],
$_POST['db_password'], $_POST['db_database']) or die(mysql_error());
$result = mysqli_query($con, $_POST['query_message']);
?>
Is it possible to check out the parameter $_POST['query_message'] is safe or not?
You should always build your queries within your code and then sanitise any variables you're going to use within them. NEVER pass the query or the database connection variables in via $_POST unless your user is querying the database via that form, in which case I'd recommend you just install phpMyAdmin.
As for sanitising your variables, if you really don't want to use PDO's prepared statements, you can sanitise incoming integers as follows:
$id = (isset($_POST['id']) ? (int)$_POST['id'] : null);
if ($id) {
$sql = "SELECT *
FROM `table`
WHERE `id` = {$id}";
}
And for strings use this:
$username = (isset($_POST['username']) ? mysqli_real_escape_string($con, $_POST['username']) : null);
if ($username) {
$sql = "SELECT *
FROM `table`
WHERE `username` = {$username}";
}
You can also call real_escape_string() directly on your $con object as follows:
$username = (isset($_POST['username']) ? $con->real_escape_string($con, $_POST['username']) : null);
However, as with #Shankar-Damodaran above, I highly suggest you do use PDO prepared statements to query your database.
Why you don't wanna use Prepared Statements ? That is really weird. I strongly suggest you should go for it.
You could make use of mysqli::real_escape_string for escaping quotes that is commonly used for SQL Injection Attacks.
Something like...
OOP Style
$message = $mysqli->real_escape_string($_POST['query_message']);
Procedural Style
$message = mysqli_real_escape_string($link,$_POST['query_message']);
other way is using:
htmlentities($query);
as an extra you could use preg_match() regular expressions to avoid
the inclusion of certain words (SELECT, DROP, UNION .......)
Example:
try{
$query = sprintf("SELECT * FROM users WHERE id=%d", mysqli_real_escape_string($id));
$query = htmlentities($query);
mysqli_query($query);
}catch(Exception $e){
echo('Sorry, this is an exceptional case');
}
There are real world cases where prepared statements are not an option.
For a simple example, a web page page where you can do a search on any number of any columns in the database table. SAy that table has 20 searchable columns. you would need a huge case statement that has all 20 single column queries, all 19+18+17+16+15+14+13+... 2 column queries, all possible 3 column queries... that's a LOT of code. much less to dynamically construct the where clause. That's what the OP means by prepared statements being less flexible.
Simply put, there is no generic case. If there was, php would have it already.
real_escape_string can be beaten. a common trick is to % code the character you are trying to escape so real_escape_string doesn't see it. then it gets passed to mysql, and decoded there. So additional sanitizing is still required. and when all characters used in injection are valid data, it's a PITA, because you can't trust real_escape_string to do it.
If you are expecting an integer, it's super easy.
$sanitized=(int)$unsanitized;
done.
If you are expecting a small text string, simply truncating the string will do the trick. does't matter that it's not sanitized if there's not enough room to hold your exploit
But there is no one size fits all generic function that can sanitize arbitrary data against sql injection yet. If you write one, expect it to get put into php. :)
I'm creating a basic blog and I'm using the following code.
It's collecting the id (always a number) from the url and before I use, I wondered if anyone could check the security of the code and let me know if its ok?
I really don't want any injections, etc, and I want to keep it as much secured as possible.
<?php
if(is_numeric($_GET['id']) && $_GET['id'] > 0){
include("connectionfile.php");
$ia = intval($_GET['id']);
$ib = mysql_real_escape_string($ia);
$ic = strip_tags($ib);
$qProfile = "SELECT * FROM #### WHERE id='$ic' ";
$rsProfile = mysql_query($qProfile);
$row = mysql_fetch_array($rsProfile);
extract($row);
$title = trim($title);
$post = trim($post);
$date = trim($date);
mysql_close();
}else{
echo 'hack error here';
}
?>
$ia = intval($_GET['id']);
$ib = mysql_real_escape_string($ia);
$ic = strip_tags($ib);
strip_tags is useless, because it is only relevant in an HTML context. Any one of the other two methods would be sufficient to prevent SQL injection. Generally, just use the appropriate escaping mechanism for the language you're dealing with. In this case you're dealing with SQL, so mysql_real_escape_string alone is fine. See The Great Escapism (Or: What You Need To Know To Work With Text Within Text) for a step-by-step approach to escaping.
Better yet, learn PDO with prepared statements instead of the deprecated mysql_ functions, which solves the issue of SQL injection much better.
Don't use mysql_ functions. They are deprecated. Use mysqli or
PDO.
Use parameterized queries
Don't use "extract" as it pollutes the local scope. There are rare cases where it's safe, usually internal to an ORM, where it's
within the object. This is dangerous otherwise as all forms of
nasty variable names could be introduced, especially with successful
SQL injection.
Do exception handling so that database errors do not break the page entirely, and in the case of a bad query somehow forced via SQL Injection, nothing is displayed to indicate that the query was broken.
Even after you do all the above, still make sure you use htmlentities() or otherwise validate the data is what you expect before you display.
This code is a mess ;-)
if statement can be simplified "if (($id = (int)$_GET['id']) > 0) {"
if you acknowledge my 1. point, then $ia, $ib and $ic can be deleted
don't trim() database data! data should be trimed before INSERT into database.
read what #FilmJ has answered you
I saw several examples and people using this way to query the database in a login form.
I'm not fully sure is this is the best way to do a login form secure.
This is the query in PHP:
$query = "SELECT * FROM users WHERE usern = '".$_POST['username']."' AND passw = '".md5($_POST['password'])."'";
Is enough having md5() on the password post to avoid sql injection?.
I think that the md5 function will convert all characters and sql strings to a 32 char string.
Which other ways can I protect the login form?
mysql_real_escape_string($_POST['username']), etc.
Although it's better to use the mysqli extension and use prepared statements.
(Assuming you're using MySQL)
Edit: In response to the comment below, it might be good to use this for LIKE queries:
addcslashes(mysql_real_escape_string($_POST['username']), '%_')
You must sanitize your data before you let it near your database. The simplest way to do this is by using mysql_real_escape_string($_POST['username']) but this is only the very least you need to do.
If you're using a framework like CodeIgniter, you can use their in-build functionality which strips $_POST or $_GET inputs of any XSS risk. Otherwise, I'd recommend these posts:
What's the best method for sanitizing user input with PHP?
Clean & Safe string in PHP
You need to escape $_POST['username'] as well
and yes md5 will protect you from sql injection.
For this example, something like this would be ok
$query = "SELECT * FROM users WHERE MD5(usern) = '".md5($_POST['username'])."' AND passw = '".md5($_POST['password'])."'";
The way you have build your query easily allows to inject pieces of code in the username. You can use prepared statements to avoid that:
http://php.net/manual/en/pdo.prepared-statements.php
Prepared statements basically will describe how the statement will be structured, and adds the data afterwards. This way, the user can not alter the structure of the statement with the input data.
If you make a function which sanitizes all POSTS and GETS you are safe
function clean() {
foreach($_POST as $key => $val) {
$_POST[$key] = mysql_real_escape_string($val);
}
}
You can also use PDO and statements with variables, and PDO will clean automatically.
<?php
try {
$dbh = new PDO("mysql:host=$hostname;dbname=$db", $dbusername, $dbpassword);
$query = "SELECT * FROM users WHERE usern = ? AND passw = ?";
$sth=$dbh->prepare($sql);
$sth->execute(array($_POST['username'], md5($_POST['password']));
$result = $sth->fetch();
}
} catch(PDOException $e) {
echo $e->getMessage();
exit;
}
PDO is the Best way to stop SQL Injection in PHP
Just one simple solution use parameters for fields like username and password so that SQL command string is separably sent from the parameters and then attacker will only get blank responses.When parameters are used SQL command string is parsed and compiled separately from the parameters. Using prepared statements is the best solution.
I today i start to read different articles about SQLi and DoS/DdoS to know how to protect my site and i found this thing :
Link: link to the article
// DB connection
// $id = (int)$_GET['id'];
$id = $_GET['id'];
$result = mysql_query("SELECT id,name,pass FROM users WHERE id = $id")
or die("Error");
if($data = mysql_fetch_array($result))
$_SESSION['name'] = $data['name'];
if(preg_match('/(benchmark|sleep)/i', $id))
exit('attack'); // no timing
I want to know the use of this.Also after this the guy show how to bypass it and i want to know if PDO is secury?
if(preg_match('/(benchmark|sleep)/i', $id)) checks if the $id matches the strings benchmark or sleep (the i stands for case-insensitive).
In the context it's presented I'd say this makes no sense what so ever though... I'd rather do this, and be done with it:
$id = (int) $_GET['id'];
$result = mysql_query('SELECT id,name,pass FROM users WHERE id = '.$id);
Notice I cast the id to an int, so if it's anything else it should just end up being 0, which most likely doesn't match anything since id columns usually starts on 1 (from my experience anyways).
I want to know the use of this
That's quite silly and apparently useless attempt to detect a possible SQL injection which is supposed to run a resource-consuming query.
Also after this the guy show how to bypass it
No wonder.
Once you have a code open to injection, thaere are thousands methods to run it.
The only your concern should be injection in general.
Once you protected - no ddos injection would be possible.
i want to know if PDO is secury?
First, it is not PDO secure, but strict and constant use of prepared statements considered secure.
Second, nope, prepared statements helps only half the problem