开发同事反馈有系统收到SQL注入的风险告警,整理一下SQL注入攻击常见方式及预防方法。
SQL注入攻击是输入参数未经过滤,直接拼接到SQL语句当中解析,执行达到开发者预想之外行为的攻击方式。
下面是网上找到的例子
以php编程语言、mysql数据库为例,介绍一下SQL注入攻击的构造技巧、构造方法
在浏览器地址栏输入:learn.me/sql/article.php?id=1,正常情况下,应该返回一个id=1的文章信息。这是一个get型接口,发送这个请求相当于调用一个查询语句:
$sql = "SELECT * FROM article WHERE id =",$id
但是,如果在浏览器地址栏输入:learn.me/sql/article.php?id=-1 OR 1 =1,这就是一个SQL注入攻击,会返回文章的所有信息。因为1=1永远是true,所以where条件相当于没有,查询的结果相当于整张表的内容。
有这样一个用户登录场景:登录界面包括用户名和密码输入框,以及登录按钮。
这是一个post请求,登录时调用接口learn.me/sql/login.html,首先连接数据库,然后后台对post请求参数中携带的用户名、密码进行参数校验,即sql的查询过程。
假设正确的用户名和密码为user和pwd123,输入正确的用户名和密码、提交,相当于调用了以下的SQL语句:
SELECT * FROM user WHERE username = 'user' ADN password = 'pwd123'
由于用户名和密码都是字符串,SQL注入方法即把参数携带的数据变成mysql中注释的字符串。
mysql中有2种注释的方法:
用户名输入:user'#(单引号用于闭合user左边的单引号),密码随意输入,如:111,然后提交。等价于SQL语句:
SELECT * FROM user WHERE username = 'user'#'ADN password = '111'
由于后面都被注释掉了,相当于SQL没有了密码验证:
SELECT * FROM user WHERE username = 'user'
用户名输入:user'-- (注意--后面有个空格,单引号用于闭合user左边的单引号),密码随意输入,如:111,然后提交。等价于SQL语句:
SELECT * FROM user WHERE username = 'user'-- 'AND password = '111'
因此,以上两种情况可能输入一个错误的密码或者不输入密码就可登录用户名为'user'的账号,这是十分危险的事情。
例如java就有PreprareStatement进行预编译。
在程序运行时第一次操作数据库之前,SQL已经被数据库编译和解析,对应的执行计划也会缓存下来并以参数化的形式进行查询。当把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1’,数据库也只会将它作为一个参数值来处理而不会作为一个SQL指令,如此,就起到防止SQL注入的作用了。
例如之前的语句
SELECT * FROM article WHERE id = -1 OR 1=1
预编译会将输入整体作一个参数,而不是SQL的一部分,即解释为
SELECT * FROM article WHERE id = '-1 OR 1=1'
如果限定了id是数字类型,该sql执行会报错;如果是字符串类型,应该也查询不出结果
参考
https://blog.csdn.net/han0373/article/details/79181045
https://blog.csdn.net/github_36032947/article/details/78442189
https://blog.csdn.net/weixin_45179130/article/details/90761966