I have a script where I submit some fields that get entered into a MySQL database when I submit it now it goes through successfully but never gets inserted into the database if one of the fields has an apostrophe. What can I modify to get this to work?
if ($_POST) {
$name = trim($_POST['your_name']);
$email = trim($_POST['your_email']);
$answers = $_POST['answers'];
$i = 0;
foreach ($answers as $a) {
if (trim($a))
$i++;
}
if ($name && $email && $i >= 40) {
$array = array();
$q = mysql_query("select * from fields");
while($f = mysql_fetch_array($q))
$array[$f['label']] = $answers[$f['ID']];
$array = serialize($array);
$time = time();
$ip = $_SERVER['REMOTE_ADDR'];
$token = md5($time);
$result = mysql_query("insert into data (submit_name, submit_email, submit_data, submit_confirm, submit_time, submit_ip, submit_token)
values ('$name', '$email', '$array', '0', '$time', '$ip', '$token')");
You need to escape characters with special meaning in MySQL in your data.
The quick and dirty way to improve your code would be to pass all your strings through mysql_real_escape_string before inserting them into your string of SQL.
The better approach would be to switch away from mysql_query to something that allows the use of bound parameters (preferably with prepared statements).
Use mysql_real_escape_string(), as this will both fix your apostrophe issue and at least partly help avoid SQL injection attacks. If you don't want to get your hands dirty with PHP's built-in PDO library, you might consider a Database Abstraction Layer (DBAL). ADODB is an example.
Related
I used Praneeth Madush Advanced-PHP-Login-System script in my projects. This script based on user class. This class contains four functions. This functions seams don't use MySQL Prepared Statements. This script appears to be a security risk. For example this is insert function:
public function insert($data){
if(!empty($data) && is_array($data)){
$columns = '';
$values = '';
$i = 0;
if(!array_key_exists('created',$data)){
$data['created'] = date("Y-m-d H:i:s");
}
if(!array_key_exists('modified',$data)){
$data['modified'] = date("Y-m-d H:i:s");
}
foreach($data as $key=>$val){
$pre = ($i > 0)?', ':'';
$columns .= $pre.$key;
$values .= $pre."'".$val."'";
$i++;
}
$query = "INSERT INTO ".$this->userTbl." (".$columns.") VALUES (".$values.")";
$insert = $this->db->query($query);
return $insert?$this->db->insert_id:false;
}else{
return false;
}
}
My question is this script secure? What are the bugs in this script?
Is it resistant to SQL injection attack?
Yes it is vulnerable to SQL injections, if user can input anything in $data and it isn't modified.
exemple:
//i guess 2 values :
$val[column1]="x',select password from mysql.user where user=’root’);--";
$val[column2]='doesntmatter';
//then:
$values="'x',select password from mysql.user where user=’root’);--,'doesntmatter'";
//then your query will be :
$query = "INSERT INTO ('column1','column2') `usertable` VALUES ('x',select password from mysql.user where user=’root’);--,'doesntmatter'
Here I just replaced column2 value by the user password of your database and I would have that nicly print on my user account of your site. But that's just one thing, if anything can be input everything can come out.
For bugs just run the thing and we might help you with errors.
This question already has answers here:
How to avoid code repetition with PHP SQL prepared statements?
(2 answers)
Closed 2 years ago.
I'm trying to make a database for users to publish scripts for a game. Every single time I've had an issue using query and got it working one way or another. This time, I decided to make it a little easier to format the string for the query. Its not working. Heres my code:
function getSQLOperation($Data){
$returning = "INSERT INTO `ScriptDatabase`";
$keys = "(";
$values = ") VALUES (";
foreach ($Data as $Key => $Value){
$keys = $keys."`".$Key."`, ";
$values = $values."'".$Value."',";
}
return $returning.$keys.$values.")";
}
$values = array();
$values['Visibility'] = "Public";
$values['Name'] = "NameOfScript";
$values['Publisher'] = "UserID";
$values['Genres'] = "";
$values['PublishDate'] = Date('m-d-Y');
$values['Updated'] = $values['PublishDate'];
$values['Version'] = "1.0";
$values['Description'] = "None for now";
$values['Likes'] = "0";
$values['Dislikes'] = "0";
$values['Downloads'] = "0";
$operation = getSQLOperation($values);
mySQL table structure:
Anything I'm doing wrong here?
MySQL doesn't allow trailing commas in queries, but your query is generated as:
INSERT INTO `foo`(`bar`, `baz`,) VALUES ('x','y',)
Of note, there are much better ways to work with MySQL. Check out PDO, especially prepared statements.
I mean it. Your query is vulnerable to SQL Injection attack and that's serious.
I'm trying to insert some values into a database, however, it's always unsuccessful and I'm not sure what the problem is. Could I get some assistance please
$query1 = "INSERT INTO `incidenceoffire`(`locationOfFire`, `dateFireOccurred`, `timeFireOccurred`, `classOfFire`, `originOfFire`, `noOfWounded`,
`noOfFatalities`,`occupancy`,`noOfFirePersonnelOnScene`,`noOfFireTrucks`,`backupUsed`)
VALUES('$locationoffire', '$datefireoccurred', '$timefireoccurred', '$classoffire', '$originoffire', '$occupancy', '$noofwounded', '$nooffatalities',
'$noofpersonnel', '$nooftrucks', '$backuptrucks')";
$incidenceoffire_id = mysql_insert_id();
$query2 = "INSERT INTO `backuptrucks` (`unitName`) VALUES ('$unitname')";
$query2 .=" WHERE `IncidenceOfFire_incidentID` = '".$incidenceoffire_id."'";
$result = false;
if(mysql_query('BEGIN')){
if(mysql_query($query1) && mysql_query($query2))
{
$result = mysql_query('COMMIT');
echo '<script type="text/javascript">
alert("Insert Successful!");
</script>';
}
else
{
mysql_query('ROLLBACK');
echo '<script type="text/javascript">
alert("Insert Unsuccessful!");
</script>';
}
}
For the purpose of clarity, here's what you need. I'm not going to optimize it or anything but it's a baseline for where you should start.
$mysqli = new mysqli('host', 'name', 'user', 'database');
$query1 = $mysqli->prepare('INSERT INTO
`incidenceoffire`(
`locationOfFire`,
`dateFireOccurred`,
`timeFireOccurred`,
`classOfFire`,
`originOfFire`,
`noOfWounded`,
`noOfFatalities`,
`occupancy`,
`noOfFirePersonnelOnScene`,
`noOfFireTrucks`,
`backupUsed`
)
VALUES(?,?,?,?,?,?,?,?,?,?,?));
In the above we're using mysqli's prepare. This function will allow us to safely escape the data that is being passed into the query. This is for security purposes. the ? represents the value that we're inserting associated with the field's we've identified above.
$query1->bind_param('sssssssssss',
$locationoffire,
$datefireoccurred,
$timefireoccurred,
$classoffire,
$originoffire,
$occupancy,
$noofwounded,
$nooffatalities,
$noofpersonnel,
$nooftrucks,
$backuptrucks);
Here, we've used bind_param to bind the variable to the ?'s that we've used in the prepared statement. This allows us to safely escape the data. the s in the first argument stands for string as the data we expect to receive from that variable should be a string. You can also use i for integer - when expecting only numbers, and d for double, if you expect to have .'s and ,'s. Lastly, you can use b if you expect a blob to be transferred over time to the statement.
Now, because you have two statements, repeat the above and use $query2, then you can perform your conditional. We will use execute() to execute the prepared statement we built earlier.
if($query1->execute() && $query2->execute()):
$result[] = $query1->commit();
$result[] = $query2->commit();
echo '<script type="text/javascript">alert("Insert Successful!");</script>';
else:
$result[] = $query1->rollback();
$result[] = $query2->rollback();
echo '<script type="text/javascript">alert("Insert Unsuccessful!");</script>';
endif;
This should all function for you from the get go, but please read and understand what's being relayed. Always use documentation and examples provided at http://php.net, and please follow best practices for security less you create a site that becomes hacked and I end up repairing it one day
I realize there are a lot of questions already about this. But my method isn't the same as theirs, so I wanted to know. I think I understand SQL, but I don't want to risk making a mistake in the future, so thanks for any help. (This is just a project I'm doing, not homework or anything important).
function checkLogin($username, $password) {
$username = strtolower($username);
connectToDatabase();
$result = mysql_query("SELECT * FROM `users` WHERE username='$username'");
$dbpassword = "";
while($row = mysql_fetch_array($result))
{
$rowuser = $row['username'];
if($username != $row['username']) continue;
$dbpassword = $row['password'];
}
if($dbpassword == "") {
return false;
}
$genpass = generatePassword($password);
return $genpass == $dbpassword;
}
So hit me with your best shot :)
And I don't think my method is as efficient as it could be. I don't understand php enough to understand what $row = mysql_fetch_array($result) is doing unfortunately.
Because you are taking an arbitrary string and placing it directly into an SQL statement, you are vulnerable to SQL injection.
( EDITED based on a comment below. )
The classic example of SQL injection is making a username such as the following:
Robert'); DROP TABLE users;--
Obligatory XKCD link
Explanation:
Given the "username" above, interpolation into your string results in:
SELECT * FROM `users` WHERE username='Robert'); DROP TABLE users;--'
The comment symbol -- at the end is required to "get rid" of your closing quote, because I just substituted one of mine to end your select statement so that I could inject a DROP TABLE statement.
As #sarnold pointed out, PHP's mysql_query only executes a the first query in the string, so the above example (known as query stacking) does not apply. The function is explained here: http://php.net/manual/en/function.mysql-query.php.
A better example can be found here. Here they use a username of
' OR 1 OR username = '
which interpolated becomes
SELECT * FROM `users` WHERE username='' OR 1 OR username = ''
and which would cause your application to retrieve all users.
The short answer is yes.
A perhaps more helpful answer is that you should never trust user input; prepared statements are the easiest way to protect against this, if you have PDO available. See PDO Prepared Statements
<?php
$stmt = $dbh->prepare("SELECT * FROM `users` WHERE username=?");
if ($stmt->execute($username)) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
?>
The other answers are an excellent description of your problem, however, I think they both overlook the best solution: use PHP's PDO Prepared Statements for your queries.
$stmt = $dbh->prepare("SELECT * FROM users where username = ?");
if ($stmt->execute(array($username))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
This is a small, simple example. There are more sophisticated ways of using PDO that might fit your application better.
When you use PDO prepared statements you never need to manually escape anything and so long as you use this slightly different style, you will never write an SQL injection vulnerability and you don't have to maintain two variables per underlying "data" -- one sanitized, one as the user supplied it -- because only one is ever required.
I would say yes it is open to SQL injection.
This is because you are taking user input in the form of $username and putting it into your SQL statement without making sure it is clean.
This is a function that I like to use in my applications for the purpose of cleaning strings:
function escape($data) {
$magicQuotes = get_magic_quotes_gpc();
if(function_exists('mysql_real_escape_string')) {
if($magicQuotes) {
$data = stripslashes($data);
}
$data = mysql_real_escape_string($data);
}
else {
if(!$magicQuotes) {
$data = addslashes($data);
}
}
return $data;
}
Then you can use it like this:
$username = escape(strtolower($username));
connectToDatabase();
$result = mysql_query("SELECT * FROM `users` WHERE username='$username'");
PHP controls that with get_magic_quotes_gpc();, however my question is: Is any SQL injection protection enabled by default when installing PHP > 5.xxxx?
I guess it is since I can't recall if I have enabled/disabled any options when dealing with this issue. On a side note, MySQL doesn't seem to be doing anything, since I tried to execute some simple SQL injection in ASP.net/C# with MySQL (community...5 something...) And it worked.
However when I tried the same in PHP - it was escaped with . Also, that was attempted on Windows 7.
Magic quotes is NOT a solution to prevent SQL Injection. It is by far insufficient to do proper character escaping. Just disable it and use prepared SQL statements with bound parameters. See example using PDO:
$pdo = new PDO("mysql:dbname=my_database", $dbUser, $dbPassword);
$sql = "SELECT * FROM users WHERE login = :login AND password = :password";
$stmt = $pdo->prepare($sql);
$stmt->bindValue("login", $_POST["login"]);
$stmt->bindValue("password", md5($_POST["password"]));
$stmt->execute();
$rows = $stmt->fetchAll();
Or be sure to properly escape the inserted values:
$pdo = new PDO("mysql:dbname=my_database", $dbUser, $dbPassword);
$sql = "SELECT * FROM users WHERE login = " . $pdo->quote($_POST["login"]) . " AND password = " . md5($_POST["password"]);
$rows = $pdo->query($sql)->fetchAll();
I recommend using http://php.net/manual/en/function.mysql-real-escape-string.php
I always use that whenever I get an input from a user.
SQL Injection can not be prevented by the PL or the Platform or even the Framework if the programmer doesn't keep it in mind,
There are two general programmatic methods of SQLi prevention :
escape all dynamic strings and then concat them to the query (a little unsafe)
use prepared statements to separate data from query
To use the former try :
$cond = mysql_real_escape_string($cond);
mysql_query("SELECT * FROM table WHERE {$cond}");
To use the latter, you could use PDO in PHP, which has prepared statements supported in.
What all the other answers didn't metion, mysql_real_escape_string WORKS ONLY FOR STRINGS.
I've seen something like this at least over 9000 times.
$id=mysql_real_escape_string($_GET['id']);
mysql_query("SELECT foo FROM bar WHERE foobar=$id");
Keep in mind, that you should explicit cast to an int in this case.
$id=(int)$_GET['id'];
Use a database class which does basic sanitation in case you forgot to do it e.g. mysql_real_escape_string.
I personally use something like this for text inputs (it is not recursive for arrays).
function escape($mixed){
if(is_array($mixed)){
foreach($mixed as $m => $value){
$mixed[$m] = mysql_real_escape_string(htmlspecialchars($value, ENT_QUOTES, "UTF-8"));
}
}else{
$mixed = mysql_real_escape_string(htmlspecialchars($mixed, ENT_QUOTES, "UTF-8"));
}
return $mixed;
}
But you should manually sanitize every input using preg_replace for example using this...
function replace($string, $type = "an", $custom = ""){
switch($type){
case "n": $regex = "0-9"; break;
case "a": $regex = "a-zA-Z"; break;
case "an": $regex = "a-zA-Z0-9"; break;
}
return preg_replace("#([^$regex$custom]+)#is", "", $string);
}
$_POST["phone"] = "+387 61 05 85 05";
$phone = replace($_POST["phone"], "n"); // 38761058505
There is no silver bullet for this.