SQL日期注入本质是字符串拼接导致的通用SQL注入,须用参数化查询配合数据库原生日期函数(如TO_DATE、STR_TO_DATE)并显式指定格式,辅以应用层格式与范围校验。

SQL日期注入风险本质是字符串拼接
只要把用户输入直接拼进SQL语句的WHERE date_col = '2024-01-01'这类字符串里,就存在注入风险——攻击者可以传入'2024-01-01' OR 1=1 --绕过条件。这不是日期格式的问题,而是未参数化导致的通用SQL注入。
用数据库原生日期函数替代字符串拼接
各数据库都提供安全的日期解析函数,它们接受字符串但内部做类型校验和上下文隔离,不会被当作SQL代码执行:
- PostgreSQL:
TO_DATE('2024-01-01', 'YYYY-MM-DD')或DATE '2024-01-01'(字面量语法) - MySQL:
STR_TO_DATE('2024-01-01', '%Y-%m-%d')或DATE('2024-01-01') - SQL Server:
CONVERT(DATE, '2024-01-01')或TRY_CONVERT(DATE, @input)(推荐,失败返回NULL而非报错) - Oracle:
TO_DATE('2024-01-01', 'YYYY-MM-DD')
注意:这些函数仍需配合参数化查询使用——函数只是把字符串转成日期类型,不能替代占位符。错误写法:"WHERE date_col = TO_DATE('" + userInput + "', 'YYYY-MM-DD')";正确写法:"WHERE date_col = TO_DATE(?, 'YYYY-MM-DD')"(JDBC)或对应语言的绑定参数方式。
别依赖CAST或CONVERT自动推断格式
像CAST('2024/01/01' AS DATE)在不同数据库、甚至不同区域设置下行为不一致。SQL Server可能按MDY或DMY解析,PostgreSQL默认只认ISO格式。显式指定格式能避免隐式转换失败或误判:
- MySQL中
CAST('01/02/2024' AS DATE)可能变成2024-01-02或报错,取决于sql_mode - PostgreSQL中
CAST('01-02-2024' AS DATE)会因datestyle配置不同而解析为2024-01-02或2024-02-01 - 始终用带格式模板的函数(如
TO_DATE、STR_TO_DATE),不依赖自动推断
应用层验证 + 数据库函数双保险
数据库函数能防注入,但不保证业务逻辑合理。比如用户传'9999-99-99',TO_DATE可能成功转成无效日期(取决于数据库严格模式)。所以:
- 应用层先用正则或标准库(如Python
datetime.strptime、JavaLocalDate.parse)校验格式和范围 - 再把已确认合法的字符串交给数据库函数处理,避免无效输入打到DB层
- 对模糊输入(如“上个月”、“本周一”)不要在SQL里用
CASE WHEN硬编码,应由应用计算出确切日期后传参
真正难防的不是格式错,是业务语义错——比如查“未来30天订单”,结果用户输了个负数当偏移量。这类问题必须在应用逻辑里拦截,数据库函数只负责安全转换。

















