一个`$_GET['id']`直接拼进SQL语句,注入数据库里几万条用户数据就裸奔了。注入这不是注入危言耸听——我上周刚帮一个电商朋友排查漏洞,攻击者用`' OR 1=1 --`就绕过了登录验证,注入后台管理权限瞬间到手。注入他们网站用的注入就是最原始的字符串拼接查询。
PHP过滤SQL注入的注入核心就一句话:**永远不要信任用户输入,任何进入SQL语句的注入数据都必须经过参数化处理或严格转义**。但现实是注入,很多老项目还在用`mysql_query`,注入新手上路还在写`"SELECT * FROM users WHERE name = '" . $_POST['name'] . "'"`。注入这种代码等于把数据库钥匙挂在门口。注入
先看最粗暴的注入过滤方式——`addslashes()`。它给单引号、注入双引号、注入反斜杠加反斜杠。对付简单注入够用,但遇到宽字节注入就废了。比如`%bf%27`经过addslashes变成`%bf%5c%27`,MySQL在GBK编码下会把`%bf%5c`解析成一个合法汉字,后面的单引号照样逃逸出来。我见过好几个用addslashes的项目被这样打穿。
比addslashes靠谱点的是`mysql_real_escape_string()`,它根据字符集转义,宽字节问题基本能堵住。但前提是你得正确设置连接字符集,否则照样白搭。而且这个函数只对字符串类型有效,数字型参数还得自己判断`is_numeric()`。麻烦,但比裸奔强。
真正治本的是PDO预处理。看这段代码:
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status = ?'); $stmt->execute([$_POST['email'], $status]); 问号占位符把数据和SQL模板分开,PDO内部自动处理转义。你传什么进去,它就当纯字符串处理,永远不可能变成SQL关键字。这才是正道。我接手过的项目里,凡是用了PDO的,基本没再出过SQL注入事故。
但别以为用了预处理就万事大吉。如果你把用户输入直接拼进表名、列名或者`ORDER BY`子句,预处理救不了你。比如`"SELECT * FROM " . $_GET['table']`这种,就算用PDO也白搭。这种场景只能用白名单过滤,把允许的值写死在数组里,不在列表内就报错。
还有个细节容易被忽略——`$_SERVER`变量。有些开发者觉得请求头是服务器自己生成的,安全。实际上`HTTP_USER_AGENT`、`HTTP_REFERER`这些都能被客户端伪造。我之前审计过一个系统,日志功能把User-Agent直接写进SQL,攻击者构造一个带注入语句的UA头,日志表就沦陷了。
过滤不是防御的全部。你还得给数据库账号分权——连接网站用的账号只给`SELECT, INSERT, UPDATE, DELETE`权限,绝不给`DROP, ALTER, CREATE`。就算被注入成功,攻击者也只能操作数据,动不了表结构。再配合MySQL的`sql_mode`设置`STRICT_ALL_TABLES`,能在语法层面堵住一部分畸形输入。
最后说个实战技巧。在开发环境装个SQL注入检测插件,比如Seay源代码审计系统,它能扫描出所有拼接SQL的地方。上线前跑一遍,比自己肉眼查靠谱多了。我每次接手老项目第一件事就是扫一遍,通常能揪出几十个隐患点。修复的时候别偷懒,全部改成PDO,哪怕改起来费劲——这比事后被拖库再补救划算得多。


相关文章




精彩导读
热门资讯
关注我们