登录框输个单引号,网站就崩了?
老张做公司官网维护快三年了,有天下午突然收到客户投诉:网站一打开全是乱码,后台进不去。他赶紧远程连接服务器,发现数据库里多了几百条奇怪记录,用户表里甚至出现用户名为 'admin' OR '1'='1 的账号。这不是普通故障,是被人用 SQL 注入攻进来了。
这类攻击其实很常见。比如你在网页登录框输入用户名 admin,密码处填 ' OR 1=1--,有些没做防护的系统就会误判为“条件恒成立”,直接让你绕过验证进后台。这种操作成本极低,但破坏力极强。
SQL注入是怎么发生的
问题出在动态拼接 SQL 语句上。假设后端代码这么写:
String sql = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'";当攻击者输入恶意字符串时,原本的查询逻辑就被改写了。像 ' OR 1=1-- 这种 payload,会让语句变成:
SELECT * FROM users WHERE username='admin' AND password='' OR 1=1--'-- 是注释符,后面的内容被忽略,而 OR 1=1 让条件永远成立,结果就是返回所有用户数据。
防火墙不是摆设,关键看怎么用
很多人以为装了防火墙就万事大吉,其实传统网络层防火墙对这种应用层攻击基本无效。真正起作用的是 WAF(Web 应用防火墙)。它能识别常见的 SQL 注入特征,比如语句中的 UNION SELECT、LOAD_FILE、OR 1=1 等关键词组合。
举个例子,某电商站点在 WAF 规则里设置了拦截包含 ' OR ' 的请求。当有人尝试用密码 ' OR 'a'='a 提交登录时,请求还没到服务器就被拦下,返回 403 错误。这时候日志里会留下痕迹,管理员可以及时响应。
但也不能全依赖 WAF。有些绕过手段,比如用编码变形(%27%20OR%20%271%27%3D%271)或者拆分关键字,就能躲过简单规则。所以得配合其他措施一起上。
别让漏洞从代码里长出来
最根本的解决办法还是改代码。用参数化查询(Prepared Statement)几乎能杜绝这类问题。比如 Java 里的 PreparedStatement:
String sql = "SELECT * FROM users WHERE username=? AND password=?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);这时候不管用户输入什么,都会被当成纯数据处理,不会参与 SQL 语义解析。MySQL、PostgreSQL 都支持这种模式,PHP 用 PDO 也能实现类似效果。
另外,数据库权限也要收紧。别让 Web 应用用 root 账号连库,专门建个只读或最小权限账号,就算被注入,对方也删不了表、拿不到系统文件。
日常排查该看哪些地方
如果你负责维护一个老系统,不确定有没有风险,可以从几个点下手:看看最近的访问日志里有没有大量 404 后面跟着 .sql 或 /phpmyadmin 的路径;检查数据库慢查询日志,是否出现异常复杂的 SELECT 语句;还有就是手动测试,在输入框里敲个单引号提交,如果页面报错信息里露出 MySQL 或 SQL Server 字样,那基本就是裸奔状态。
还有一种隐蔽情况:搜索功能。比如商品搜索框,输入 ' AND SLEEP(5)--,如果页面卡五秒才响应,说明数据库执行了延时命令,这已经是盲注攻击的典型迹象。
发现问题后别慌,先临时在 Nginx 或 Apache 上加个过滤规则,把可疑字符挡住,再安排开发修代码。安全这事,早一步动手,少一分损失。