防止sql注入 注释,求大神指点,因为我是刚学java,有些还需要注释,下面是摘抄的,但是我不懂

MySQL for Java的SQL注入测试 - 加菲学Java - ITeye技术网站
博客分类:
只要你学JDBC,基本上所有的人都会和你说,Statement不能防止SQL注入, PreparedStatement能够防止SQL注入.
基本上参加工作了一段时间之后还是这么认为的, 没错, 这句是没有问题的, 但到底如何进行SQL注入?怎么直观的去了解SQL注入?这还是需要花一定的时间去实验的.
前提:以下的测试都是在一种理想环境下
首先准备好数据库环境, 以下是数据库的schema:
create database java_
create table pstest(
id int(10) not null primary key auto_increment,
name varchar(32),
age int(3)
insert into pstest (name, age) values ('Tom', 23);
insert into pstest (name, age) values ('Tom1', 23);
insert into pstest (name, age) values ('Tom2', 23);
insert into pstest (name, age) values ('Tom3', 23);
insert into pstest (name, age) values ('Tom4', 23);
insert into pstest (name, age) values ('Tom5', 23);
以上就是建立了pstest表, 并插入了一些测试数据.
1. 测试Statement
public class StatementTest {
public static void main(String[] args) throws SQLException {
Connection con =
Statement stmt =
// name很强大, 传入了这么多东西
String name = "Tom';select * from pstest where name='Tom";
String sql = createSql(name);
System.out.println(sql);
con = DBConn.getConnection();
stmt = con.createStatement();
stmt.execute(sql);
} catch(Exception e) {
e.printStackTrace();
} finally {
stmt.close();
con.close();
// 根据参数的name参数查询
private static String createSql(String name) {
String sql = "select id, name, age from pstest ";
// 拼接一下SQL
if(name != null && name.length() != 0) {
sql += "where name ='" + name + "'";
数据库连接的URL为:
"jdbc:mysql://localhost:3306/java_mysql";
其实上面的意图很简单:
Tom';select * from pstest where name='Tom
就是想先执行一条SQL查询语句,然后把表的数据删除。
这只是理想环境. 实际上要想传入这么复杂的数据, 真的很难想象
这里将URL单独拎出来是有作用的, 继续看下面
Run一下StatementTest. 会发现报异常了:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL check the manual that corresponds to your MySQL server version for the right syntax to use near 'select * from pstest where name='Tom'' at line 1
想法很简单, 现实很残酷, 未能如所愿.
看到这里,你也应该想到了Statement的execute(String sql)默认是只能执行一条SQL的.
若想让execute(String sql)能够同时只能几条SQL语句, 怎么办?修改连接的URL:
jdbc:mysql://localhost:3306/java_mysql?allowMultiQueries=true
重点是allowMultiQueries=true这个参数
再来Run一下StatementTest. OK,没有报任何的异常.打印的SQL为:
select id, name, age from pstest where name ='Tom';select * from pstest where name='Tom';
上面的SQL到底做了什么呢?
我们先观察一下:第一条是查询SQL, 第二条是delete, 第三条是查询SQL,其实第一条和第三条是一样的.
为了直观的看上面SQL的执行效果, 我们再次执行下最开始的schema.sql
这时候数据库有6条数据
mysql& select *
+----+------+------+
| id | name | age
+----+------+------+
2 | Tom1 |
3 | Tom2 |
4 | Tom3 |
5 | Tom4 |
6 | Tom5 |
+----+------+------+
select id, name, age from pstest where name ='Tom';select * from pstest where name='Tom';
这时候可以看到MySQL客户端
mysql& select id, name, age from pstest where name ='Tom';select * from pstest where name='Tom';
+----+------+------+
| id | name | age
+----+------+------+
+----+------+------+
1 row in set (0.00 sec)
-- 执行第一条查询SQL
Query OK, 6 rows affected (0.05 sec)
-- 执行第二条delete语句, Oh, No, 数据库全部的6条数据被删除了
Empty set (0.00 sec)
-- 执行第三条SQL查询, 没有查询到任何数据
上面的注释已经写好了,就不多说了。
这时候的确已经实现了SQL注入.
2. 测试PreparedStatemet
public class PreparedStatementTest {
public static void main(String[] args) throws SQLException {
Connection con =
PreparedStatement ps =
ResultSet rs =
String sql = "select id, name, age from pstest where name = ? ";
con = DBConn.getConnection();
ps = con.prepareStatement(sql);
ps.setString(1, "Tom';select * from pstest where name='Tom");
rs = ps.executeQuery();
} catch(Exception e) {
e.printStackTrace();
} finally {
rs.close();
ps.close();
con.close();
直接Run一下,OK,也没出现任何的异常,数据库中的数据也还在
但是我们到底执行了什么样的SQL, 查看MySQL的日志.
这里简单提下MySQL的日志,可以在my.ini下配置
log=MySQL_Log
# 在这里加上日志名称
这时候会在MySQL/MySQL Server 5.1/Data/目录下生成MySQL_Log文件, 里面记录的就是日志了.
好了,回到正题,看一下刚刚PreparedStatementTest执行的SQL,在MySQL_Log中查看
23 Connect
root@localhost on java_mysql
23 Query /* mysql-connector-java-5.1.20-SNAPSHOT ( Revision: ${bzr.revision-id} ) ...
23 Query SHOW WARNINGS
23 Query /* mysql-connector-java-5.1.20-SNAPSHOT ( Revision: ${bzr.revision-id} ) */SELECT @@session.auto_increment_increment
23 Query SHOW COLLATION
23 Query SET character_set_results = NULL
23 Query SET autocommit=1
23 Query select id, name, age from pstest where name = 'Tom\';select * from pstest where name=\'Tom'
重点是最后一条SQL.
因为数据库中的数据都还在,我们就直接执行这条SQL
select id, name, age from pstest where name = 'Tom\';select * from pstest where name=\'Tom'
查看MySQL的客户端
mysql& select id, name, age from pstest where name = 'Tom\';select * from pstest where name=\'Tom';
Empty set (0.00 sec)
-- 就执行了这一条查询的SQL语句
可以看到什么的字符串已经被转义了.
让我们来看一下转义字符:
mysql& select 'Tom\';delete';
+-------------+
| Tom';delete |
+-------------+
| Tom';delete |
+-------------+
1 row in set (0.00 sec)
总结:其实从上面的测试中已经看出了。的确Statement是不安全的, 可以进行SQL注入, 而PreparedStatement可以防止SQL注入。就好比上面我们想在做查询的时候将pstest中的全部数据都删除掉一样. 前面已经说过这是在理想的环境下做的测试. 在真正的环境中,就想这么简单的实现SQL注入, 基本上是不可能的。而且Statemenet,让它执行execute(String sql)的时候同时执行多条SQL, 基本上不可能会去这么做的.
其实,关于Statement的execute(String sql)语句能够同时执行多条SQL语句, 可以看MySQL自带的测试例子:
可查看testsuite.regression包下的ResultSetRegressionTest类:
public class ResultSetRegressionTest extends BaseTestCase {
public void testBug33678() throws Exception {
if (!versionMeetsMinimum(4, 1)) {
createTable("testBug33678", "(field1 INT)");
// allowMultiQueries=true设置
Connection multiConn = getConnectionWithProps("allowMultiQueries=true");
Statement multiStmt = multiConn.createStatement();
multiStmt.setFetchSize(Integer.MIN_VALUE);
// 一次性执行多条SQL语句
.execute("SELECT 1 UNION SELECT 2; INSERT INTO testBug33678 VALUES (1); UPDATE testBug33678 set field1=2; INSERT INTO testBug33678 VALUES(3); UPDATE testBug33678 set field1=2 WHERE field1=3; UPDATE testBug33678 set field1=2; SELECT 1");
// 以下代码省略...
加菲学Java
浏览: 96946 次
来自: 扬州
huang_xiaok 写道FusionCharts XT有免 ...
FusionCharts XT有免费试用版可以下载哦,下载地址 ...
fusioncharts 图片2种方式使用java导出 - 项 ...
这里假定任何以 '/' 结束的 URL 都是指向目录的。如果不 ...
扫盲贴,不错!!!有效防止SQL注入的5种方法总结
作者:jason.bai
字体:[ ] 类型:转载 时间:
SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编程时的疏忽,通过SQL语句,实现无帐号登录,甚至篡改数据库。下面这篇文章主要给大家介绍了关于防止SQL注入的5种方法,教大家有效的防止sql注入,需要的朋友可以参考学习。
sql注入入门
SQL 注入是一类危害极大的攻击形式。虽然危害很大,但是防御却远远没有XSS那么困难。
SQL 注入漏洞存在的原因,就是拼接 SQL 参数。也就是将用于输入的查询参数,直接拼接在 SQL 语句中,导致了SQL 注入漏洞。
演示下经典的SQL注入
我们看到:select id,no from user where id=2;
如果该语句是通过sql字符串拼接得到的,比如: String sql = "select id,no from user where id=" +
其中的 id 是一个用户输入的参数,那么,如果用户输入的是 2, 那么上面看到查到了一条数据,如果用户输入的是 2 or 1=1 进行sql注入攻击, 那么看到,上面的语句(select id,no from user where id=2 or 1=1; )将user表中的所有记录都查出来了。 这就是典型的sql注入。
再看一列:
我们看到通过 sql 注入能够直接将表 sqlinject 删除掉!可见其危害!
SQL注入攻击的总体思路
&&&&& 1、寻找到SQL注入的位置
&&&&& 2、判断服务器类型和后台数据库类型
&&&&& 3、针对不通的服务器和数据库特点进行SQL注入攻击
SQL注入攻击实例
比如在一个登录界面,要求输入用户名和密码:
可以这样输入实现免帐号登录:
用户名: ‘or 1 = 1 –
密 码:点登陆,如若没有做特殊处理,那么这个非法用户就很得意的登陆进去了.(当然现在的有些语言的数据库API已经处理了这些问题)
这是为什么呢? 下面我们分析一下:
从理论上说,后台认证程序中会有如下的SQL语句:
String sql = "select * from user_table where username=' "+userName+" ' and password=' "+password+" '";
当输入了上面的用户名和密码,上面的SQL语句变成:
SELECT * FROM user_table WHERE username=''or 1 = 1 -- and password=''
分析SQL语句:
条件后面username=”or 1=1 用户名等于 ” 或1=1 那么这个条件一定会成功;
然后后面加两个-,这意味着注释,它将后面的语句注释,让他们不起作用,这样语句永远都能正确执行,用户轻易骗过系统,获取合法身份。
这还是比较温柔的,如果是执行
SELECT * FROM user_table WHERE username='' ;DROP DATABASE (DB Name) --' and password=''
….其后果可想而知…
下面我针对JSP,说一下应对方法:
1.(简单又有效的方法)PreparedStatement
采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。
使用好处:
&&&& (1).代码的可读性和可维护性.
&&&& (2).PreparedStatement尽最大可能提高性能.
&&&& (3).最重要的一点是极大地提高了安全性.
sql注入只对sql语句的准备(编译)过程有破坏作用
而PreparedStatement已经准备好了,执行阶段只是把输入串作为数据处理,
而不再对sql语句进行解析,准备,因此也就避免了sql注入问题.
2.使用正则表达式过滤传入的参数
要引入的包:
import java.util.regex.*;
正则表达式:
private String CHECKSQL = “^(.+)\\sand\\s(.+)|(.+)\\sor(.+)\\s$”;
判断是否匹配:
Pattern.matches(CHECKSQL,targerStr);
下面是具体的正则表达式:
检测SQL meta-characters的正则表达式 : /(\%27)|(\')|(\-\-)|(\%23)|(#)/ix
修正检测SQL meta-characters的正则表达式 : /((\%3D)|(=))[^\n]*((\%27)|(\')|(\-\-)|(\%3B)|(:))/i
典型的SQL 注入攻击的正则表达式 : /\w*((\%27)|(\'))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix
检测SQL注入,UNION查询关键字的正则表达式 : /((\%27)|(\'))union/ix(\%27)|(\')
检测MS SQL Server SQL注入攻击的正则表达式: /exec(\s|\+)+(s|x)p\w+/ix
3.字符串过滤
比较通用的一个方法:
(||之间的参数可以根据自己程序的需要添加)
public static boolean sql_inj(String str){
String inj_str = "'|and|exec|insert|select|delete|update|
count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
String inj_stra[] = split(inj_str,"|");
for (int i=0 ; i & inj_stra. i++ ){
if (str.indexOf(inj_stra[i])&=0){
4.jsp中调用该函数检查是否包函非法字符
防止SQL从URL注入:
sql_inj.java代码:
package sql_
import java.net.*;
import java.io.*;
import java.sql.*;
import java.text.*;
import java.lang.S
public class sql_inj{
public static boolean sql_inj(String str){
String inj_str = "'|and|exec|insert|select|delete|update|
count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
//这里的东西还可以自己添加
String[] inj_stra=inj_str.split("\\|");
for (int i=0 ; i & inj_stra. i++ ){
if (str.indexOf(inj_stra[i])&=0){
5.JSP页面判断代码:
使用javascript在客户端进行不安全字符屏蔽
功能介绍:检查是否含有”‘”,”\\”,”/”
参数说明:要检查的字符串
返回值:0:是1:不是
function check(a){
fibdn = new Array (”‘” ,”\\”,”/”);
for (ii=0; ii<i; ii++)
{ for (jj=0; jj<j; jj++)
{ temp1=a.charAt(jj);
temp2=fibdn[ii];
if (tem'; p1==temp2)
{ return 0; }
总的说来,防范一般的SQL注入只要在代码规范上下点功夫就可以了。
凡涉及到执行的SQL中有变量时,用JDBC(或者其他数据持久层)提供的如:PreparedStatement就可以 ,切记不要用拼接字符串的方法就可以了。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具java持久层框架mybatis如何防止sql注入
sql注入大家都不陌生,是一种常见的攻击方式,攻击者在界面的表单信息或url上输入一些奇怪的sql片段,例如“or ‘1’=’1’”这样的语句,有可能入侵参数校验不足的应用程序。所以在我们的应用中需要做一些工作,来防备这样的攻击方式。在一些安全性很高的应用中,比如银行软件,经常使用将sql语句全部替换为存储过程这样的方式,来防止sql注入,这当然是一种很安全的方式,但我们平时开发中,可能不需要这种死板的方式。
mybatis框架作为一款半自动化的持久层框架,其sql语句都要我们自己来手动编写,这个时候当然需要防止sql注入。其实Mybatis的sql是一个具有“输入+输出”功能,类似于函数的结构,如下:
&select id=“getBlogById“ resultType=“Blog“
parameterType=”int”&
select id,title,author,content
from blog where id=#{id}
这里,parameterType标示了输入的参数类型,resultType标示了输出的参数类型。回应上文,如果我们想防止sql注入,理所当然地要在输入参数上下功夫。上面代码中高亮部分即输入参数在sql中拼接的部分,传入参数后,打印出执行的sql语句,会看到sql是这样的:
id,title,author,content from blog where id = ?
不管输入什么参数,打印出的sql都是这样的。这是因为mybatis启用了预编译功能,在sql执行前,会先将上面的sql发送给数据库进行编译,执行时,直接使用编译好的sql,替换占位符“?”就可以了。因为sql注入只能对编译过程起作用,所以这样的方式就很好地避免了sql注入的问题。
mybatis是如何做到sql预编译的呢?其实在框架底层,是jdbc中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的sql语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行一个sql时,能够提高效率,原因是sql已编译好,再次执行时无需再编译。
话说回来,是否我们使用mybatis就一定可以防止sql注入呢?当然不是,请看下面的代码:
&select id=“orderBlog“ resultType=“Blog“
parameterType=”map”&
select id,title,author,content
from blog order by ${orderParam}
仔细观察,内联参数的格式由“#{xxx}”变为了${xxx}。如果我们给参数“orderParam”赋值为”id”,将sql打印出来,是这样的:
select id,title,author,content from
blog order by id
显然,这样是无法阻止sql注入的。在mybatis中,”${xxx}”这样格式的参数会直接参与sql编译,从而不能避免注入攻击。但涉及到动态表名和列名时,只能使用“${xxx}”这样的参数格式,所以,这样的参数需要我们在代码中手工进行处理来防止注入。
结论:在编写mybatis的映射语句时,尽量采用“#{xxx}”这样的格式。若不得不使用“${xxx}”这样的参数,要手工地做好过滤工作,来防止sql注入攻击。
参考来源 .
你可能对这些文章感兴趣.
Copyright & 2014 &&java面试题2173人阅读
Java(11)
数据库(11)
& &1.关于SQL注入
什么是SQL注入:
由于jdbc程序在执行的过程中sql语句在拼装时使用了由页面传入参数,如果用户恶意传入一些sql中的特殊关键字,会导致sql语句意义发生变化,这种攻击方式就叫做sql注入,参考用户注册登录案例。
&&首先看一下以下代码:
String sql = &select* from users where username='& + userName
+ &' and password='& + passWord+&'&;
Connection conn =
Statement state =
conn = JdbcUtil.getConnection();
System.out.println(sql);
state = conn.createStatement();
result = state.executeQuery(sql);
这是一段根据传入用户名,密码查找用户表的代码。
在做用户登录的验证的时候,我们可能会根据用户所填写的用户名和密码在后台拼成一条SQL语句执行,去查用户表:
select* from users where username='张三' and password='小张',如果能查出结果则表示验证成功,允许登录,否则账号或密码错误不允许登录。那么在组成这条语句的过程中会存在一个叫做SQL注入的问题,就是用户在输入用户名或密码的时候填写某些内容使得后台所拼成的SQL语句语义有所变化。
& & & &举个例子,在没有防止SQL的情况下:假如我们知道一个用户叫做张三,但是不知道这个用户的密码是什么,我们依然可以在登录的时候在用户输入框写上:张三'# 然后密码框任意填:njksad。一点击登录,会发现居然能够登录上去。那是为什么呢?
& & 这是因为#在SQL中的意思是注释,那么我们根据上面的情况来分析一下最终所拼成的SQL语句是怎样的,
select* from users where username='张三'#' and password='njksad'
为了让大家能够看清楚上面那条SQL语句,笔者特地加大显示,可以看到 &username='张三'
之后是一个#
那就意味着之后的内容都是注释,也就是可以忽略掉那么这条语句真正发挥作用的部分就是:select* from users where username='张三'
直接变成了一条查找张三 的语句,完全不用经过密码验证。
2.防止SQL注入攻击
那么怎么才能做到防止SQL注入攻击呢?
在上面那段代码中,Statement的对象是用来执行SQL语句的,Statement有一个子类叫做PreparedStatement,可以做到防止SQL注入攻击,接下来我们来看看PreparedStatement有什么特点以及怎么使用:
PreparedStatement是Statement的孩子,不同的是,PreparedStatement使用预编译机制,在创建PreparedStatement对象时就需要将sql语句传入,传入的过程中参数要用?替代,这个过程回导致传入的sql被进行预编译,然后再调用PreparedStatement的setXXX将参数设置上去,由于sql语句已经经过了预编译,再传入特殊值也不会起作用了。
而且PreparedStatement使用了预编译机制,sql语句在执行的过程中效率比Statement要高。
String sql = &select* from users where username=? and password=?&;
Connection conn =
PreparedStatement state =
conn = JdbcUtil.getConnection();
System.out.println(sql);
state = conn.prepareStatement(sql);
state.setString(1, userName);
state.setString(2, passWord);
result = state.executeQuery();
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:38352次
积分:1046
积分:1046
排名:千里之外
原创:64篇
(1)(1)(1)(4)(3)(3)(2)(1)(2)(1)(6)(15)(6)(7)(12)

我要回帖

更多关于 spring 注释注入 的文章

 

随机推荐