select * from users where username='marcofly' and password=md5('test')
这样如果数据库不存在这样的字段就表示输入错误,无法登陆。正常情况下是如此,但是对于有SQL注入漏洞的网站来说,只要构造个特殊的“字符串”,照样能够成功登录。 比如我们填写用户名为zlq' or '1'='1' or '1'='1看看,这样后构造出的SQL语句为
select * from users where username='zlq' or '1'='1' or '1'='1' and password=md5('test') //就是替换marcofly这个字符串,替换之后它是怎么执行的呢,先执行and部分,就是 '1'='1' and password=md5('test'),这个密码对不上是返回假,就是不正确,然后执行or,
'zlq' or '1'='1'这个是或者的意思, 'zlq' 为真或者'1'='1'为真就正确,'1'='1'肯定为真的,所以正确,我们把代码缩小看看
('zlq' or '1'='1' )or ('1'='1' and password=md5('test') ),这里给出逻辑'zlq' or '1'='1' 为真,'1'='1' and password=md5('test')为假,(真 )or (假),即为正确 。你测试要是有万能密码漏洞的页面都能成功,而且很多人用htmlspecialchars过滤也没效果,因为htmlspecialchars需要填写两一个参数才能过滤单引号,默认是不过滤单引号的,所以上面的注入100%成功。
我们再输入' or 1=1#看看,把marcofly替换' or 1=1#,
select * from users where username='' or 1=1#' and password=md5('test')
语义分析:“#”在mysql中是注释符,这样井号后面的内容将被mysql视为注释内容,这样就不会去执行了,换句话说,以下的两句sql语句等价: select * from users where username='' or 1=1
这样1=1永远为真,or那么执行成功 。
现在我给出解决这个漏洞终极方案,保证天煞都无法入侵成功。是这样的,不知道前面看到没有,password=md5('test')就是说把密码经过MD5加密后再查询SQL,因为经过MD5加密后的字符串是32位的,那么经过加密后的都是一连串的像这样的ac59075b964b0715字符,是不可能办到去转换执行SQL语句的。我们经过改写SQL语句成这样:
select * from users where username=md5('marcofly') and password=md5('test')
我们再次输入用户名为 zlq' or '1'='1' or '1'='1看看,执行的语句已经变为
select * from users where username=‘6c92bfdc2da722a1’ and password=‘4621d373cade4e83’
看到了吧,无论你输入什么新型的SQL万能密码注入语句都行,都是转为一个MD5字符串。不要嫌弃经过MD5转换的效率,这里只用MD5加密过滤什么的都不用 ,其实企业中没有一个说嫌过滤牺牲性能的,如果真有这样的站长让我瞧瞧,让我膜拜一下。其实注入攻击难就难在参数性SQL注入,因为你不可能用MD5加密查询一个数据然后用MD5呈现给客户吧,如果有时间我再讲讲SQL注入的强大防御阵营。