You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

防护逻辑说明

  1. 绑定变量占位符:用:b1、:b2这类占位符替代直接拼接用户输入的值,确保输入内容只会被当作参数值解析,不会被当作SQL语句的一部分执行。
  2. 绑定变量集合:用SYS.ODCIVARCHAR2LIST存储所有绑定变量的值,统一通过USING子句传递给动态SQL,避免零散传递的混乱。
  3. 模糊匹配处理:将%直接写在SQL语句中,绑定变量仅传递用户输入的原始值,既实现模糊查询需求,又杜绝拼接风险。

这种方式彻底切断了攻击者通过输入篡改SQL逻辑的可能,同时还能提升SQL语句的执行效率(Oracle会缓存绑定变量SQL的执行计划)。

内容的提问来源于stack exchange,提问作者MrGoodman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 13:13:13