占位符,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.所以最终,占位符确实不存在注入问题

  • 9
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值