占位符,SQL注入?

这两天在上课时被同学拿了一段代码问我,这段代码有什么问题,我看了一会说:Connection和PreparedStatement都没关。他说不止这方面的问题,还有sql注入的问题,我就坚决的说使用了占位符不存在sql注入的问题,但是他提出了一种情况,在我看来也很有道理的情况。

pstmt = conn.prepareStatement("delete from user where user.id=?");

pstmt.setString(1, "w");

他认为如果把代码写成这样就有注入问题了

pstmt = conn.prepareStatement("delete from user where user.id=?");
pstmt.setString(1, "w‘ or ‘2‘=‘2");

当时我看了只能告诉他一定不存在注入问题,因为在我的想法中我一直记得的是用占位符能解决注入问题,至于怎么解决的就不知道了,看了上面的代码也很有道理,感觉setString后的sql语句应该是

delete from user where user.id=‘w‘ or ‘2‘=‘2‘;

回到宿舍我专门写了程序测试一下,事实证明并不想我们想的这样,的确使用占位符不存在注入问题,所以解释是在执行的时候把一些字符给转义了,但这个转义的过程是在什么地方转义的呢,把上面的sql语句在mysql控制台上运行一下,查看一下数据看到所有数据都被删除完,那只能解释成在java程序中转义的,于是我就去看java的源代码,发现在java源码中PreparedStatement只是一个接口,而且是没有子类的接口,我就很纳闷,没实现怎么用的?所以一定有实现的地方,去网上查了一下,jdk直提供接口,而具体实现是由数据库厂商实现的,我们用的就是数据库厂商实现的类。于是我就又去查mysql的jar包源码,发现有个PreparedStatement实现了jdk中的PreparedStatement了。里面的setString方法如下实现:

public void setString(int parameterIndex, String x) throws SQLException {
		// if the passed string is null, then set this column to null
		if (x == null) {
			setNull(parameterIndex, Types.CHAR);
		} else {
			StringBuffer buf = new StringBuffer((int) (x.length() * 1.1));
			buf.append(‘\‘‘);

			int stringLength = x.length();

			//
			// Note: buf.append(char) is _faster_ than
			// appending in blocks, because the block
			// append requires a System.arraycopy()....
			// go figure...
			//
			for (int i = 0; i < stringLength; ++i) {
				char c = x.charAt(i);

				switch (c) {
				case 0: /* Must be escaped for ‘mysql‘ */
					buf.append(‘\\‘);
					buf.append(‘0‘);

					break;

				case ‘\n‘: /* Must be escaped for logs */
					buf.append(‘\\‘);
					buf.append(‘n‘);

					break;

				case ‘\r‘:
					buf.append(‘\\‘);
					buf.append(‘r‘);

					break;

				case ‘\\‘:
					buf.append(‘\\‘);
					buf.append(‘\\‘);

					break;

				case ‘\‘‘:
					buf.append(‘\\‘);
					buf.append(‘\‘‘);

					break;

				case ‘"‘: /* Better safe than sorry */
					if (this.usingAnsiMode) {
						buf.append(‘\\‘);
					}

					buf.append(‘"‘);

					break;

				case ‘\032‘: /* This gives problems on Win32 */
					buf.append(‘\\‘);
					buf.append(‘Z‘);

					break;

				default:
					buf.append(c);
				}
			}

			buf.append(‘\‘‘);

			String parameterAsString = buf.toString();

			byte[] parameterAsBytes = null;

			if (!this.isLoadDataQuery) {
				parameterAsBytes = StringUtils.getBytes(parameterAsString,
						this.charConverter, this.charEncoding, this.connection
								.getServerCharacterEncoding(), this.connection
								.parserKnowsUnicode());
			} else {
				// Send with platform character encoding
				parameterAsBytes = parameterAsString.getBytes();
			}

			setInternal(parameterIndex, parameterAsBytes);
		}
	}

到此就告一段落,可以发现在setString时最外面的单引号被转义了,也就是说setString后的sql语句是这样的

delete from user where user.id=\‘w‘ or ‘2‘=‘2\‘;

而且仔细看会发现在setString中是一个字符一个字符的解析,该转义的都已经转义,正如他一句注释中写的Better safe than sorry.所以最终,占位符确实不存在注入问题

时间: 2024-10-31 01:41:05

占位符,SQL注入?的相关文章

记录一下学习PDO技术防范SQL注入的方法

最近学习了使用PDO技术防范SQL注入的方法,在博客里当做一次笔记.若果有新的感悟在来添上一笔,毕竟也是刚开始学习.一. 什么是PDO PDO全名PHP Data Object PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口. PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据. 二.如何去使用PDO防范SQL注入?/防范sql注入这里使用quate()方法过滤特殊字符和通过预处理的一些方式以及bindPar

为什么占位符可以防止sql注入?

先看下面用占位符来查询的一句话 String sql = "select * from administrator where adminname=?"; psm = con.prepareStatement(sql); String s_name ="zhangsan' or '1'='1"; psm.setString(1, s_name); 假设数据库表中并没有zhangsan这个用户名, 用plsql运行sql语句,可以查出来所有的用户名,但是在Java中并

ADO.NET 占位符(防SQL 注入攻击)

当在添加程序中注入攻击时在控制台应用程序中可以这样写: 请输入编号:U006 请输入用户名:无敌 请输入密码:1234 请输入昵称:呵呵 请输入性别:True 请输入生日:2000-1-1 请输入民族:N004');update Users set PassWord='0000';-- 添加成功! 这样,不仅添加成功一条数据,而且数据库中Users表里的所有数据的密码都被修改成了0000.数据被篡改了,数据库被成功注入攻击. 那么我们怎么来防御这种注入攻击呢? 其实很简单,只需要修改下程序,在添

SQl语句中使用占位符的优点

1.增加SQL代码可读性2.占位符可以预先编译,提高执行效率3.防止SQL注入4用占位符的目的是绑定变量,这样可以减少数据SQL的硬解析,所以执行效率会提高不少 绑定变量是Oracle解决硬解析的首要利器,能解决OLTP系统中library cache的过度耗用以提高性能 绑定变量是Oracle解决硬解析的首要利器,能解决OLTP系统中library cache的过度耗用以提高性能.然刀子磨的太快,使起来锋利,却容易折断.凡事皆有利弊二性,因地制宜,因时制宜,全在如何权衡而已.本文讲述了绑定变量

Mybatis 中 sql 语句的占位符 #{} 和 ${}

#{} 表示一个占位符号,通过 #{} 可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换.#{} 可以有效防止   sql注入.#{} 可以接收简单类型值或 pojo 属性值. 如果 parameterType 传输单个简单类型值,#{} 括号中可以是 value 或其它名称. ${} 表示拼接sql串,通过 ${} 可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换,不能防止 sql 注入问

深入Spring Boot:那些注入不了的Spring占位符(${}表达式)

Spring里的占位符 spring里的占位符通常表现的形式是: <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="url" value="${jdbc.url}"/> </bean> 或者 @Confi

C#sql语句如何使用占位符

背景:在程序中,写sql语句时,可能要根据变量的值不同,SQL语句产生相应的变化.比如说存在变量StuName,根据变量值的不同,检索不同姓名的学生记录,这时需用到占位符的知识. 1,{0}占位符,代码如下: 1 string sql=@"select top 1 * from Student where StuName='{0}'"; 2 sql = string.Format(sql, "李四"); 以上代码即是在Student数据表中,查询学生姓名为“李四”的

Spring实战(八)bean装配的运行时值注入——属性占位符和SpEL

前面涉及到依赖注入,我们一般哦都是将一个bean引用注入到另一个bean 的属性or构造器参数or Setter参数,即将为一个对象与另一个对象进行关联. bean装配的另一个方面是指将一个值注入到bean的属性or构造器参数中,通常我们可以将值硬编码在配置类中,XML中也是硬编码(写出所有值). 1.若想避免硬编码,让这些值在运行时再确定,Spring提供了两种在运行时求值的方式. 属性占位符(Property placeholder)--Spring支持将属性定义到外部的属性文件中,然后用占

深入Spring Boot:那些注入不了的 Spring 占位符 ( ${} 表达式 )

Spring里的占位符 spring里的占位符通常表现的形式是: 1 2 3 <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="url" value="${jdbc.url}"/> </bean> 或者