检测到目标URL存在SQL注入漏洞
上周三凌晨两点,检测我盯着屏幕上一行报错:“检测到目标URL存在SQL注入漏洞”。到目这不是注入扫描器误报,是漏洞我手动测试时触发的。目标站点是检测个地方政务查询页面,参数 SQL注入这东西,检测1998年就有人公开讨论,到目二十多年过去,注入它依然排在OWASP Top 10里。漏洞为什么?检测因为写代码的人总以为“我用了框架就安全了”。错。到目我见过用MyBatis的注入接口, 具体到这次测试,漏洞点在一个不起眼的“按年份筛选”功能。URL长这样: 有人觉得SQL注入“过时了”,WAF能挡。我实测过,某云WAF对 更麻烦的是二次注入。用户注册时输入 修复方案其实很老套。参数化查询,所有数据库驱动都支持。Java用 我最后给那个政务站点提了修复建议:把 SQL注入不会消失。只要有人写?到目id=1024,加个单引号直接返回了数据库错误信息——MySQL 5.7的注入语法报错,连表名都带出来了。漏洞${ }和#{ }混用,前者直接拼接字符串,一个order by参数就能注入。也见过Django项目,开发者图省事用extra()写原生SQL,结果where条件里的用户输入没转义。/query?year=2023&type=policy。我把year改成2023' AND 1=1 -- ,页面正常;改成2023' AND 1=2 -- ,返回空。确认存在布尔盲注。再进一步,用extractvalue()报错注入,直接读出了当前数据库名:gov_query。整个过程不到十分钟。union select拦截严格,但对/*!50000union*/这种内联注释就放行了。还有用%0a换行、%09制表符绕过关键词检测的。攻击者不需要多高明,一个sqlmap加上--tamper=space2comment就能跑。防守方却要覆盖所有参数、所有编码、所有数据库类型。admin'--,应用把用户名转义后存进数据库。等管理员在后台修改这个用户密码时,SQL语句拼出来变成UPDATE users SET password='xxx' WHERE username='admin'--'。转义发生在入库前,出库后直接拼接,照样中招。这种漏洞扫描器很难发现,得靠人工审计代码。PreparedStatement,Python用cursor.execute("SELECT * FROM t WHERE id=%s", (id,)),PHP用PDO的bindParam。别自己写过滤函数,什么addslashes、mysql_real_escape_string,遇到GBK编码照样被宽字节注入打穿。还有,数据库账号权限最小化。查询接口只给SELECT权限,DROP、FILE这些全禁掉。就算被注入了,也读不到/etc/passwd。year参数强制转成整数,用Integer.parseInt(),非数字直接返回400。再上参数化查询。他们运维回了一句:“之前外包说用了防注入系统。”我截了个图发过去——sqlmap跑出来的current user: root@localhost。对方没再回复。"SELECT * FROM users WHERE name='" + name + "'",它就一直在。检测到漏洞只是开始,真正要命的是那些没被检测到的。
-
上一篇
-
下一篇