定义:
SQL注入常见的Web安全问题之一,其形式主要是把SQL命令插入到Web表单提交或页面请求url的查询字符串,破坏原有SQL结构,最终达到欺骗服务器执行恶意的SQL命令。
原理
sql注入的原理是将sql代码伪装到输入参数中,传递到服务器解析并执行的一种攻击手法。也就是说,在一些对server端发起的请求参数中植入一些sql代码,server端在执行sql操作时,会拼接对应参数,同时也将一些sql注入攻击的“sql”拼接起来,导致会执行一些预期之外的操作。
示例:
日常使用的登录接口:在登录界面包括用户名和密码输入框,以及提交按钮,输入用户名和密码,提交。
登录时调用接口/user/login/ 加上参数username、password,首先连接数据库,然后后台对请求参数中携带的用户名、密码进行参数校验,即sql的查询过程。假设正确的用户名和密码为ls和123456,输入正确的用户名和密码、提交,相当于调用了以下的SQL语句。
SELECT * FROM user WHERE username = 'ls' AND password = '123456'
sql中会将#及--以后的字符串当做注释处理,如果我们使用“' or 1=1 #"作为用户名参数,那么服务端构建的sql语句就如下:
select * from users where username='' or 1=1#' and password='123456'
而#会忽略后面的语句,因此上面的sql也等价于:
select * from users where username='' or 1=1
而1=1属于常等型条件,因此这个sql便成为了如下,查询出所有的登陆用户。
select * from users
其实上面的sql注入只是在参数层面做了些手脚,如果是引入了一些功能性的sql那就更危险了,比如上面的登陆接口,如果用户名使用这个"' or 1=1;delete * from users;#",那么在";"之后相当于是另外一条新的sql,这个sql是删除全表,那后果可想而知
SQL 注入的危害:
如果网站存在 SQL 注入漏洞,相当于将数据库直接暴露在攻击者面前。攻击者利用 SQL 注入漏洞能实现包括但不限于以下攻击:
- 跳过账户权限验证达到越权;
- 获取数据库关键信息从而进行脱库
- 在特别情况下还可以修改数据库内容或者插入内容到数据库,如果数据库权限分配存在问题,或者数据库本身存在缺陷,那么攻击者可以通过SQL注入漏洞直接获取webshell或者服务器系统权限。
如何有效防止SQL注入:
-
数据校验:对来自用户的数据(GET, POST, cookie 等)最好做到以下两种过滤校验(前后端最好能同时校验):
- 检查输入的数据是否具有所期望的数据格式。这种在参数是数字的时候特别有效,如果攻击者选择在参数中插入内容的话则会被转换成
NaN
导致攻击失败。 - 使用数据库特定的敏感字符转义函数把用户提交上来的非数字数据进行转义。
- 特殊字符:--、#、等等
- 权限限制
严格限制Web应用的数据库的操作权限,给此用户提供仅仅能够满足其工作的最低权限,从而最大限度的减少注入攻击对数据库的危害。
- 日志处理:当数据库操作失败的时候,尽量不要将原始错误日志返回,比如类型错误、字段不匹配等,把代码里的 SQL 语句暴露出来,以防止攻击者利用这些错误信息进行 SQL 注入。
-
sql预编译(非ORM框架)
通过prepareStatementsql进行预编译,将绑定的参数传到mysql服务器,mysql服务器对参数进行编译,即填充到相应的占位符的过程中,做了转义操作。 我们常用的jdbc就有预编译功能,不仅提升性能,而且防止sql注入。
- ORM框架处理 如myBatis
myBatis使用注意事项:
MyBatis中并不是百分百的能防止SQL注入,比如“#{xxx}”
这样格式的参数会直接参与SQL编译,从而不能避免注入攻击。但涉及到动态表名和列名时,只能使用“${xxx}”
这样的参数格式。所以,这样的参数需要我们在代码中手工进行处理来防止注入。
在编写MyBatis的映射语句时,尽量采用“#{xxx}”
这样的格式。若不得不使用“${xxx}”
这样的参数,要手工地做好过滤工作,来防止SQL注入攻击。