我们正在尝试验证用户提供的 SQL“where”片段没有任何“写入”副作用或其他 SQL 注入。我们通过在具有只读访问权限的 SQL 连接上运行命令并捕获任何异常来实现此目的。这适用于单个命令,但对于复合语句,我们看到 JdbcTemplate 记录有关 SQLException 的调试消息,但不会引发异常。
这将抛出 SQLException:
jdbcTemplate.execute("drop table students;")
这不会:
jdbcTemplate.execute("select 1 where 1=1; drop table students;")
尽管它会在 DEBUG 日志中记录相同的错误。以下是运行第二条语句时的调试级别日志:
SqlVerifierController : Running Sql: select count(*) as numResults from dbo.tbtCloudDialingToImport where 1=1;drop table students;
jdbc.core.JdbcTemplate : Executing SQL statement [select count(*) as numResults from dbo.tbtCloudDialingToImport where 1=1;drop table students;]
jdbc.datasource.DataSourceUtils : Fetching JDBC Connection from DataSource
jdbc.internals.SQLServerStatement : SQLServerStatement:10 created by (ConnectionID:1 ClientConnectionId: 93203efc-9061-4f6e-9501-61a788096f57)
jdbc.internals.SQLServerStatement : SQLServerStatement:10 Executing (not server cursor) SELECT 1
jdbc.internals.SQLServerResultSet : SQLServerResultSet:10 created by (SQLServerStatement:10)
jdbc.internals.SQLServerStatement : SQLServerStatement:11 created by (ConnectionID:1 ClientConnectionId: 93203efc-9061-4f6e-9501-61a788096f57)
jdbc.internals.SQLServerStatement : SQLServerStatement:11 Executing (not server cursor) select count(*) as numResults from dbo.tbtCloudDialingToImport where 1=1;drop table students;
jdbc.internals.SQLServerResultSet : SQLServerResultSet:11 created by (SQLServerStatement:11)
jdbc.internals.SQLServerException : *** SQLException: com.microsoft.sqlserver.jdbc.SQLServerException: Cannot drop the table 'students', because it does not exist or you do not have permission. Msg 3701, Level 11, State 5, Cannot drop the table 'students', because it does not exist or you do not have permission.
SqlVerifierController : Running Sql: select top(2) TRIM(AccountNumber) from dbo.tbtCloudDialingToImport where 1=1;drop table students;
jdbc.core.JdbcTemplate : Executing SQL query [select top(2) TRIM(AccountNumber) from dbo.tbtCloudDialingToImport where 1=1;drop table students;]
jdbc.datasource.DataSourceUtils : Fetching JDBC Connection from DataSource
jdbc.internals.SQLServerStatement : SQLServerStatement:12 created by (ConnectionID:1 ClientConnectionId: 93203efc-9061-4f6e-9501-61a788096f57)
jdbc.internals.SQLServerStatement : SQLServerStatement:12 Executing (not server cursor) select top(2) TRIM(AccountNumber) from dbo.tbtCloudDialingToImport where 1=1;drop table students;
jdbc.internals.SQLServerResultSet : SQLServerResultSet:12 created by (SQLServerStatement:12)
SQLServerResultSetMetaData : SQLServerResultSetMetaData:2 created by (SQLServerResultSet:12)
jdbc.internals.SQLServerException : *** SQLException: com.microsoft.sqlserver.jdbc.SQLServerException: Cannot drop the table 'students', because it does not exist or you do not have permission. Msg 3701, Level 11, State 5, Cannot drop the table 'students', because it does not exist or you do not have permission.
有关“无法删除表‘学生’”的类似日志记录出现在 SQL Server 计算机中。
在 jdbcTemplate 上将“ignoreWarnings”设置为 false 没有任何效果。
jdbcTemplate的版本来自org.springframework:spring-jdbc:5.3.1
我们检查了 JdbcTemplte、连接,我们尝试了执行 sql 语句的不同方法,我们检查了结果集,没有任何迹象表明复合语句中存在 sql 异常。
如果复合语句在语法上不正确,那么我们将得到一个异常。这将引发异常:
jdbcTemplate.execute("select 1 where 1=1; bogus sql statement;")
我们希望无权运行的有效复合语句抛出异常,或者至少给我们一些除了捕获调试日志之外还存在异常的反馈。
我们发现以下查询将为每个 sql 语句返回一个结果集(因此在本例中为 2 个,“select 1”和“drop table Students”),我们可以检查每个结果集以查看是否有错误:
BEGIN TRY
SELECT 1; drop table students;
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber
, ERROR_SEVERITY() AS ErrorSeverity
, ERROR_STATE() AS ErrorState
, ERROR_PROCEDURE() AS ErrorProcedure
, ERROR_LINE() AS ErrorLine
, ERROR_MESSAGE() AS ErrorMessage
;
END CATCH
并且可以使用以下java语句轻松查询:
Map<String,Object> resultSets = jdbcTemplate.call(con -> con.prepareCall(sql), new ArrayList<>());