2015-06-22 89 views
-2

我是PHP新手,希望有人能帮助我解决这个问题。PHP/MySQLi:如何防止INSERT上的SQL注入(代码部分工作)

我想使用PHP在MySQL数据库中存储两个值(电子邮件和密码)。输入通过jQuery中的Ajax传递给PHP页面(通过网站上的onclick事件)。

现在我想保护这个PHP查询免受SQL注入攻击 - 我正在谈论一个标准的网站,所以我不想过头,但我认为一些标准的保护措施不能坏。

以下是我之前所做的工作,只是为了确保一般程序正在运行。 然后我试图通过使用密码加密陈述来提高安全性,但我不确定是否以正确的方式做了这个+我不知道是否以及如何将这个需要应用到选择部分(以及我正在检查电子邮件是否已经存在)。

我已经看过很多关于这个主题的网页,但作为一个初学者,这正是我的问题。 有人可以用这个例子来说明什么应该改变或在这里添加,也许提供一些简短的解释?如果可能,我想继续使用MySQLi

以前的PHP:

$conn = new mysqli($servername, $username, $password, $dbname); 
$conn->set_charset("utf8"); 
if($conn->connect_error){ 
    die("Connection failed: " . $conn->connect_error); 
} 
$email = $_POST["email"]; 
$pw = $_POST["pw"]; 

$sql = "SELECT email FROM Users WHERE email = '" . $email . "'"; 
$query = $conn->query($sql); 
if(mysqli_num_rows($query) > 0){ 
    echo "Record already exists"; 
}else{ 
    $sql = "INSERT INTO Users (email, pw) VALUES ('" . $email . "', '" . $pw . "')"; 
    if($conn->query($sql)){ 
     echo "Update successful"; 
    }else{ 
     echo "Update failed"; 
    }; 
} 
$conn->close(); 

新PHP:

$conn = new mysqli($servername, $username, $password, $dbname); 
$conn->set_charset("utf8"); 
if($conn->connect_error){ 
    die("Connection failed: " . $conn->connect_error); 
} 
$email = $_POST["email"]; 
$pw = password_hash($_POST["pw"], PASSWORD_BCRYPT); 

$sql = "SELECT email FROM Users WHERE email = '" . $email . "'"; 
$query = $conn->query($sql); 
if(mysqli_num_rows($query) > 0){ 
    echo "Record already exists"; 
}else{ 
    $sql = $conn->prepare("INSERT INTO Users (email, pw) VALUES ('" . $email . "', '" . $pw . "')"); 
    $sql->bind_param('s', $name); 
    $sql->execute(); 
    $result = $sql->get_result(); 
    if($result){ 
     echo "Update successful"; 
    }else{ 
     echo "Update failed"; 
    }; 
} 
$conn->close(); 

更新:

从吉特伟大的答案和其他评论在这里后,我修改了我查询如下 - 有人可以让我知道,如果没有根据吉特的建议,现在是正确的吗?

$conn = new mysqli($servername, $username, $password, $dbname); 
$conn->set_charset("utf8"); 
if($conn->connect_error){ 
    die("Connection failed: " . $conn->connect_error); 
} 
$email = $_POST["email"]; 
$pw = password_hash($_POST["pw"], PASSWORD_BCRYPT); 

$stmt = $conn->prepare("SELECT email FROM Users WHERE email = ?"); 
$stmt->bind_param('s', $email); 
$stmt->execute(); 
$result = $stmt->get_result(); 
if(mysqli_num_rows($result) > 0){ 
    echo "Record already exists"; 
}else{ 
    $stmt = $conn->prepare("INSERT INTO Users (email, pw) VALUES (?, ?)"); 
    $stmt->bind_param('ss', $email, $pw); 
    $stmt->execute(); 
    $result = $stmt->get_result(); 
    if($result){ 
     echo "Update successful"; 
    }else{ 
     echo "Update failed"; 
    }; 
} 
$conn->close(); 

提前许多感谢, 麦克

+1

查看准备好的语句:MySQLI http://php.net/manual/en/mysqli.prepare.php/PDO http://php.net/manual/en/pdo.prepared-statements.php – RuubW

+0

谢谢你 - 我会看看。 – keewee279

+1

可能的重复[如何防止SQL注入在PHP?](http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php) –

回答

2

新的PHP代码片断,你仍然容易受到注射。
您在插入部分中使用了准备好的语句,但实际上并没有正确使用准备工作的优势。

当创建一个事先准备好的声明,您可以创建在其中添加而不是原始值的占位符的查询:

$stmt = $conn->prepare("INSERT INTO Users (email, pw) VALUES (?, ?)"); 

问号是占位符,并通过使用bind_param方法以后替换:

$stmt->bind_param('ss', $email, $pw); 

绑定调用的ss部分告诉它的两个字符串传递给数据库(为小号 MySQL数据库0,i for int等)。
您绑定了一个参数($name),但它没有占位符或查询中的任何类型的引用。

另一方面,您的选择语句仍然不安全并且易受攻击。
我可能会在那里使用准备好的语句,就像插入部分一样。

您总是希望确保来自用户的输入对于数据库是“安全的”,如果您连接查询字符串并将用户输入添加到数据库中,数据库将不会转义字符串,只会运行它。

当您自己编写完整查询时,只使用标准的query方法调用,而无需任何输入参数,尤其是用户通过的输入参数!

+0

非常感谢,并对迟到的回复感到抱歉。这真棒,这里的解释真的很有帮助!有一种方法可以在我完成上述操作后向您发送更新后的查询?只是想确保它没问题,因为这是我第一次写这样的东西。 – keewee279

+0

更新:我修改了试图实施建议的帖子中的查询。根据你的方法,你或其他人能否告诉我这是否正确? – keewee279

+1

看起来好多了。你可以改变你的'mysqli_num_rows($ result)'来使用OOP mysqli样式(你在其他所有代码中使用):'$ stmt-> num_rows'。你也可以在电子邮件中进行正则表达式检查来验证它(所以它实际上是一个电子邮件地址),但你现在应该工作(没有运行代码,所以可能有语法错误,我不能看到在代码片段,但总体思路是正确的,呵呵)。 – Jite

1
$query = $mysqli->prepare("INSERT INTO `table` (`col1`, `col2`) VALUES (?, ?)"); 
$col1 = 100; 
$col2 = 14; 
$query->bind_param('ii', $col1, $col2); 
$query->execute(); 
$query->close(); 
+0

非常感谢您的回复! – keewee279