如果插入用户输入而不修改SQL查询,则应用程序容易受到SQL注入的攻击,如下例所示:
$unsafe_variable = $_POST['user_input'];
mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
Run Code Online (Sandbox Code Playgroud)
这是因为用户可以输入类似的内容value'); DROP TABLE table;--,查询变为:
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
Run Code Online (Sandbox Code Playgroud)
可以采取哪些措施来防止这种情况发生?
为什么一个人不应该使用mysql_*功能的技术原因是什么?(例如mysql_query(),mysql_connect()或mysql_real_escape_string())?
即使他们在我的网站上工作,为什么还要使用其他东西?
如果他们不在我的网站上工作,为什么我会收到错误
警告:mysql_connect():没有这样的文件或目录
即使使用mysql_real_escape_string()函数,是否存在SQL注入的可能性?
考虑这个示例情况.SQL是用PHP构造的,如下所示:
$login = mysql_real_escape_string(GetFromPost('login'));
$password = mysql_real_escape_string(GetFromPost('password'));
$sql = "SELECT * FROM table WHERE login='$login' AND password='$password'";
Run Code Online (Sandbox Code Playgroud)
我听过很多人对我说,这样的代码仍然很危险,即使使用了mysql_real_escape_string()函数也可以破解.但我想不出任何可能的漏洞?
像这样的经典注射:
aaa' OR 1=1 --
Run Code Online (Sandbox Code Playgroud)
不工作.
你知道任何可能通过上面的PHP代码注入的注入吗?
他们都做同样的事情,只是区别对待吗?
除了使用prepare之间有什么区别
$sth = $db->query("SELECT * FROM table");
$result = $sth->fetchAll();
Run Code Online (Sandbox Code Playgroud)
和
$sth = $db->prepare("SELECT * FROM table");
$sth->execute();
$result = $sth->fetchAll();
Run Code Online (Sandbox Code Playgroud)
?
迁移远离mysql库后我正在使用PDO.我用什么代替旧mysql功能?
我需要转义单引号,以便它们进入我的数据库,我认为可能有更好的方法来处理这个,而不添加(斜)所有字符串的斜杠.有人可以告诉我应该使用的是什么吗?
如果是,为什么还有那么多成功的SQL注入?仅仅因为一些开发人员太愚蠢而无法使用参数化语句?
我使用修改我的代码mysql_*来PDO.在我的代码中我有mysql_real_escape_string().在PDO中,这相当于什么?
我正在重新设计一个使用最小数据库的PHP驱动的网站.原始版本使用"伪准备语句"(PHP函数进行引用和参数替换)来防止注入攻击并将数据库逻辑与页面逻辑分开.
用一个使用PDO和真实预处理语句的对象替换这些ad-hoc函数似乎很自然,但在阅读它们之后,我不太确定.PDO似乎仍然是一个好主意,但准备好的声明的主要卖点之一是能够重用它们......我永远不会.这是我的设置:
SELECT foo,bar FROM baz WHERE quux = ? ORDER BY bar LIMIT 1.该批次中最复杂的陈述只是三个这样的选择与UNION ALLs 连接在一起.鉴于使用准备好的语句至少会使我正在进行的数据库往返次数增加一倍,我最好避免使用它们吗?我是否可以使用PDO::MYSQL_ATTR_DIRECT_QUERY以避免多个数据库跳闸的开销,同时保留参数化和注入防御的好处?或者,与执行我不应该担心的非准备查询相比,准备好的语句API使用的二进制调用是否运行良好?
编辑:
伙计们,感谢所有好的建议.这是我希望我可以将多个答案标记为"已接受"的地方 - 许多不同的观点.不过,最终,我必须给rick他应得的......如果没有他的答案,我会幸福地离开并完成错误的事情,即使遵循了所有人的建议.:-)
仿真准备好的陈述吧!
我正在尝试为我的数据库实现一个非常基本的搜索引擎,其中用户可能包含不同类型的信息.搜索本身由几个联合选择组成,其中结果总是合并为3列.
然而,返回的数据是从不同的表中获取的.
每个查询使用$ term进行匹配,我将它作为准备参数绑定到":term".
现在,手册说:
调用PDOStatement :: execute()时,必须为要传递给语句的每个值包含唯一的参数标记.您不能在预准备语句中两次使用同名的命名参数标记.
我想,不是用termex替换每个:term参数:termX(x为term = n ++),必须有一个更好的解决方案吗?
或者我只需绑定X号:termX?
编辑发布我的解决方案:
$query = "SELECT ... FROM table WHERE name LIKE :term OR number LIKE :term";
$term = "hello world";
$termX = 0;
$query = preg_replace_callback("/\:term/", function ($matches) use (&$termX) { $termX++; return $matches[0] . ($termX - 1); }, $query);
$pdo->prepare($query);
for ($i = 0; $i < $termX; $i++)
$pdo->bindValue(":term$i", "%$term%", PDO::PARAM_STR);
Run Code Online (Sandbox Code Playgroud)
好的,这是一个样本.我没有时间使用sqlfiddle,但如果有必要,我会稍后添加一个.
(
SELECT
t1.`name` AS resultText
FROM table1 AS t1
WHERE
t1.parent = :userID
AND …Run Code Online (Sandbox Code Playgroud) 构建我的第一个Web应用程序并希望更好地理解SQL注入(https://github.com/astaxie/build-web-application-with-golang/blob/master/en/eBook/09.4.md).
我总是使用'database/sql'库并使用'?'构建查询,从而获得多少SQL注入保护?而不是连接字符串?在这种情况下,我仍然需要担心什么样的SQL注入攻击?