PHP中如何防止SQL注入

4 篇文章 0 订阅
4 篇文章 0 订阅

这是StackOverFlow上一个投票非常多的提问 How to prevent SQL injection in PHP?   我把问题和赞同最多的答题翻译了下来。


提问如果用户的输入能直接插入到SQL语句中,那么这个应用就易收到SQL注入的攻击,举个例子:

$unsafe_variable = $_POST['user_input'];

mysqli_query("INSERT INTO table (column) VALUES ('" . $unsafe_variable . "')");

用户可以输入诸如 :  value'); DROP TABLE table;--   ,SQL语句就变成这样了:

INSERT INTO table (column) VALUES('value'); DROP TABLE table;--')
(译者注:这样做的结果就是把table表给删掉了) 我们可以做什么去阻止这种情况呢?


回答:

使用prepared statements预处理语句)和参数化的查询。这些SQL语句被发送到数据库服务器,它的参数全都会被单独解析。使用这种方式,攻击者想注入恶意的SQL是不可能的。


要实现这个主要有两种方式:

1. 使用 PDO

$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');

$stmt->execute(array(':name' => $name));

foreach ($stmt as $row) {
    // do something with $row
}

2. 使用 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
}

PDO

需要注意的是使用PDO去访问MySQL数据库时,真正的prepared statements默认情况下是不使用的。为了解决这个问题,你需要禁用模拟的prepared statements。下面是使用PDO创建一个连接的例子:

$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

上面的例子中,错误报告模式并不是强制和必须的,但建议你还是添加它。通过这种方式,脚本在出问题的时候不会被一个致命错误终止,而是抛出PDO Exceptions,这就给了开发者机会去捕获这个错误。


然而第一行的 setAttribute() 是强制性的,它使得PDO禁用模拟的prepared statements并使用真正的prepared statements。这可以确保这些语句和值在被发送到MySQL服务器之前不会被PHP解析(这使得攻击者没有注入恶意SQL的机会)。


尽管你可以使用可选的构造函数参数去设置 charset ,但重点需要注意的是小于5.3.6的PHP版本,DSN(Data Source Name)是默认忽略 charset 参数的。


说明

当你传一个SQL语句做预处理时会发生什么?它被数据库服务器解析和编译了。通过指定参数(通过之前例子中的 ? 或者像 :name 这样的命名式参数)你告诉数据库引擎你是想过滤它。接着当你调用 execute() 函数时,prepared statements会和你刚才指定的参数的值结合。


在此重要的是,参数的值是和编译过的语句结合,而非一个SQL字符串。SQL注入就是当创建被发送到数据库的SQL语句时,通过欺骗的手段让脚本去引入恶意的字符串。因此当你使用单独的参数发送真实正确的SQL时,你就限制了被某些不是你真实意图的事情而搞挂掉的风险。使用prepared statements 传递的任何参数都会被当做字符串对待(不过数据库引擎可能会做一些优化,这些参数最终也可能变成numbers)(译者注:意思就是把参数当做一个字符串而不会去做额外的行为)。比如在上面的例子中,如果 $name 变量的值是 'Sarah'; DELETE * FROM employees  ,产生的结果是会去搜索"'Sarah'; DELETE * FROM employees"这一整个字符串,最终的结果你也就不会面对的是一张空表了。


使用prepared statements的另一个好处是,如果你在同一session中再次执行相同的语句,也就不会被再次解析和编译,这样你就获得一些速度上的提升。


哦,既然你问的是插入操作该如果防止,下面给出一个例子(使用PDO):

$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');

$preparedStatement->execute(array(':column' => $unsafeValue));


翻译完, 本人翻译水平有限,请读者见谅。

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: PHP防止SQL注入的方法主要有以下几种: 1. 使用参数化查询或预处理语句 参数化查询或预处理语句可以帮助你在将数据插入到SQL语句之前,对数据进行格式化和转义。这种方法可以有效地防止SQL注入攻击。 2. 过滤用户输入 过滤用户输入是另一种常用的防止SQL注入攻击的方法。你可以使用PHP内置的函数(如strip_tags()、htmlentities()、addslashes()等)来过滤用户输入的特殊字符,从而减少SQL注入的风险。 3. 使用ORM框架 ORM框架可以自动将PHP对象转换为SQL语句,并在将数据插入到数据库之前对数据进行验证和转义,从而防止SQL注入攻击。 总之,在编写PHP代码时,务必要注意防止SQL注入攻击,遵循安全编码的最佳实践,以确保应用程序的安全性。 ### 回答2: 在PHP防止SQL注入可以采取以下几种方法: 1. 使用预处理语句:使用PDOPHP数据对象)或者MySQLi扩展的预处理语句可以有效防止SQL注入。预处理语句通过将参数传递给SQL查询,而不是将变量直接插入查询语句,从而避免了注入攻击的可能。例如: ```php $stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username"); $stmt->bindParam(':username', $username); $stmt->execute(); ``` 2. 使用参数化查询:对于直接执行的查询,可以使用参数化查询来防止注入。参数化查询,用户输入的数据会被视为参数,而不是直接拼接到查询语句。例如: ```php $sql = "SELECT * FROM users WHERE username = ?"; $stmt = $pdo->prepare($sql); $stmt->execute([$username]); ``` 3. 过滤和验证用户输入:对用户输入的数据进行严格的过滤和验证,只接受合法的输入,并拒绝含有特殊字符或SQL关键字的输入。 4. 使用PHP的内置函数进行转义:在将用户输入用于SQL查询之前,可以使用`mysqli_real_escape_string`函数或者`PDO::quote`方法对输入数据进行转义,从而确保输入数据的特殊字符不会被SQL解释器错误解读。 5. 限制数据库用户权限:为了减少潜在的攻击风险,可以为数据库用户分配最小权限,只授权其对数据库所需的表进行相应操作,避免了对整个数据库的访问。 综上所述,通过合理使用预处理语句、参数化查询、过滤和转义用户输入,以及限制数据库用户权限,可以有效地防止SQL注入攻击,并保护应用程序的安全性。 ### 回答3: PHP有很多方法可以防止SQL注入。 1. 使用预处理语句:使用预处理语句可以让数据库解析和编译SQL语句一次,然后在每次执行时只传递参数。这样可以避免将恶意SQL代码嵌入到参数。 2. 使用参数化查询:参数化查询将用户输入的值和SQL查询语句分离,这样可以确保用户输入的数据被视为数据而不是SQL代码。 3. 过滤输入:对于从用户输入获取的数据,可以使用内置的函数(如`filter_input()`或`filter_var()`)进行过滤和验证,以确保输入数据的安全性。 4. 对特殊字符进行转义:使用`mysqli_real_escape_string()`或`PDO::quote()`函数可以对特殊字符进行转义,以防止其被解释为SQL代码。 5. 合理设置数据库用户权限:确保数据库用户只有最低权限,只能访问需要的数据库和表,以减少数据库被注入的风险。 6. 使用安全的数据库连接:使用高级的数据库连接方式(如使用PDO和绑定参数)可以提高数据库连接的安全性。 7. 更新和维护框架和库:及时更新和维护PHP框架和第三方库,以获得最新的安全修复和补丁。 8. 错误处理:在生产环境,应该禁用错误和警告信息的显示,以防止暴露敏感信息。 总之,通过使用预处理语句、参数化查询、过滤输入、转义特殊字符等方法,结合合理的用户权限设置和安全的数据库连接,可以有效地防止SQL注入攻击。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值