SQL注入防御方法总结
SQL 注入(SQL Injection)是发生在 Web 程序中数据库层的安全漏洞,是网站存在最多也是最简单的漏洞。OWASP Top10虽然常年有更改,但SQL注入基本一直位于榜首,其优势在于极低的使用代价以及极高的危害性,地位可见一斑。SQL 注入已经成为互联网世界 Web 应用程序的最大风险,下面我们讲一下SQL注入的常见防御手段
采用预编译语句集
使用预编译的SQL语句,SQL语句的语义是不会发生改变的。预编译语句在创建的时候就已经将指定的SQL语句发送给了DBMS,完成了解析,检查,编译等工作,所以攻击者无法改变SQL语句的结构,只是把值赋给SQL的变量并传给SQL语句
严格控制数据类型并对特殊字符进行转义
在java、c等强类型语言中一般是不存在数字型注入的,因为在接受到用户输入id时,代码一般会做一个int id 的数据类型转换,假如我们输入的是字符串的话,那么这种情况下,程序就会报错。在PHP、ASP这些没有强调处理数据类型的语言,我们可以加入一个检查数字类型函数is_numeric()以防止字符型注入,然后将诸如" ' "这样的特殊字符进行转义,以防止了一些恶意攻击者来闭合语句
在SQL语句中检测并屏蔽掉诸如CREATE、DROP、ALERT等可能存在严重危害的DDL语言。
禁止访问系统级表
实际开发过程中,基本不会涉及需要访问系统级表,而SQL注入中需要通过系统级表访问大量信息,所以禁用系统级表可以有效防止SQL注入
禁止访问系统变量
Druid同样也是通过配置策略的方式限制用户对于系统敏感变量的访问,代码与系统表的限制类似,正常的针对version、basedir的查询不会报错,但是:
因为@@version的内容在where或having之后,所以会被禁止。判断代码Druid\src\main\java\com\alibaba\druid\wall\spi\wallvisitorutils.javaDruid使用黑名单限制了对敏感的系统变量的访问,具体内容直接被写在配置文件Druid\src\main\resources\META-INF\druid\wall\mysql\deny-variant.txt中:
禁止访问系统函数
和系统敏感的表、变量一样,Druid也禁用了诸如sleep等危险的系统函数的使用,最新的Druid在mysql中摒弃了黑名单的做法,采用白名单的方式限制函数的使用,其他数据库仍旧使用黑名单。
而且在判断使用危险系统函数的时候,和上文一样,Druid会判断敏感函数在sql语句中出现的位置:
不会被禁止,原因也是一样,不存在注入点。
会被禁止,因为显而易见的sleep函数出现在了可能存在注入点的位置(from的子节点)。
禁止出现注释
通常的业务SQL语句不会带有注释,而在SQL注入中类似的行为却很常见,Druid默认模式下,会在SQL parser解析之前,先消除语句中的单行和多行注释内容。
诸如'//or//'1'='2等常见绕waf手段都是利用了SQL的快注释符。
删除注释,并重新拼接为“合规”的sql语句的代码,位于
Druid\src\main\java\com\alibaba\druid\sql\parser\lexer.java
以“#”为例,首先判断#号的注释符,然后判断如果是单行或者多行注释。这是一种对业务低伤害的防护方式,因为业务人员如果是正常使用sql的注释功能,删除之后正常进入解析器,不会对语句正常执行造成任何影响,而如果是恶意的SQL注入行为,则会报错告警。
禁止同时执行多条SQL语句
每次只允许执行一条SQL,禁止一次执行多条SQL语句,可以有效防止堆叠注入。
禁止永真条件
利用永真条件判断是否存在注入点是sql注入攻击最常用的手段。Druid对where、order by和group by节点之后的两个及以上永真条件进行过滤。
因为单纯的永真语句普遍存在于业务代码中,比如
其中$id为可控输入,如果输入为1,在数据库层就会变成永真条件。因此Druid目前的规则允许语句子句之后最多只存在一个永真逻辑表达式。
之类的都会被拦截
使用转义字符
使用转义字符,来修复SQL注入漏洞,以便忽略掉一些特殊字符
Web应用防火墙
对访问数据库的Web应用程序采用Web应用防火墙(Web Application Firewall,WAF)。这有助于识别出针对SQL注入的各种尝试,进而防止此类尝试作用到应用程序上。
扫码关注 |
和哈士奇一起探索新世界的安全topic
文章:刘兴旺
排版:Elena