Oracle动态SQL防注入咨询:如何规避注入风险?
Oracle动态SQL注入风险分析与防护方案
一、注入攻击示例
你的代码直接将用户输入的p_search_email、p_search_name拼接到SQL语句中,攻击者可以构造恶意输入篡改SQL逻辑,实现窃取敏感数据或破坏数据库的目的:
1. 窃取top_secret_column敏感数据
假设攻击者构造p_search_email的值为:
'') UNION ALL SELECT account_id, user_name, top_secret_column FROM my_accounts WHERE '1'='1
拼接后的最终SQL会变成:
SELECT account_id, user_name, email FROM my_accounts WHERE 1 = 1 AND UPPER(email) = UPPER(''') UNION ALL SELECT account_id, user_name, top_secret_column FROM my_accounts WHERE '1'='1'')
这条SQL会同时执行原查询和UNION查询,将top_secret_column的敏感内容混入结果返回,攻击者就能直接获取敏感数据。
2. 删除my_important_table表
攻击者构造p_search_email的值为:
'); DROP TABLE my_important_table; --
拼接后的最终SQL会变成:
SELECT account_id, user_name, email FROM my_accounts WHERE 1 = 1 AND UPPER(email) = UPPER('''); DROP TABLE my_important_table; --'')
Oracle会先执行原查询,接着执行DROP TABLE语句(--会注释掉后面的多余字符),直接删除目标业务表。
二、正确的防护方案
使用绑定变量是抵御SQL注入的核心手段,Oracle支持在动态SQL中通过USING子句传递绑定变量,将用户输入的值与SQL逻辑彻底分离。修改后的代码如下:
CREATE TABLE my_accounts (account_id NUMBER, user_name VARCHAR2(30), email VARCHAR2(30), top_secret_column VARCHAR2(30)); --CREATE TABLE my_important_table(id number); DECLARE -- input variables p_cur SYS_REFCURSOR; -- OUT p_exact_search NUMBER := 1; p_search_email VARCHAR2(50) := 'foo@bar.com'; p_search_name VARCHAR2(50) := null; -- v_sql VARCHAR2(4000); v_bind_vars SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST(); -- 存储绑定变量值 FUNCTION get_query_text(p_column VARCHAR2, p_exact_search NUMBER, p_var_idx IN OUT NUMBER) RETURN VARCHAR2 IS v_res VARCHAR2(200); BEGIN p_var_idx := p_var_idx + 1; IF p_exact_search = 1 THEN v_res := ' UPPER(' || p_column || ') = UPPER(:b' || p_var_idx || ')'; ELSE v_res := ' UPPER(' || p_column || ') LIKE ''%'' || UPPER(:b' || p_var_idx || ') || ''%'''; END IF; RETURN chr(10) || ' AND' || v_res; END; BEGIN v_sql := 'SELECT account_id, user_name, email FROM my_accounts WHERE 1 = 1'; DECLARE v_var_idx NUMBER := 0; BEGIN IF p_search_email IS NOT NULL THEN v_sql := v_sql || get_query_text('email', p_exact_search, v_var_idx); v_bind_vars.EXTEND; v_bind_vars(v_var_idx) := p_search_email; END IF; IF p_search_name IS NOT NULL THEN v_sql := v_sql || get_query_text('user_name', p_exact_search, v_var_idx); v_bind_vars.EXTEND; v_bind_vars(v_var_idx) := p_search_name; END IF; --dbms_output.put_line(v_sql); IF v_bind_vars.COUNT > 0 THEN OPEN p_cur FOR v_sql USING v_bind_vars(1), v_bind_vars(2); -- 根据实际参数数量调整 ELSE OPEN p_cur FOR v_sql; END IF; CLOSE p_cur; END; END;
防护逻辑说明
- 绑定变量占位符:用
:b1、:b2这类占位符替代直接拼接用户输入的值,确保输入内容只会被当作参数值解析,不会被当作SQL语句的一部分执行。 - 绑定变量集合:用
SYS.ODCIVARCHAR2LIST存储所有绑定变量的值,统一通过USING子句传递给动态SQL,避免零散传递的混乱。 - 模糊匹配处理:将
%直接写在SQL语句中,绑定变量仅传递用户输入的原始值,既实现模糊查询需求,又杜绝拼接风险。
这种方式彻底切断了攻击者通过输入篡改SQL逻辑的可能,同时还能提升SQL语句的执行效率(Oracle会缓存绑定变量SQL的执行计划)。
内容的提问来源于stack exchange,提问作者MrGoodman
相关产品推荐
相关产品推荐

