|
SQL注入攻击至今仍是效限OWASP Top 10里的常客,根源在于开发者把用户输入直接拼进了SQL语句。制s注入别指望防火墙或WAF能替你挡掉所有攻击,攻击真正的效限防线必须落在代码层。 参数化查询(Prepared Statement)是制s注入第一条防线,也是攻击唯一值得无条件信任的方案。拿Java的效限JDBC举例,用PreparedStatement代替Statement,制s注入把用户输入当作参数传入,攻击数据库驱动会负责转义特殊字符。效限这招对绝大多数注入变体都有效,制s注入因为SQL语句的攻击结构在编译时就已经固定,用户输入永远只是效限数据,不可能变成可执行代码。制s注入我见过不少团队用了ORM框架就以为万事大吉,攻击结果在写原生查询时又犯了拼接的老毛病——框架只是工具,不背这个锅。 存储过程算是个折中方案,但它不是银弹。如果你在存储过程内部还是用动态SQL拼接,那跟直接在应用层拼接没区别。真正有意义的是把数据库权限收紧:应用账号只赋予执行存储过程的权限,不直接操作表。这样即便注入成功,攻击者能调用的也仅限于预设好的逻辑,翻不了天。当然,这要求你设计存储过程时足够谨慎,别把EXEC或sp_executesql用得飞起。 输入验证和转义属于辅助手段,别把它当主菜。白名单校验(比如只允许数字、特定格式的字符串)能挡掉一部分低水平攻击,但黑名单过滤几乎没用——攻击者用/*注释、CHAR()函数编码、Unicode变体就能轻松绕过。转义函数(如MySQL的mysql_real_escape_string)也只在正确设置字符集时有效,否则可能被宽字节注入击穿。这些手段能增加攻击成本,但依赖它们等于在走钢丝。 数据库账号权限的最小化设计,是很多人忽略却性价比极高的一步。应用连接数据库的账号,原则上只该有SELECT、INSERT、UPDATE、DELETE权限,绝不给DROP、ALTER或FILE权限。我见过某家电商公司,应用账号居然有GRANT OPTION,被注入后攻击者直接给自己建了个管理员账号。权限收得越紧,注入后的破坏半径就越小——哪怕SQL语句被篡改,数据库引擎也会因为权限不足直接报错。 把错误信息藏好,别给攻击者当向导。数据库报错信息里往往包含表名、字段名甚至SQL片段,这些是攻击者构造后续payload的地图。生产环境统一返回泛化的错误页面,详细日志只写到服务端文件,并且定期轮转清理。别嫌麻烦,攻击者拿到一次详细报错,可能省掉几小时的盲注探测时间。 最后提一句,定期做渗透测试或代码审计,别光靠开发自觉。自动化扫描工具能发现明显的拼接点,但业务逻辑复杂的漏洞还是需要人工看。找个懂安全的后端工程师或者外包团队,每季度打一次,比出事后再救火便宜得多。 说到底,SQL注入不是靠某个单一技巧能根治的顽疾,它考验的是从编码习惯到运维规范的整套流程。把参数化查询当默认选项,权限收紧当硬性要求,错误处理当日常习惯——这三板斧落地了,绝大多数注入攻击就跟你没关系了。剩下的边角料,靠测试补漏就行。 |