SQL注入、占位符拼接符

时间:2023-12-09 12:34:31

一、什么是SQL注入

官方:

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

个人:

用户在网页输入框中输入SQL命令后,后台接收没后没有进行识别或类型转换,而把它直接运行了。直接运行的话它可是可以直接操作数据库的SQL命令,而不是后台期望的给SQL命令的普通参数。

记一次SQL注入实战 http://blog.jobbole.com/105586/

二、Mybatis中的占位符和拼接符

1、占位符

(1)#{}表示一个占位符号,通过#{}把parameterType 传入的内容通过preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。

(2)#{}可以接收简单类型值或pojo属性值。如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

例如(这是用JDBC编写,在Mybatis中我们看不到PreparedStatement,只要是用占位符#{},它自动实现这过程):

 String sql = “insert into user (name,pwd) values(?,?)”;  
 PreparedStatement ps = conn.preparedStatement(sql);  
 ps.setString(1, “jack”);   //占位符顺序从1开始
 ps.setString(2, “123456”); //也可以使用setObject
 ps.executeQuery();

2、拼接符

${}表示拼接sql串,通过${}可以将parameterType 传入的内容直接拼接在sql中且不进行jdbc类型转换,${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

三、为什么PreparedStatement 有效的防止sql注入?

1、PreparedStatement简介

PreparedStatement是用来执行SQL查询语句的API之一,Java提供了 Statement、PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程。

2、普通SQL注入简介

比如:某个网站的登录验证SQL查询代码为:

strSQL = "SELECT * FROM users WHERE name = '" + userName + "' and pw = '"+ passWord +"';"

 

恶意填入:

userName = "1' OR '1'='1";

passWord = "1' OR '1'='1";

 

那么最终SQL语句变成了:

strSQL = "SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1';"

 

因为WHERE条件恒为真,这就相当于执行:

strSQL = "SELECT * FROM users;"

因此可以达到无账号密码亦可登录网站。

3、使用PreparedStatement的参数化的查询可以阻止大部分的SQL注入

在使用参数化查询的情况下,数据库系统(eg:MySQL)不会将参数的内容视为SQL指令的一部分来处理,而是在数据库完成SQL指令的编译后,才套用参数运行,因此就算参数中含有破坏性的指令,也不会被数据库所运行。

即SQL语句在程序运行前已经进行了预编译,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1'、数据库也会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令。

补充1:在页面输入的时候可以加入校验,不可输入sql关键字,不可输入空格,也可以防止SQL注入。

补充2:PreparedStatement比 Statement 更快

使用 PreparedStatement 最重要的一点好处是它拥有更佳的性能优势,SQL语句会预编译在数据库系统中。执行计划同样会被缓存起来,它允许数据库做参数化查询。使用预处理语句比普通的查询更快,因为它做的工作更少(数据库对SQL语句的分析,编译,优化已经在第一次查询前完成了)。为了减少数据库的负载,生产环境中德JDBC代码你应该总是使用PreparedStatement 。值得注意的一点是:为了获得性能上的优势,应该使用参数化sql查询而不是字符串追加的方式。下面两个SELECT 查询,第一个SELECT查询就没有任何性能优势。

SQL Query 1:字符串追加形式的PreparedStatement

String loanType = getLoanType();

PreparedStatement prestmt = conn.prepareStatement("select banks from loan where loan_type=" + loanType);

SQL Query 2:使用参数化查询的PreparedStatement

PreparedStatement prestmt = conn.prepareStatement("select banks from loan where loan_type=?");

prestmt.setString(1,loanType);

很明显Mybatis中是用的参数化查询

参考:http://www.importnew.com/5006.html