MySql sql注入问题的学习

MySql sql注入问题

什么是SQL注入?

SQL注入是影响企业运营最具有破坏性的漏洞之一。

应用程序向后台数据库进行SQL查询时,如果为攻击者提供了影响该查询的能力,就会引起SQL注入。

示例:

name = "Robert');DROP TABLE students;--"
query = "INSERT INTO students (name) VALUES ('%s')" % (name)

conn.executescript(query)

也就是说,这段包含DROP TABLE关键字的数据项使得原有的简单的插入姓名信息的SQL语句:

INSERT INTO students (name) VALUES ('Robert')

变为了同时包含另外一条清除表单命令的语句:

INSERT INTO students (name) VALUES ('Robert');DROP TABLE students;

防护方法与解决方案

例如:

1使用PreparedStatement,避免直接使用Statement对象

Statement对象可能造成sql注入:

直接使用 JDBC 的场景,如果代码中存在拼接 SQL 语句,那么很有可能会产生注入,如

// concat sql
String sql = "SELECT * FROM users WHERE name ='"+ name + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);

安全的写法是使用 参数化查询 ( parameterized queries ),即 SQL 语句中使用参数绑定( ? 占位符 ) 和 PreparedStatement,如

// use ? to bind variables
String sql = "SELECT * FROM users WHERE name= ? ";
PreparedStatement ps = connection.prepareStatement(sql);
// 参数 index 从 1 开始
ps.setString(1, name);

还有一些情况,比如 order by、column name,不能使用参数绑定,此时需要手工过滤,如通常 order by 的字段名是有限的,因此可以

使用白名单的方式来限制参数值

使用了 PreparedStatement 并不意味着不会产生注入,如果在使用 PreparedStatement之前,存在拼接 sql 语句,

那么仍然会导致注入,如

// 拼接 sql
String sql = "SELECT * FROM users WHERE name ='"+ name + "'";
PreparedStatement ps = connection.prepareStatement(sql);

PreparedStatement 是如何防止 SQL 注入的?

正常情况下,用户的输入是作为参数值的,而在 SQL 注入中,用户的输入是作为 SQL 指令的一部分,会被数据库进行编译/解释执行。

当使用了 PreparedStatement,**带占位符 ( ? ) 的 sql 语句只会被编译一次,**之后执行只是将占位符替换为用户输入,并不会再次编译/解

释,因此从根本上防止了 SQL 注入问题。

在 select * from table where 后面拼接一些条件来获取你的信息

Mybatis下注入防范

应尽量避免采用 的 形 式 进 行 参 数 传 递 。 果 无 法 避 免 ( 有 些 S Q L 如 l i k e 、 i n 、 o r d e r b y 等 , 程 序 员 可 能 依 旧 会 选 择 {}的形式进行参数传递。果无法避免(有些SQL如like、in、order by等,程序员可能依旧会选择 SQLlikeinorderby{}的方式传

参),那就需要对传入参数自行进行转义过滤。

使用 #{} 语法时,MyBatis 会自动生成 PreparedStatement ,使用参数绑定 ( ?) 的方式来设置值,上述两个例子等价的 JDBC 查询代码如下:

String sql = "SELECT * FROM users WHERE id = ?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setInt(1, id);

因此 #{} 可以有效防止 SQL 注入,

但有些时候,如 order by 语句,使用 #{} 会导致出错,如

ORDER BY #{sortBy}

sortBy 参数值为 name ,替换后会成为

ORDER BY "name"

即以字符串 “name” 来排序,而非按照 name 字段排序

这种情况就需要使用 ${}

ORDER BY ${sortBy}

使用了 ${}后,使用者需要自行过滤输入,方法有:

代码层使用白名单的方式,限制 sortBy 允许的值,如只能为 name, email 字段,异常情况则设置为默认值 name

在 XML 配置文件中,使用 if 标签来进行判断

Mapper 接口方法

List<User> getUserListSortBy(@Param("sortBy") String sortBy);
<select id="getUserListSortBy" resultType="org.example.User">
SELECT * FROM user 
    <if test="sortBy == 'name' or sortBy == 'email'">
    	order by ${sortBy} 
    </if>
</select>

因为 Mybatis 不支持 else,需要默认值的情况,可以使用 choose(when,otherwise)

<select id="getUserListSortBy" resultType="org.example.User">
    SELECT * FROM user  
    <choose>    
        <when test="sortBy == 'name' or sortBy == 'email'">      
            order by ${sortBy}    
        </when>    
        <otherwise>     
         order by name    
        </otherwise>    
    </choose>
</select>

JPA注入防范

从SQL注入防范的角度来说,这种将安全责任抛给框架远比依靠程序员自身控制来的保险。因此如果项目使用JPA作为数据访问层,基本

上可以很大程度的消除SQL注入的风险。但是话不能说的太死,在我见过的一个Spring Boot项目中,虽然采用了JPA作为持久框架,但是

有一位老程序员不熟悉于使用JPQL来构建查询接口,依旧使用字符串拼接的方式来实现业务,而为项目安全埋下了隐患。

,程序员只要遵循JPA的开发规范,就无需担心注入问题,框架都为你做好幕后工作了。

sql注入的其他防范方法

  • 一切输入都是不安全的:对于接口的调用参数,要进行格式匹配,例如admin的通过name查询的接口,与之匹配的Path应该使用正

    则匹配(因为用户名中不应该存在特殊字符),从而确保传入参数是程序控制范围之内的参数,即只接受已知的良好输入值,拒绝不

    良输入。注意:验证参数应将它与输出编码技术结合使用。

  • 利用分层设计来避免危险:前端尽量静态化,尽量少的暴露可以访问到DAO层的接口到公网环境中,如果现有项目,很难修改存在注

    入的代码,可以考虑在web服务之前增加WAF进行流量过滤,当然代码上就不给hacker留有攻击的漏洞才最好的方案。也可以在拥有

    nginx的架构下,采用OpenRestry做流量过滤,将一些特殊字符进行转义处理。

  • 尽量使用预编译SQL语句:由于动态SQL语句是引发SQL注入的根源。应使用预编译语句来组装SQL查询。

  • 规范化:将输入安装规定编码解码后再进行输入参数过滤和输出编码处理;拒绝一切非规范格式的编码。

参考

漫画:什么是SQL 注入?:https://mp.weixin.qq.com/s/R6G89cY4QlqUyW3L7iAE3A

美团一面:如何干掉恶心的 SQL 注入?:https://mp.weixin.qq.com/s/2oEnztxm26bT67I66ayLQw

以Java的视角来聊聊SQL注入:https://mp.weixin.qq.com/s/0_m15WGpTtcxDJ2fg1HtFQ

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值