sqlscript 不支持 preparedstatement 机制,所有参数在存储过程定义时静态拼接进执行计划;防注入必须依赖输入层白名单校验或系统视图验证,而非语法层面防护。

SQLScript里根本不存在“预编译”这个机制
直接说结论:SQLScript 不支持类似 JDBC 的 PreparedStatement 机制,也没有运行时参数绑定接口。所谓“预编译的 SQLScript”,是常见误解——CREATE PROCEDURE 中的 USING 子句、或调用时传入的参数,全部在**存储过程定义阶段就被静态拼接进执行计划**,不经过语句解析器的二次校验。
这意味着:如果你在 EXEC 'SELECT * FROM ' || :table_name 这类动态拼接中直接拼入用户输入,哪怕用了 :param 占位符,也照样触发 SQL 注入。
真正能防注入的只有两种方式:白名单校验 + 系统视图过滤
防御必须落在输入校验层,而非指望 SQLScript 自带防护。关键不是“怎么写 SQLScript”,而是“怎么让输入进不来非法值”。
- 对表名、列名、排序字段等元数据类输入,**强制走白名单映射**:
IF :input_table NOT IN ('CUSTOMERS', 'ORDERS', 'PRODUCTS') THEN SIGNAL SQL_ERROR_CODE 10001 SET MESSAGE_TEXT = 'Invalid table name'; END IF; - 若需动态对象名,优先查系统视图做存在性验证:
SELECT COUNT(*) FROM SYS.TABLES WHERE SCHEMA_NAME = 'MYSCHEMA' AND TABLE_NAME = :input_table—— 注意这里:input_table必须先经正则清洗(只允许字母、数字、下划线) - 避免使用
EXEC或EXECUTE IMMEDIATE拼接任意字符串;改用静态 SQL + 条件分支:IF :mode = 'TOP10' THEN SELECT * FROM SALES ORDER BY AMOUNT DESC LIMIT 10; ELSE SELECT * FROM SALES; END IF;
应用层传参 ≠ SQLScript 安全边界
很多开发者以为从 ABAP 或 Node.js 传入 :user_id 参数就安全了,其实危险发生在更前端:
- ABAP 调用
CALL DATABASE PROCEDURE时,如果USING的参数来自cl_http_request=>get_form_field( ),且未校验格式,漏洞已存在 - Node.js 使用
@sap/hana-client执行CALL MY_PROC(:p1, :p2),若p1是未经处理的 URL 查询参数,MY_PROC内部仍可能用它拼接动态 SQL -
SESSION_CONTEXT()返回值不可信——它可被恶意客户端伪造,不能作为权限或对象名依据
哪些场景下“看似安全”实则高危
这些写法常被误认为防注入,但实际都失败:
-
SELECT * FROM "MYTABLE" WHERE ID = :id—— 字面量安全,但若:id是通过EXEC 'SELECT * FROM ' || :user_table间接控制表名,整条链路崩塌 - 用
REPLACE_REGEXPR过滤单引号:REPLACE_REGEXPR('\'|;|--|/\*|\*/' IN :input WITH '' GLOBAL)—— 正则漏掉 Unicode 变体、宽字节绕过、注释嵌套等,且破坏合法输入(如人名 O'Connor) - 存储过程加
SECURITY DEFINER—— 这只影响权限上下文,和注入无关;攻击者照样能删库,只要语句语法合法
最易被忽略的一点:HANA 的 SQLScript 错误信息默认暴露表结构和函数签名,开启 sqlscript_error_log = true 会把完整报错堆栈打到日志,给攻击者提供探测依据。生产环境务必关掉。











