随着web应用开发的发展,有很多的程序员进入到这个行业中,但是这批人的技术水平和编程经验参差不齐,很多人在编写代码的时候,没有对用户输入的参数进行合法性校验,使得这成为了一个潜在的安全隐患。如果遇到技术高手,发现这个问题,他可以提交一段数据库查询脚本,获取对自己想要的数据,这就是我们说的sql Injection,即sql注入。
一 背景
某高校开发了一个网课系统,学生需在该系统中选课并完成学习,数据库中有一张表course,这张表存放着每个学生的选课信息及完成情况,具体设计如下:
数据如下:
本系统中数据库采用MySQL,通过数据库驱动Jdbc对数据库进行操作。
该系统提供了一个功能查询指定学生的课程完成情况的API接口,代码如下。
二 注入攻击演示
1. 正常情况下要查询一个学生的选课及完成情况,我们只需要传递该学生对应的ID即可。
这个sql脚本很简单,如下:
2. 看起来好像没有问题对吧,但是你信不信我通过这个接口可以拿到所有学生的数据,不信?要实现很简单,只要保证这条sql脚本where条件为真就可以了,如下脚本:
具体怎么做大呢?
也很简单,我们只需要在请求该接口的时候将studendId设置为4 or 1 = 1,这样这条sql的where条件就恒真了,sql也就等同于下面这样
请求结果如下,我们拿到了这张表的所有数据
3. 查询mysql版本号,使用union拼接sql
union select1,1,version(),1
4. 查询数据库名
union select1,1,database(),1
5. 查询mysql当前用户的所有库
union select1,1, (SELECTGROUP_CONCAT(schema_name) FROM information_schema.schemata) schemaName,1
通过上面的演示你有何感想?后背有没有阵阵发凉?
这里恐怖不仅仅是可以获取到你的所有数据,更可怕的是他还可对你的数据库进行更新、删除(删库、删表)等等操作。
三 如何防止sql注入
1. 代码中让sql预编译是最佳的防止sql注入攻击的方案
这样我们传进来的参数 4 or 1 = 1就会被当作是一个student_id,所以就不会出现sql注入了。
2. 确认每种数据的类型,比如是数字,数据库则必须使用int类型来存储
3. 规定数据长度,能在一定程度上防止sql注入
4. 严格限制数据库权限,能最大程度减少sql注入的危害
5. 避免直接响应一些sql异常信息,sql发生异常后,自定义异常进行响应
6. 过滤参数中含有的一些数据库关键词