防止 SQL 注入 - PDO,mysqli [重复]

Posted

技术标签:

【中文标题】防止 SQL 注入 - PDO,mysqli [重复]【英文标题】:Secure against SQL Injection - PDO, mysqli [duplicate] 【发布时间】:2012-08-04 02:06:15 【问题描述】:

可能重复:Best way to prevent SQL Injection in php

我刚刚发现我的网站是易受攻击的。

因为它连接到数据库并具有以下功能:注册、更改密码、通知等......并且假设它完全易受攻击。

我应该在代码中寻找什么以开始使其安全?

我的意思是,我做了一些研究,但在任何地方,每个人对安全性的看法都不一样。

“使用 PDO。”

“使用 mysql_real_escape_string。”

“使用加斜线。”

我究竟应该寻找什么?

"$_POST" and "$_GET" variables??
"$_SESSION" variables?

SQL 查询?

$sql = "select * from user";
$sql = "update user set user="new_user_name";
$sql = "insert into user (user) values ('userid')";

在每种情况下我应该怎么做? 请帮助我知道我必须去什么和去哪里。

谢谢。

【问题讨论】:

在保护自己之前,您需要知道原因。试试bobby-tables.com(傻名字,严肃话题) 【参考方案1】:

以下是制作安全 php 应用程序需要考虑的要点。

    使用 PDO 或 mysqli 永远不要相信任何输入。考虑每个变量,即 $_POST、$_GET、$_COOKIE、$_SESSION、$_SERVER,就好像它们被污染了一样。对这些变量使用适当的过滤措施。 为避免 XSS 攻击,请使用 php 的内置函数 htmlentities, strip_tags 等,同时将用户输入数据插入 数据库。 在 PHP.INI 中禁用注册全局变量 在 PHP.INI 中禁用“allow_url_fopen” 不允许用户输入超出要求的数据。验证输入 允许最大字符数。同时验证每个字段 相关的数据类型。 在开发期后禁用错误报告。它可能会给 对黑客有用的数据库信息。 在发布表单时使用一次性令牌。如果令牌存在并且匹配 表单发布有效,否则无效。 使用参数化的数据库查询 使用存储过程

您可以通过谷歌搜索每个点以获取更多详细信息。 希望这会有所帮助

【讨论】:

#2 不应该相信任何输入,期间。完全有可能注入自己,而不会出现任何“用户”数据。 @MarcB,你就在那儿,伙计:) 你为什么不提mysqli_real_escape_string或提供任何链接? @ShaquinTrifonoff,我认为第 2 点可以解释。 当然! mysqli_real_escape_string 将是“适当的过滤措施”。 :-)【参考方案2】:

您应该查找的内容:任何从客户端/用户发送的数据。清理/转义这些数据。

PDO 可以清理查询(使用PDO::prepare)并支持多种 SQL 系统。

对于 MySQL,请使用 MySQLi。如果您使用的是 MySQL,mysqli_real_escape_string 是用于清理数据的函数。

【讨论】:

-1 建议 PDO 以某种方式自动清理查询。 糟糕...我应该说“PDO 可以清理数据库查询”。编辑了我的答案。感谢您提及@Vatev! 你的意思是'PDO自动转义参数字符串(但只有参数,而不是如果你在查询字符串中连接它们)'【参考方案3】:

您提供的所有 SQL 查询实际上都不会受到 SQL 注入的攻击。

SQL 注入漏洞的发生是因为 SQL 输入没有正确转义。

例如:

$sql = "select * from users where user_id ="  . $_GET['user_id'];

考虑我是否通过了以下内容:

http://some_server.com/some_page.php?user_id=123%20or%201=1

执行时的查询最终会是:

select * from users where user_id = 123 or 1=1

要解决此问题,请使用参数化查询:

$query = "select * from users where user_id = ?"

当您将 user_id 值绑定到查询时,数据访问层将正确转义输入字符串并执行以下操作:

select * from users where user_id = '123 or 1=1' which would not return any rows, preventing the injection

如果使用 PHP 和 mysql 扩展:

$sql = "select * from users where user_id = '" . mysql_real_escape_string($_GET['user_id']) . "'";

请记住,您需要转义进入 SQL 查询的所有输入:

$sql = "select id_column from some_table where id = 1";
$stmt = mysqli_query($conn, $sql);
if($stmt === false) die(mysqli_error($conn) . "\n");
while($row = mysqli_fetch_assoc($conn, $stmt) 
    $sql = "update some_other_table set some_value = 'new value' where some_column = '" . mysqli_real_escape_string($conn, $row['id_column']) . "'";
    ....

这是因为您从数据库中选择的值可能包含在 SQL 语句中执行时不安全的字符,例如名称“O'Hara”或示例。

【讨论】:

为简单起见,我使用了 mysql() 扩展。同样适用于 PDO 或 mysqli 扩展。如果使用 PDO,请确保您使用的是准备好的语句。 MySQLi 可以使用准备好的语句或 mysqli::real_escape_string。 你为什么不在你的例子中使用mysqli?从搜索中找到此内容的人可能会复制并粘贴代码。 我喜欢 mysql 扩展。我所有的代码仍然使用它,所以我很自然地使用它。在最近版本的 PHP mysql 中,mysqli 和 PDO 都使用了 mysqlnd 驱动,所以实际上不同的扩展没有区别。 不鼓励使用mysqli_* 函数。请参阅 this 和 mysql_query。请使用 MySQLi。 Here is an article on choosing an API. 如果你想使用 mysqli 使用 mysqli。仅仅因为 mysql 扩展是“不鼓励”(即弃用)并不意味着它不能作为一个简单的例子。如果您想更改扩展名,请随时编辑我的答案。【参考方案4】:

我一直在使用 PDO

你的例子:

<?php
   $stmt = $dbh->prepare("insert into user (user) values (?)");
   $stmt->bindParam(1, $name);
   $name = 'ValueHere';
   $stmt->execute();
?>

【讨论】:

以上是关于防止 SQL 注入 - PDO,mysqli [重复]的主要内容,如果未能解决你的问题,请参考以下文章

PDO(PHP Data Object),Mysqli,以及对sql注入等问题的解决

如果 PDO 和 mysqli 不可用,使用 mysql_* 函数是不是安全?

使用 MySQLi 时如何防止 SQL 注入? [复制]

PDO防止sql注入的机制

使用 MySQLi 时如何防止 SQL 注入

PDO防止sql注入的机制