一个登录框,入渗一个输入框,透测一个密码框,入渗再加一个“登录”按钮。透测这是入渗SQL注入最经典的舞台。攻击者不需要什么高深工具,透测在用户名框里敲下' or 入渗1=1 --,就能让后台SQL语句变成永远为真的透测查询,直接绕过身份验证。入渗我第一次在靶场复现这个操作时,透测后背发凉——原来所谓的入渗安全边界,薄得像一层窗户纸。透测
SQL注入的入渗本质,是透测把用户输入拼进SQL语句,却被数据库当成了代码执行。入渗问题不在数据库,也不在SQL语言,而在开发者写代码时的那一份“信任”。你看,很多漏洞不是技术多复杂,而是人太习惯走捷径。字符串拼接是最省事的写法,参数化查询要额外写几行代码,于是有人就偷懒了。这种偷懒,在2023年的全球漏洞报告中依然高居OWASP Top 10前三名。
实际操作中,渗透测试员第一步是“探针”。随便输入一个单引号,看页面报错是否暴露SQL语句片段。有些系统直接把错误堆栈甩到前端,像喝醉的人把家门钥匙放在门口垫子下。报错信息里藏着数据库类型、表名、甚至字段名——这些信息对攻击者来说,就是一张精确到门牌号的地图。
探到注入点后,第二步是判断注入类型。数字型、字符型、还是搜索型?每种类型的闭合方式不一样。比如字符型注入,你得先猜后台SQL是怎么拼接的:是WHERE id='$input'还是WHERE name="$input"?这活儿跟开锁有点像,得试不同的钥匙坯子。有些测试员喜欢用ORDER BY逐列试探字段数量,或者用UNION SELECT把数据“借”出来。后者更狠,直接把自己想要的数据拼进结果集,让页面替你打印数据库内容。
盲注是另一片战场。页面不报错,不回显数据,一切像死水一样平静。但你可以让数据库当你的“哑巴信使”:输入if(1=1,sleep(5),0),看响应时间是否延迟5秒。时间盲注就是这么磨人,一个字符一个字符地猜,像在黑暗里摸钥匙串。我见过一个老手,用二分法加时间盲注,硬是从一个没有回显的登录接口里,把管理员密码的哈希值一个字节一个字节抠了出来,花了七个小时。这活儿考验耐心,更考验对数据库函数特性的熟悉程度。
防御方也不是吃素的。参数化查询(PreparedStatement)是首选,它把数据和代码彻底分离,让用户输入永远只是“数据”。其次是输入验证,白名单比黑名单靠谱得多——黑名单总有漏网之鱼,比如用/**/代替空格,或者用十六进制编码绕过关键字过滤。再往深一层,数据库账号权限要最小化,连接应用的那个账号不该有DROP权限,更不该是sa或root。有些公司把数据库备份放在同一台服务器上,等于把备用轮胎也扎了洞。
做渗透测试时,我常对客户说一句话:别把安全当成合规检查,它更像体检。查出问题不可怕,可怕的是明明知道哪里疼,却拖着不去看。SQL注入的修复成本,在开发阶段可能只要半天,一旦上了线,可能要通宵回滚、补丁、数据恢复,算上业务中断的损失,够买好几台服务器了。
最后说个真实案例。某电商平台的优惠券查询接口,因为一个拼接SQL的旧代码,被攻击者拖走了全量用户手机号和订单记录。事后排查发现,那个接口三年前就被标注过“低风险”,因为当时觉得“没人会注意到这个冷门功能”。结果呢?冷门功能恰恰是防守薄弱点,就像你家后院的矮围墙,贼不翻前门,专挑那儿下手。安全测试的意义,就是把每个矮围墙都垒高一点,哪怕它看起来不起眼。