预编译语句防住了注入吗?为什么还是被攻击了?
我用PHP开发用户登录功能时,明明用了预编译语句,但测试时发现输入' OR 1=1 --还是能绕过验证,这是为什么?
代码是这样的:
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = '$_POST['username']' AND password = ?");
$stmt->bind_param("s", $password);
$stmt->execute();
我按教程设置了参数化查询,但测试时发现只要在用户名里输入恶意字符,查询就会报错。错误信息显示: Unknown column '1'' OR 1=1 --' in 'where clause'。明明用了预编译为什么还会被攻击?是不是参数绑定的位置有问题?
?占位符生效,你把用户名直接拼进 SQL 里了,等于留了个后门。你看这行:
username是直接插进去的,恶意输入' OR 1=1 --就会变成:这语法都乱了,当然报错说列不存在。关键是——你压根没给 username 做参数绑定。
正确做法是:两个参数都用占位符。
直接用这个改法:
记住一句话:只要有一个地方拼接 SQL,整个查询就不安全。别只绑一个参数就以为万事大吉。
username部分根本没有用参数绑定,直接拼接了$_POST['username'],这就是典型的 SQL 注入漏洞。预编译只对用了bind_param的部分有效,你得把用户名也改成参数绑定。修复代码如下:
检查一下所有动态输入的地方,确保全都用参数化查询,不要再手动拼接 SQL 了。