SQL注入详解以及案例与防护
SQL注入是每个基于数据库开发的研发人员,都必须要注意到的问题。
1.SQL注入的根本原因,
是攻击者可以通过传入系统的参数来篡改SQL语句造成。
其后果不外乎:
1) 查看系统表结构信息
2) 更改系统表结构信息
3) 查看/更改到该用户不被允许访问的数据表, 或表中的某些敏感数据。
2.SQL注入原理
想要防范SQL Injection, 先看看SQL是怎么被注入的。
How SQL Injected:
最典型的是这种情形: 程序中根据用户输入的数据来动态构建SQL的Where条件。拿用户登录校验举例:
如果根据用户输入的userName, password,程序中这样构建SQL:
|
1
|
String sql = "select * from users where user_name='" + userName + "' and password='" + password + "'"; |
如果用户故意输入这样的参数(无论参数来源方式是HTTP GET or HPPT Post, Ajax请求也是HPPT GET或POST之一):
userName="admin"
password="xxx' OR 1=1"
最终程序构造出来的SQL语句是:
|
1
|
"select * from users where user_name='admin' and password='xxx' or 1=1"; |
这显然轻松突破了程序假定的SQL逻辑(Where 条件总是true,变得毫无用处)。
通过这种方式可以肆意更改SQL语句,比如
|
1
2
|
"select * from users where user_name='admin' and password='xxx' or 1=1 union select * from users";"select * from users where user_name='admin' and password='xxx'; delete from users"; |
等等。
其次,结合应用系统对错误信息的不当处理,甚至可以窥测系统的表结构信息:
|
1
|
"select * from users where user_name='admin' and password='xxx' abcdef"; |
显然篡改后的SQL执行肯定会报系统错误, 类似于:
|
1
|
[jdbc]SQL error code=XXXX, SQL: select * from users where user_name='admin' and password='xxx' abcdef,; |
如果这个错误信息直接抛到页面上,那么用户立即就知道tableName=users, fieldName: user_name, password.
用户通过SQL injection再构造这样的SQL:
|
1
|
"select * from users where user_name='admin' and password='xxx' union select user_name, password/2 from user where user_name='admin'"; |
假定admin用户的密码是aaa111@@@, 那么系统在执行password/2时,尝试将aaa111@@@转换为数值再除以2时,会发生类型转换错误,类似于:
|
1
|
[jdbc]SQL error code=XXXX, 'aaa111@@@' is not a number. |
如果这个错误信息直接抛到页面上,那么用户立即就知道admin的密码是aaa111@@@
再次,如果应用连接到数据库的帐号还有DDL语句的执行权限,那就更危险了:
通过SQL Injection可以构建如下的SQL:
|
1
|
"select * from users where user_name='admin' and password='xxx' or 1=1; select table_name from all_tables"; |
查询系统所有的表的名称,以及还可以破坏数据:
|
1
2
|
"select * from users where user_name='admin' and password='xxx' or 1=1; truncate table users";"select * from users where user_name='admin' and password='xxx' or 1=1; drop table users"; |
3.SQL注入防范
了解了SQL Injection的原理,防范SQL Injection就容易了:
其实防止用户窥视系统表结构甚至执行DDL语句来破坏表结构或数据很容易:
在DB层通过限制应用程序连接到数据库的用户权限即可避免系统表被用户查看或更改。
比如:只应该授权其必要的schema和数据库对象的DML执行权限即可。
绝对不应该给其执行DDL语句(Create/Drop table, Truncate Table, etc.)的权限。
此时,就是用户篡改了SQL, 也不能成功执行DDL语句: 系统会报无权执行此SQL!
所以程序中主要是防范黑客查看/更改不被允许访问的数据表, 或表中的某些敏感数据。
其实只要你堵住用户随意更改SQL条件的漏洞,就可以防范上述的所有SQL Injection.
再进一步,只要你使用bind variables/参数绑定即可:
|
1
2
3
4
5
|
String strSQL = SELECT * FROM users where username=? AND password=?); PreparedStatement pstmt = myConnection.prepareStatement(strSQL); pstmt.setString(1,”guest”); pstmt.setString(2, “xyzabc”); pstmt.execute(); |
如果你使用Hibernate这样的OR mapping 工具的话,一样很方便地使用bind variables/参数绑定的方式来避免SQL Injection.
|
1
2
3
4
|
Query q = sess.createQuery("from Users u where u.userName = :userName and u.password=:password");q.setString("userName", "guest");q.setString("password", "password");List userList = q.list(); |
最后,对于应用系统错误,你应该通过try catch住,做特定的处理,而不是随意抛弃到页面上,以防程序逻辑或敏感信息泄漏
转自 烂代码
https://www.trashcode.cn/post/d/e30a5883-ce4d-43f8-91a7-d66ee907237a

浙公网安备 33010602011771号