JdbcTemplate防止sql注入攻击的源码解析
概述
使用spring中org.springframework.jdbc.core.JdbcTemplate进行sql查询时,如果调用的是query(String sql, RowMapper<T> rowMapper)方法,是可以被sql注入攻击的。
会发生sql注入的查询
query(String sql, RowMapper<T> rowMapper)
源码解析
@Override public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException { return result(query(sql, new RowMapperResultSetExtractor<>(rowMapper))); }
最后执行:
class QueryStatementCallback implements StatementCallback<T>, SqlProvider { @Override @Nullable public T doInStatement(Statement stmt) throws SQLException { ResultSet rs = null; try { rs = stmt.executeQuery(sql); return rse.extractData(rs); } finally { JdbcUtils.closeResultSet(rs); } } @Override public String getSql() { return sql; } }
可以看到,最终执行时使用的是Statement接口,是会发生sql注入的。
不会发生sql注入的查询
query(String sql, @Nullable Object[] args, RowMapper<T> rowMapper)
源码解析
@Override public <T> List<T> query(String sql, @Nullable Object[] args, RowMapper<T> rowMapper) throws DataAccessException { return result(query(sql, args, new RowMapperResultSetExtractor<>(rowMapper))); }
调用:
@Override @Nullable public <T> T query(String sql, @Nullable Object[] args, ResultSetExtractor<T> rse) throws DataAccessException { return query(sql, newArgPreparedStatementSetter(args), rse); }
继续调用:
@Override @Nullable public <T> T query(String sql, @Nullable PreparedStatementSetter pss, ResultSetExtractor<T> rse) throws DataAccessException { return query(new SimplePreparedStatementCreator(sql), pss, rse); }
最后执行的代码是:
return execute(psc, new PreparedStatementCallback<T>() { @Override @Nullable public T doInPreparedStatement(PreparedStatement ps) throws SQLException { ResultSet rs = null; try { if (pss != null) { pss.setValues(ps); } rs = ps.executeQuery(); return rse.extractData(rs); } finally { JdbcUtils.closeResultSet(rs); if (pss instanceof ParameterDisposer) { ((ParameterDisposer) pss).cleanupParameters(); } } } });
可以发现,最终执行时使用的是PreparedStatement接口。PreparedStatement可以使用占位符,是预编译的,所以可以预防sql注入攻击。
环境说明
spring-jdbc版本:5.0.10.RELEASE