概述
使用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