Oracle安全使用SQL脚本

时间:2016-02-11 12:40:57

标签: sql oracle plsql

我尝试使用this link使用安全的SQL脚本,但是当动态绑定变量的数量越来越多时,代码似乎很笨拙。请检查此代码并提出降低复杂性的想法。

根据下面的代码,您可以看到这三个变量(ZONE_CODE_STR,ACTIVE_STR和LOGICAL_ENV_STR)作为查询的参数,当值到来时我使用它们或者用空字符串替换它们。但问题是当我想要的时候添加一个参数,IF-ELSE逻辑变得太复杂。如果我想再增加一个新的动态变量,请帮我找一个简单的方法。

代码示例:

    -- APPLICATION VARIABLES STARTS HERE
    ZONE_CODE_STR VARCHAR2(100);
    ZONE_CODE_FLAG VARCHAR2(20);
    ACTIVE_STR VARCHAR2(100);
    ACTIVE_FLAG VARCHAR2(20);
    LOGICAL_ENV_STR VARCHAR2(100);
    LOGICAL_ENV_FLAG VARCHAR2(20);
    QUERY_STR VARCHAR2(4000);
    -- APPLICATION VARIABLES END HERE
BEGIN



-- APPLICATION LOGIC STARTS HERE
  ZONE_CODE_STR  := ' AND ZONE_ENV_CODE  IN (: IN_ZONE_ENV_CODE)';
  ZONE_CODE_FLAG := '@@ZONE_CODE@@';
  LOGICAL_ENV_STR  := ' AND LOGICAL_DB_ENVIRONMENT.ZONE_ENV_CODE IN(: IN_ZONE_ENV_CODE)';
  LOGICAL_ENV_FLAG := '@@LOGICAL_ENV@@';
  ACTIVE_STR     := ' AND ACTIVE  =: IN_ACTIVE';
  ACTIVE_FLAG    := '@@ACTIVE@@';
  QUERY_STR  :='SELECT
RES_DETAIL.FRAME_NAME,RES_DETAIL.LISTENER_PORT,
RES_DETAIL.PROPERTY_NAME,RES_DETAIL.PROPERTY_VALUE,RES_DETAIL.IP_ADDRESS,
TEST_APP_ENTRIES.*,
TEST_APP_WEB_SERVER_TYPE.APP_WEB_SERVER_TYPE_NAME,
TEST_OPERATION_TYPE.OPERATION_TYPE_NAME,
TEST_SINGLE_SIGN_ON.SINGLE_SIGN_ON_NAME,TEST_APP_REALM_ENTRIES.WARE_ID,TEST_APP_REALM_ENTRIES.RESOURCE_FILTER,
TEST_APP_REALM_ENTRIES.PROTECTION_STATUS, TEST_APP_REALM_ENTRIES.AUTHENTICATION_TYPE_ID,
TEST_AUTHENTICATION_TYPE.AUTHENTICATION_TYPE_NAME,
TEST_APP_REALM_ENTRIES.ROLE
FROM 
  (
  SELECT * FROM TEST_APP_ENTRIES WHERE APP_EXT_CODE =: IN_APP_EXT_CODE
@@ZONE_CODE@@
@@ACTIVE@@
  )TEST_APP_ENTRIES
  INNER JOIN
  TEST_APP_REALM_ENTRIES
ON
  TEST_APP_ENTRIES.WAE_ID = TEST_APP_REALM_ENTRIES.WAE_ID

INNER JOIN
  TEST_OPERATION_TYPE
ON
  TEST_APP_ENTRIES.OPERATION_TYPE_ID = TEST_OPERATION_TYPE.OPERATION_TYPE_ID
INNER JOIN
  TEST_APP_WEB_SERVER_TYPE
ON
  TEST_APP_ENTRIES.APP_WEB_SERVER_TYPE_ID = TEST_APP_WEB_SERVER_TYPE.APP_WEB_SERVER_TYPE_ID
INNER JOIN
  TEST_SINGLE_SIGN_ON
ON
  TEST_APP_ENTRIES.SINGLE_SIGN_ON_ID = TEST_SINGLE_SIGN_ON.SINGLE_SIGN_ON_ID
INNER JOIN
  TEST_AUTHENTICATION_TYPE
ON
  TEST_APP_REALM_ENTRIES.AUTHENTICATION_TYPE_ID = TEST_AUTHENTICATION_TYPE.AUTHENTICATION_TYPE_ID
RIGHT OUTER JOIN
  (SELECT APP_FRAMES.LOGICAL_DB_ENV_NAME AS LOGICAL_DB_ENV_NAME,APP_FRAME_PROPERTIES.FRAME_NAME AS FRAME_NAME,APP_FRAME_PROPERTIES.APP_EXT_CODE AS APP_EXT_CODE,FRAMES.LISTENER_PORT AS LISTENER_PORT,
  LOGICAL_DB_ENVIRONMENT.ZONE_ENV_CODE AS ZONE_ENV_CODE,
APP_FRAME_PROPERTIES.PROPERTY_NAME AS PROPERTY_NAME,APP_FRAME_PROPERTIES.PROPERTY_VALUE AS PROPERTY_VALUE,NODES.IP_ADDRESS AS IP_ADDRESS
FROM APP_FRAME_PROPERTIES,NODES,FRAMES,APP_FRAMES,LOGICAL_DB_ENVIRONMENT
WHERE APP_FRAME_PROPERTIES.FRAME_NAME = FRAMES.FRAME_NAME
AND APP_FRAME_PROPERTIES.APP_EXT_CODE = APP_FRAMES.APP_EXT_CODE
AND LOGICAL_DB_ENVIRONMENT.APP_EXT_CODE = APP_FRAMES.APP_EXT_CODE
AND LOGICAL_DB_ENVIRONMENT.LOGICAL_DB_ENV_NAME = APP_FRAMES.LOGICAL_DB_ENV_NAME
AND APP_FRAME_PROPERTIES.LOGICAL_DB_ENV_NAME = APP_FRAMES.LOGICAL_DB_ENV_NAME
AND NODES.FRAME_NAME = APP_FRAME_PROPERTIES.FRAME_NAME 
AND APP_FRAMES.FRAME_NAME = APP_FRAME_PROPERTIES.FRAME_NAME
AND APP_FRAMES.APP_EXT_CODE =: IN_APP_EXT_CODE
@@LOGICAL_ENV@@
) RES_DETAIL
ON
  TEST_APP_ENTRIES.APP_EXT_CODE = RES_DETAIL.APP_EXT_CODE
  AND TEST_APP_ENTRIES.ZONE_ENV_CODE = RES_DETAIL.ZONE_ENV_CODE ORDER BY TEST_APP_ENTRIES.WAE_ID,WARE_ID';

        IF(IN_ZONE_ENV_CODE IS NOT NULL AND IN_ZONE_ENV_CODE = 'UAT') THEN
                IN_ZONE_ENV_CODE := 'DEV';
        ELSIF(IN_ZONE_ENV_CODE IS NOT NULL AND IN_ZONE_ENV_CODE = 'PROD') THEN
                IN_ZONE_ENV_CODE := 'UAT';
        END IF;

    IF(IN_ZONE_ENV_CODE IS NULL OR IN_ZONE_ENV_CODE = '' OR IN_ZONE_ENV_CODE = 'ALL') THEN
                QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,'');
                QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,'');
                IF(IN_ACTIVE IS NULL OR IN_ACTIVE = '') THEN
                        QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,'');
                        OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_APP_EXT_CODE;
                ELSE
                        QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,ACTIVE_STR);
                        OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ACTIVE,IN_APP_EXT_CODE;
                END IF;
        ELSIF (IN_ACTIVE IS NULL OR IN_ACTIVE = '') THEN
                        QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,'');
                        QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,ZONE_CODE_STR);
                        QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,LOGICAL_ENV_STR);

                        OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ZONE_ENV_CODE,IN_APP_EXT_CODE,IN_ZONE_ENV_CODE;
        ELSE
                        QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,ZONE_CODE_STR);
                        QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,LOGICAL_ENV_STR);
                        QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,ACTIVE_STR);

                        OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ZONE_ENV_CODE,IN_ACTIVE,IN_APP_EXT_CODE,IN_ZONE_ENV_CODE;   
        END IF;

2 个答案:

答案 0 :(得分:2)

我认为您可以使用以下静态sql执行您所需的操作:

add_item_sorted

因此,您之前测试的参数是否为null,然后在适当的位置将其构建到where子句中,而是将其替换为cur->next->data

您必须使用您的数据进行测试,以确保效果仍然令人满意。

附加说明:

  1. 我会用短表别名代替你的全名表;它的可读性更高。
  2. 您正在为外部查询的连接使用ANSI SQL连接语法,但在res_detail子查询中,您使用的是旧式连接。切换它以使用ANSI SQL连接语法。
  3. 顺序中的
  4. select res_detail.frame_name, res_detail.listener_port, res_detail.property_name, res_detail.property_value, res_detail.ip_address, test_app_entries.*, test_app_web_server_type.app_web_server_type_name, test_operation_type.operation_type_name, test_single_sign_on.single_sign_on_name, test_app_realm_entries.ware_id, test_app_realm_entries.resource_filter, test_app_realm_entries.protection_status, test_app_realm_entries.authentication_type_id, test_authentication_type.authentication_type_name, test_app_realm_entries.role from (select * from test_app_entries where app_ext_code = in_app_ext_code and (zone_env_code = in_zone_env_code or in_zone_env_code is null) -- changed and (active = in_active or in_active is null) -- changed ) test_app_entries inner join test_app_realm_entries on test_app_entries.wae_id = test_app_realm_entries.wae_id inner join test_operation_type on test_app_entries.operation_type_id = test_operation_type.operation_type_id inner join test_app_web_server_type on test_app_entries.app_web_server_type_id = test_app_web_server_type.app_web_server_type_id inner join test_single_sign_on on test_app_entries.single_sign_on_id = test_single_sign_on.single_sign_on_id inner join test_authentication_type on test_app_realm_entries.authentication_type_id = test_authentication_type.authentication_type_id right outer join (select app_frames.logical_db_env_name as logical_db_env_name, app_frame_properties.frame_name as frame_name, app_frame_properties.app_ext_code as app_ext_code, frames.listener_port as listener_port, logical_db_environment.zone_env_code as zone_env_code, app_frame_properties.property_name as property_name, app_frame_properties.property_value as property_value, nodes.ip_address as ip_address from app_frame_properties, nodes, frames, app_frames, logical_db_environment where app_frame_properties.frame_name = frames.frame_name and app_frame_properties.app_ext_code = app_frames.app_ext_code and logical_db_environment.app_ext_code = app_frames.app_ext_code and logical_db_environment.logical_db_env_name = app_frames.logical_db_env_name and app_frame_properties.logical_db_env_name = app_frames.logical_db_env_name and nodes.frame_name = app_frame_properties.frame_name and app_frames.frame_name = app_frame_properties.frame_name and app_frames.app_ext_code = in_app_ext_code and (logical_db_environment.zone_env_code = in_zone_env_code or in_zone_env_code is null) -- changed ) res_detail on test_app_entries.app_ext_code = res_detail.app_ext_code and test_app_entries.zone_env_code = res_detail.zone_env_code order by test_app_entries.wae_id, ware_id; 缺少别名。它来自哪个表?
  5. (parameter = some_col or parameter is null) - 在生产代码中,在外部选择中使用*是个坏主意;如果有人添加了一个列会发生什么?
  6. 一般情况下,最好尽可能避免使用动态sql - 如果不将其他文本连接到sql语句中,则不会出现安全问题,而且通常它更易于维护和调试。

答案 1 :(得分:1)

在上面的PL SQL中, 在其中一些中使用BIND VARIABLES,但是,您仍在使用连接创建动态SQL(在这种情况下使用REPLACE功能)。您提供的查询相当大而且复杂,因此我将仅使用它的简化选择为您提供示例。

-- Your stripped-down code:
ZONE_CODE_STR  := ' AND ZONE_ENV_CODE  IN ( :IN_ZONE_ENV_CODE )';
ZONE_CODE_FLAG := '@@ZONE_CODE@@';
ACTIVE_STR     := ' AND ACTIVE  = :IN_ACTIVE ';
ACTIVE_FLAG    := '@@ACTIVE@@';
QUERY_STR  :='SELECT * FROM TEST_APP_ENTRIES WHERE APP_EXT_CODE = :IN_APP_EXT_CODE @@ZONE_CODE@@ @@ACTIVE@@ ';

IF(IN_ZONE_ENV_CODE IS NOT NULL AND IN_ZONE_ENV_CODE = 'UAT') THEN
    IN_ZONE_ENV_CODE := 'DEV';
ELSIF(IN_ZONE_ENV_CODE IS NOT NULL AND IN_ZONE_ENV_CODE = 'PROD') THEN
    IN_ZONE_ENV_CODE := 'UAT';
END IF;

IF(IN_ZONE_ENV_CODE IS NULL OR IN_ZONE_ENV_CODE = '' OR IN_ZONE_ENV_CODE = 'ALL') THEN
    QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,'');
    QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,'');
    IF(IN_ACTIVE IS NULL OR IN_ACTIVE = '') THEN
        QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,'');
        OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_APP_EXT_CODE;
    ELSE
        QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,ACTIVE_STR);
        OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ACTIVE,IN_APP_EXT_CODE;
    END IF;
ELSIF (IN_ACTIVE IS NULL OR IN_ACTIVE = '') THEN
    QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,'');
    QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,ZONE_CODE_STR);
    QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,LOGICAL_ENV_STR);
    OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ZONE_ENV_CODE,IN_APP_EXT_CODE,IN_ZONE_ENV_CODE;
ELSE
    QUERY_STR := REPLACE(QUERY_STR,ZONE_CODE_FLAG,ZONE_CODE_STR);
    QUERY_STR := REPLACE(QUERY_STR,LOGICAL_ENV_FLAG,LOGICAL_ENV_STR);
    QUERY_STR := REPLACE(QUERY_STR,ACTIVE_FLAG,ACTIVE_STR);
    OPEN OUT_RESULT FOR QUERY_STR USING IN_APP_EXT_CODE,IN_ZONE_ENV_CODE,IN_ACTIVE,IN_APP_EXT_CODE,IN_ZONE_ENV_CODE;   
END IF;

我建议做的是重构你的实际SQL查询,以消除与需要动态重写查询相关的额外PL / SQL代码(如果不是全部的话)...在下面的代码中我将解释发生了什么:

SELECT * FROM TEST_APP_ENTRIES 
WHERE APP_EXT_CODE = IN_APP_EXT_CODE
AND CASE Coalesce(:IN_ZONE_ENV_CODE, 'ALL')  -- See Note 1 below...
        WHEN 'ALL' THEN ZONE_ENV_CODE
        ELSE :IN_ZONE_ENV_CODE 
    END = ZONE_ENV_CODE 
AND Coalesce(:IN_ACTIVE, ACTIVE) = ACTIVE; -- See Note 2 below...
  • 注1:我们可以使用COALESCE函数(它返回逗号中的第一个非空项),而不是检查变量为null然后替换占位符。已分隔的列表),并将WHEN部分与'ALL'的字面值进行比较(如果TRUE变量为{{{}},我们将在比较中评估:IN_ACTIVE 1}}或它实际上包含NULL)的值,我们将使用ALL,否则如果不评估ZONE_ENV_CODE,我们会转到TRUE部分{ {1}}并改为使用ELSE。然后将其中一个与WHEN进行比较。这意味着,如果:IN_ZONE_ENV_CODEZONE_ENV_CODE:IN_ZONE_ENV_CODE,我们会在where子句中使用NULL,否则我们会使用ALL

    < / LI>
  • 注2:相似但更简单......如果ZONE_ENV_CODE = ZONE_ENV_CODE:IN_ZONE_ENV_CODE = ZONE_ENV_CODE,我们只需使用COALESCE来比较ACTIVE = ACTIVE,否则{{1 }}