sql 注入原理 statement preparedstatement
http://blog.sina.com.cn/s/blog_6a384fce0100n95f.html
------以下转自 ikon.iteye.com/blog/1132255
一、我们先来看一下sql的执行过程:
在Oracle里执行一个SQL语句,一般都要经过下面几个步骤:
Create a Cursor 创建游标;
Parse the Statement 解析语句;
Bind Any Variables 绑定变量;
Run the Statement 运行语句;
Close the Cursor 关闭游标;
如果是一个查询SQL,则还要经过下面的步骤:
Describe Results of a Query 描述查询的结果集;
Define Output of a Query 定义查询的输出数据;
Fetch Rows of a Query 获取查询出来的行。
二、SQL解析过程
从上面的步骤可以看出,每执行一个SQL,都需要对它进行解析(Parse),而一个解析过程,需要完成下面的工作:
语法检查,验证它是否是合法的语句,有没有语法错误;
语义检查,实现数据字典的查找,以验证是否符合表和列的定义,类型是否正确;
(如果是CBO优化模式,关于CBO,请看后面Oracle的优化器一章)收集参考对象的统计;
在所要求的对象上获取语法分析锁,使得在语句的语法分析过程中不改变这些对象的定义;
检查用户的权限是否足够;
从许多可能的执行路径中选择此语句最佳的执行计划;
将它装入共享SQL区;
生成语句的编译版本(P-CODE)。
解析是一个昂贵的操作,因为解析过程中需要消耗许多资源,而且费时,正因为如此,Oracle创造了共享池的概念,共享池会自动将解析过的SQL缓存起来,以后碰到相同的SQL,就不用再解析了,这样可以大大提高SQL的执行速度。
三、 缓存SQL的原理
ORACLE执行SQL语句时,先将SQL语句的字串通过一个hash算法得出一个hash值,然后检查共享池中是否已存在这个哈希值,若有就用已缓存的执行计划来执行这个语句(即缓存命中,后面我们会提到共享池的命中率,就是这个概念),若没有(即缓存缺失)则需进行解析。
由于Oracle是通过SQL字符的hash值来判断是否为相同的SQL语句,因此,如果你的SQL有一点小小的变换,在Oracle看来,就是另外一个SQL了,会对它进行重新解析。
例如:
- select id, name from members where id = 1403
-
select id, name From members where id = 1403
-
select name, id from members where id = 1403
这三条SQL在Oracle看来就是三条不同的SQL。
绑定变量
在大部分时候,sql语句里有一些经常会变化的值。例如:
- select id, name from members where id = 1207
-
select id, name from members where id = 1208
-
select id, name from members where id = 1209
前面说过了,这样的SQL其实是三条不同的SQL,因为它们的字符明显不一样。那我们该怎么样才能让它们成为同一条SQL呢?可以通过绑定变量来实现。
下面是一条含绑定变量的sql 语句:
- select id, name from members where id = :member_id
这样不管member_id如何变化,Oracle都会认为这条SQL是同一条,就可以节省解析的成本了。
那么,在java开发中,怎么使用绑定变量呢?注意,不要认为下面的代码是在使用绑定变量:
- Statement stmt=conn.createStatement();
- String member_id=member.id;
-
String sql="select id,name from members where id ="+member_id;
- stmt.executeQuery(sql);
上面的例子里,当member.id的值为1207时,我们传给stmt的SQL实际上是:
- select id, name from members where id = 1207
当member.id的值为1208时,就是:
- select id, name from members where id = 1208
它们在Oracle看来仍然是不同的SQL。
其实,在java中使用绑定变量非常简单,只需要使用PreparedStatement对象就可以了。如下:
- String sql="select id,name from members where id =?";
- PreparedStatement pstmt=conn.createStatement(sql);
-
pstmt.setString(1,member.id);
这样,PreparedStatement会自动把这条SQL在传给Oracle时转化为类似下面的SQL:
- select id, name from members where id = :member_id
这样就实现了绑定变量,它只需解析一次,不管member.id如何变化,都不用再做解析了。
分享到:
相关推荐
在IT领域,尤其是在Java编程中,SQL注入是一个重要的安全问题,而PreparedStatement是解决这一问题的有效手段之一。批量插入则是提高数据库操作效率的关键技术。今天我们就来深入探讨这些知识点。 首先,我们来理解...
在IT领域,尤其是在Java编程中,SQL注入是一个重要的安全问题,而PreparedStatement是解决这一问题的有效手段之一。批量插入则是提高数据库操作效率的关键技术。今天我们将深入探讨这两个知识点。 首先,让我们来...
Statement和PreparedStatement之间的区别 Statement和PreparedStatement...结论:在 JDBC 应用中,建议使用PreparedStatement对象来代替Statement对象,以提高执行速度、避免SQL注入攻击和提高代码可读性和可维护性。
当我们处理大量重复的SQL操作时,使用`PreparedStatement`可以避免SQL注入等问题,同时提升性能。这篇博客可能是探讨如何在实际运行中获取`PreparedStatement`最终执行的SQL语句,这对于调试和分析数据库操作非常有...
如果使用 PreparedStatement 来代替 Statement 来执行 SQL 语句,其后只是输入参数,SQL 注入攻击手段将无效。这是因为 PreparedStatement 不允许在不同的插入时间改变查询的逻辑结构,大部分的 SQL 注入已经挡住了...
正确的方法是使用参数化查询,例如预编译的`PreparedStatement`,以防止SQL注入: ```java String sql = "SELECT * FROM users WHERE id=?"; PreparedStatement pstmt = connection.prepareStatement(sql); pstmt....
Java开发人员使用JDBC(Java Database Connectivity)连接到Oracle数据库时,应该优先使用`PreparedStatement`和`CallableStatement`,而不是`Statement`。这是因为前两者提供了参数化查询的支持,能够有效抵御SQL...
SQL注入是一种常见的网络安全威胁,它允许攻击者通过输入恶意的SQL代码来操纵数据库,获取、修改或删除敏感数据。为了防止SQL注入,开发者需要采取一系列的预防措施,确保应用程序的安全性。以下是一些核心的解决...
PreparedStatement preState = conn.prepareStatement(sql); preState.setString(1, userName); preState.setString(2, password); ResultSet rs = preState.executeQuery(); 2. 采用正则表达式 可以使用正则表达式...
- 使用预编译语句(PreparedStatement):这是防止SQL注入最常用的方法。预编译语句会将用户输入与SQL语句分离,确保即使输入含有恶意代码,也不会被执行。例如: ```java String query = "SELECT * FROM users ...
例如,使用 PreparedStatement 代替 Statement,可以避免 SQL 注入攻击。预编译语句还可以提高性能和可维护性。 其次,使用正则表达式可以检测 SQL meta-characters,从而防止恶意代码的注入。例如,可以使用正则...
某些数据库系统(如MySQL的`PREPARE STATEMENT`)提供了内置的SQL注入防护。同时,可以使用安全中间件如OWASP Java Encoder库来转义HTML、JavaScript和SQL等特殊字符。 ### 6. 避免硬编码SQL 尽量避免在JSP页面中...
Java-JDBC【之】JDBC概述、获取连接、SQL注入问题与解决、查询...3.SQL注入问题与解决(Statement 、PreparedStatement) 3.1.模拟SQL注入 3.2.PreparedStatement解决 3.3.Statement 与 PreparedStatement 4.完整源码
在实际开发过程中,如果使用普通的`Statement`来执行SQL语句,由于其直接拼接字符串的方式,很容易受到SQL注入的攻击。而`PreparedStatement`则通过预编译SQL语句并在执行时动态填充参数的方式来避免这一问题。这种...
1. **预编译SQL(PreparedStatement)**:使用PreparedStatement可以有效地防止SQL注入,因为它自动转义特殊字符,例如: ```java String username = request.getParameter("username"); PreparedStatement pstmt...
PreparedStatement pstmt = conn.prepareStatement("SELECT * from users WHERE username=?"); pstmt.setString(1, username); ``` 七、SQL注入的检测 要检测SQL注入,需要对Web应用程序的日志进行分析,检查是否...
1. **预编译语句(PreparedStatement)**:使用PreparedStatement可以有效地防止SQL注入,因为它会将用户输入的数据作为参数处理,而不是直接拼接到SQL语句中。例如: ```java String sql = "SELECT * FROM users ...
使用预编译的SQL语句(例如PreparedStatement)是防止SQL注入的最佳实践。这种方式将SQL语句与用户输入的数据分离,确保即使用户输入恶意代码,也不会影响到查询结构。例如: ```java String query = "SELECT * ...
### JSP如何防范SQL注入攻击 #### 背景介绍 在进行Web开发的过程中,安全性是不容忽视的重要一环。特别是在使用动态语言如Java Server Pages (JSP)时,开发者必须时刻警惕各种潜在的安全威胁,其中SQL注入是最常见...
在 Java 语言中,可以使用 PreparedStatement 对象来防御 SQL 注入攻击。例如: ```java String sql = "SELECT * FROM users WHERE username = ? and password = ?"; PreparedStatement pstmt = conn.prepare...