为什么能够登陆成功呢?实际执行的语句是:
select * from users where username='123' or 1=1 #' and password='123' or 1=1 #'
按照 Mysql 语法,#
后面的内容会被忽略,所以以上语句等同于:
select * from users where username='123' or 1=1
由于判断语句 or 1=1
恒成立,所以结果当然返回真,成功登录!
我们再尝试不使用 #
屏蔽单引号,在用户名中输入 123' or '1'='1
, 密码同样输入 123' or '1'='1
。
依然能够成功登录,实际执行的 SQL 语句是:
select * from users where username='123' or '1'='1' and password='123' or '1'='1'
两个 or
语句使 and
前后两个判断永远恒等于真,所以能够成功登录!
2.3、SQL 注入示例三:判断注入点
通常情况下,可能存在 SQL 注入漏洞的 Url 是类似这种形式 :http://xxx.xxx.xxx/abcd.php?id=XX
。
对 SQL 注入的判断,主要有两个方面:
- 判断该带参数的 Url 是否可以进行 SQL 注入
- 如果存在 SQL 注入,那么属于哪种 SQL 注入
可能存在 SQL 注入攻击的动态网页中,一个动态网页中可能只有一个参数,有时可能有多个参数。有时是整型参数,有时是字符串型参数,不能一概而论。
总之,只要是带有参数的动态网页且此网页访问了数据库,那么就有可能存在 SQL 注入。
例如现在有这么一个 URL 地址:
http://xxx/abc.php?id=1
首先根据经验猜测,它可能执行如下语句进行查询:
select * from <表名> where id = x
因此,在 URL 地址栏中输入http://xxx/abc.php?id= x and '1'='1
页面依旧运行正常,继续进行下一步!
当然不带参数的 URL 也未必是安全的,现在有很多第三方的工具,例如postman
工具,一样可以模拟各种请求!
黑客们在攻击的时候,同样会使用各种假设法来验证自己的判断!
三、如何预防 SQL 注入呢
上文中介绍的 SQL 攻击场景都比较基础,只是简单的向大家介绍一下!
那对于这种黑客攻击,我们有没有什么办法呢?
答案肯定是有的,就是对前端用户输入的所有的参数进行审查,最好是全文进行判断或者替换!
例如,当用户输入非法字符的时候,使用正则表达式进行匹配判断!
private String CHECKSQL = "^(.+)\\sand\\s(.+)|(.+)\\sor(.+)\\s$"; Pattern.matches(CHECKSQL,targerStr);
或者,全局替换,都可以!
public static String TransactSQLInjection(String sql) { return sql.replaceAll(".*([';]+|(--)+).*", " "); }
还可以采用预编译的语句集!
例如当使用Mybatis
的时候,尽可能的用#{}
语法来传参数,而不是${}
!
举个例子!
如果传入的username 为 a' or '1=1
,那么使用 ${}
处理后直接替换字符串的sql就解析为
select * from t_user where username = 'a' or '1=1'
这样的话所有的用户数据就被查出来了,就属于 SQL 注入!
如果使用#{}
,经过 sql
动态解析和预编译,会把单引号转义为 \'
,SQL 最终解析为
select * from t_user where username = "a\' or \'1=1 "
这样会查不出任何数据,有效阻止 SQL 注入!
四、参考
1、简书 - Jewel591 - sql注入基础原理
2、极术社区 - 悟能之能 - 你真的了解MyBatis中${}和#{}的区别吗?