只要你学JDBC,基本上所有的人都会和你说,Statement不能防止SQL注入, PreparedStatement能够防止SQL注入.
基本上参加工作了一段时间之后还是这么认为的, 没错, 这句是没有问题的, 但到底如何进行SQL注入?怎么直观的去了解SQL注入?这还是需要花一定的时间去实验的.
前提:以下的测试都是在一种理想环境下
首先准备好数据库环境, 以下是数据库的schema:
create database java_mysql;
use java_mysql;
drop table if exists pstest;
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 = null;
Statement stmt = null;
// name很强大, 传入了这么多东西
String name = "Tom';delete from pstest;select * from pstest where name='Tom";
String sql = createSql(name); // SQL
System.out.println(sql);
try {
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 + "'";
}
return sql;
}
}
数据库连接的URL为:
"jdbc:mysql://localhost:3306/java_mysql";
其实上面的意图很简单:
Tom';delete from pstest;select * from pstest where name='Tom
就是想先执行一条SQL查询语句,然后把表的数据删除。
这只是理想环境. 实际上要想传入这么复杂的数据, 真的很难想象
这里将URL单独拎出来是有作用的, 继续看下面
Run一下StatementTest. 会发现报异常了:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'delete from pstest;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';delete from pstest;select * from pstest where name='Tom';
上面的SQL到底做了什么呢?
我们先观察一下:第一条是查询SQL, 第二条是delete, 第三条是查询SQL,其实第一条和第三条是一样的.
为了直观的看上面SQL的执行效果, 我们再次执行下最开始的schema.sql
这时候数据库有6条数据
mysql> select * from pstest;
+----+------+------+
| id | name | age |
+----+------+------+
| 1 | Tom | 23 |
| 2 | Tom1 | 23 |
| 3 | Tom2 | 23 |
| 4 | Tom3 | 23 |
| 5 | Tom4 | 23 |
| 6 | Tom5 | 23 |
+----+------+------+
执行一下
select id, name, age from pstest where name ='Tom';delete from pstest;select * from pstest where name='Tom';
mysql> select id, name, age from pstest where name ='Tom';delete from pstest;select * from pstest where name='Tom';
+----+------+------+
| id | name | age |
+----+------+------+
| 1 | Tom | 23 |
+----+------+------+
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 = null;
PreparedStatement ps = null;
ResultSet rs = null;
String sql = "select id, name, age from pstest where name = ? ";
try {
con = DBConn.getConnection();
ps = con.prepareStatement(sql);
ps.setString(1, "Tom';delete from pstest;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下配置
[mysqld]
log=MySQL_Log # 在这里加上日志名称
这时候会在MySQL/MySQL Server 5.1/Data/目录下生成MySQL_Log文件, 里面记录的就是日志了.
好了,回到正题,看一下刚刚PreparedStatementTest执行的SQL,在MySQL_Log中查看
120719 15:54:25 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\';delete from pstest;select * from pstest where name=\'Tom'
23 Quit
重点是最后一条SQL.
因为数据库中的数据都还在,我们就直接执行这条SQL
select id, name, age from pstest where name = 'Tom\';delete from pstest;select * from pstest where name=\'Tom'
mysql> select id, name, age from pstest where name = 'Tom\';delete from pstest;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)) {
return;
}
createTable("testBug33678", "(field1 INT)");
// allowMultiQueries=true设置
Connection multiConn = getConnectionWithProps("allowMultiQueries=true");
Statement multiStmt = multiConn.createStatement();
try {
multiStmt.setFetchSize(Integer.MIN_VALUE);
// 一次性执行多条SQL语句
multiStmt
.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");
// 以下代码省略...
}
}
分享到:
相关推荐
Statement适合静态SQL,而PreparedStatement适合参数化SQL,能有效防止SQL注入。 4. 执行SQL:调用Statement或PreparedStatement的executeQuery()或executeUpdate()方法执行SQL。 5. 处理结果集:如果执行的是查询...
SQL注入是一种常见的网络安全威胁,它发生在应用程序不恰当地处理用户输入数据时,导致攻击者能够构造恶意SQL语句...同时,对于开发人员来说,了解如何测试和修复SQL注入漏洞也至关重要,以确保用户的隐私和数据安全。
### SQL注入检测与判断详细过程 #### 一、SQL注入简介 SQL注入是一种常见的Web应用程序安全漏洞,攻击者可以通过向数据库提交恶意SQL代码来获取敏感数据、修改数据或执行其他非法操作。随着网络安全意识的提高和...
SQL注入是一种常见的网络安全漏洞,它发生在应用程序不恰当地构建SQL查询时,允许攻击者通过输入恶意数据来操纵数据库。在上述描述中,我们看到两种基本的SQL注入技术:利用注释符号和分解查询条件。 首先,让我们...
Java的安全特性可以帮助保护用户数据,防止SQL注入等攻击。同时,使用HTTPS协议保证数据传输的安全,确保用户隐私不被泄露。 总结来说,"网上书店 java sql"这个项目涵盖了Java Web开发的多个核心方面:使用Java...
- 使用PreparedStatement可以防止SQL注入攻击,并提高查询效率。 7. **事务管理**: - JDBC提供对数据库事务的支持,通过`Connection`对象的`setAutoCommit(false)`来禁用自动提交,然后手动调用`commit()`或`...
“扫描工具”则指出这是一个自动化测试工具,可以遍历可能的输入,寻找可能导致SQL注入的弱点。 在压缩包文件“5d5ee1ca53034cf98f06cdf3dc9cc02c”中,虽然没有提供具体的文件名,但通常会包含源代码文件、README...
第2章 SQL注入测试 21 2.1 概述 22 2.2 寻找SQL注入 22 2.2.1 借助推理进行测试 22 2.2.2 数据库错误 29 2.2.3 应用响应 38 2.2.4 SQL盲注 42 2.3 确认SQL注入 45 2.3.1 区分数字和字符串 46 2.3.2 内联SQL注入 46 ...
标题提到的是“mysqlJava driver 5.1.7 for win”,这意味着我们讨论的是MySQL Connector/J 5.1.7版本,这是一个专门为Windows操作系统设计的Java数据库连接器。 MySQL Connector/J是MySQL官方提供的JDBC(Java ...
3. **MySQL的SQL注入**:由于标签中提到了MySQL,所以这部分可能详述MySQL数据库中的SQL注入漏洞,包括其特有的语法和可能导致的攻击场景。 4. **PHP与SQL注入**:PHP是常见的Web开发语言,因此教程可能专门讨论PHP...
第2章 SQL注入测试 2.1 概述 2.2 寻找SQL注入 2.2.1 借助推理进行测试 2.2.2 数据库错误 2.2.3 应用响应 2.2.4 SQL盲注 2.3 确认SQL注入 2.3.1 区分数字和字符串 2.3.2 内联SQL注入 ...
此外,执行SQL语句时,可以使用PreparedStatement以防止SQL注入,并提高查询性能。 压缩包中的"java各种数据库的连接及优化.wps"可能包含关于如何优化数据库连接、使用连接池、处理批处理以及查询优化等更深入的...
1. **不使用预编译的PreparedStatement对象**:在Java Web开发中,推荐使用PreparedStatement来处理SQL查询,因为它可以防止SQL注入。当使用字符串拼接方式构建SQL语句时,如`"select * from foodinfo where foodId ...
还可以使用PreparedStatement进行参数化查询,以防止SQL注入攻击: ```java String query = "SELECT * FROM Employees WHERE id = ?"; PreparedStatement pstmt = conn.prepareStatement(query); pstmt.setInt(1, ...
3. **参数化查询**:使用预编译语句可以有效防止SQL注入攻击,提高安全性。 4. **事务管理**:对于批量操作,建议在事务中进行,以保证数据的一致性和完整性。 #### 五、扩展阅读 - **JDBC规范文档**:了解JDBC...
在本示例中,我们将探讨如何使用JDBC(Java Database Connectivity)工具类与MySQL数据库建立连接,并实现登录功能,同时重点介绍如何利用PreparedStatement防止SQL注入攻击。 首先,JDBC是Java语言访问数据库的...
MySQL Connector/J是MySQL数据库与Java应用程序之间的重要桥梁,它是一个实现了Java Database Connectivity (JDBC) API的驱动程序,使得Java开发者能够方便地在MySQL数据库上执行SQL查询和操作。在这个"mysql-...
某些数据库系统(如MySQL的`PREPARE STATEMENT`)提供了内置的SQL注入防护。同时,可以使用安全中间件如OWASP Java Encoder库来转义HTML、JavaScript和SQL等特殊字符。 ### 6. 避免硬编码SQL 尽量避免在JSP页面中...
`Statement`用于执行静态SQL,而`PreparedStatement`则允许预编译的SQL语句,提高性能并防止SQL注入。 6. **结果集处理**: 执行查询后,会返回一个`ResultSet`对象,你可以遍历它来获取查询结果。 7. **关闭资源**...
5. **预编译的SQL语句**:`PreparedStatement`接口提供了预编译的SQL语句,可以提高性能,防止SQL注入攻击,并方便多次执行相同SQL时的参数绑定。 在Android平台上,由于安全性和资源限制,直接使用JDBC并不常见。...