防止 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注入等问题的解决