文章目录
PL/SQL 源代码加密概述
加密的原则
加密局限性
使用 wrap 工具加密 PL/SQL 代码
使用 DBMS_DDL 加密 PL/SQL 代码
对 PL/SQL 源代码进行加密可以在交付应用时隐藏源码和实现细节,同时也可以防止发布出去的代码被篡改;Oracle 数据库系统内置的PL/SQL 程序包和类型的代码绝大部分经过了加密处理。Oracle 为我们提供了两种加密 PL/SQL 源代码的方法:wrap 实用工具和 DBMS_DDL 子程序。本文就给大家介绍一下如何利用这些方法提高 PL/SQL 代码的安全性。
PL/SQL 源代码加密概述
加密(wrap) PL/SQL 源代码就是通过混淆隐藏 PL/SQL 内容的过程。包含加密后内容的文件被称为加密文件(wrapped file),加密文件可以被 SQL*Plus 或者导入/导出工具移动、备份以及处理,但是内容无法通过数据字典视图 *_SOURCE 进行查看。
以下 PL/SQL 对象的源代码可以进行加密:
程序包规范
程序包体
类型规范
类型体
函数
过程
PL/SQL 加密可以使用 wrap 实用工具或者 DBMS_DDL 子程序实现。wrap 工具从命令行运行,可以加密 SQL 脚本文件中的任何可加密的 PL/SQL 对象,例如一个 SQL*Plus 安装脚本。DBMS_DDL 子程序可以加密单个动态生成的 PL/SQL 单元,例如 CREATE PROCEDURE 命令。
两种加密方法都可以检查标记化错误(例如字符串超长),但是不会检查语法或者语义错误(例如不存在的表或视图)。
加密的原则
加密PL/SQL 源代码时,建议遵循以下规则:
加密程序包或者对象类型时只加密包体,不加密包规范。这样可以允许其他开发人员使用该程序包或者类型时查看需要的信息,而不能查看具体的实现。
只加密已经开发完成的源代码文件。加密文件不能进行编辑,如果想要修改加密后的 PL/SQL 代码,必须编辑未加密的原始文件并再次进行加密。
发布加密文件之前使用文本编辑器查看并确认所有重要的内容都进行了加密。
加密局限性
PL/SQL 源代码的加密功能存在以下局限性,使用时需要注意:
加密文件不支持 Oracle 数据库的向下兼容。例如,版本 n.1 的 PL/SQL 加密工具生成的文件无法导入版本 (n-1).2 的 Oracle 数据库中,甚至版本 n.2 的 PL/SQL 加密工具生成的文件无法导入版本 n.1 的 Oracle 数据库中。加密文件支持向上兼容,以及同一版本中的不同补丁包之间兼容。
加密 PL/SQL 源代码不适合作为一个隐藏密码或者表名的安全方法。对于更高级别的安全需求,可以考虑使用 Oracle Database Vault。
加密工具无法加密触发器的源代码。如果想要隐藏触发器的实现细节,可以将具体实现放入一个存储程序,然后加密该程序,最后编写一个调用加密程序的触发器。
使用 wrap 工具加密 PL/SQL 代码
wrap 工具接收一个 SQL 文件作为输入,加密该文件中可加密的 PL/SQL 对象(不会加密匿名块、触发器或者非 PL/SQL 代码),然后输出一个对应的加密文件。
wrap 工具位于 $ORACLE_HOME/bin/ 目录下,在操作系统提示符中输入以下命令:
wrap iname=input_file [ oname=output_file ] [ keep_comments=yes ]
其中,input_file 是包含 SQL 语句的文件;如果忽略文件扩展名,默认使用 .sql。output_file 是创建的加密文件;oname 可选,输出文件名默认为输入文件名加上扩展名 .plb。wrap 工具默认会删除所有的注释,除非指定了 keep_comments=yes;此时,加密文件中会保留源码之外的所有注释。注意,等号两边不能包含任何空格。
如果 input_file 是已经加密的文件,不会进行任何处理,output_file 文件的内容和 input_file 完全相同。input_file 文件中不能包含任何使用 SQLPlus DEFINE 定义的替换变量,因为 output_file 通过 PL/SQL 编译器进行解析,而不是 SQLPlus。
例如,以下命令的效果等价:
wrap iname=/mydir/myfile
wrap iname=/mydir/myfile.sql oname=/mydir/myfile.plb
以下命令为 input_file 指定了非默认的扩展名,为 output_file 指定了非默认的文件名,同时保留了注释信息:
wrap iname=/mydir/myfile.src oname=/yourdir/yourfile.out keep_comments=yes
加密之后的 output_file 文件可以通过 SQL*Plus 直接执行,创建 PL/SQL 对象:
SQL> @myfile.plb;
接下来看一个示例,假设 wraptest2.sql 文件包含以下内容:
-- The following statement will not change.
SELECT COUNT(*) FROM EMPLOYEES
/
/* The PL/SQL source text of the following two CREATE statements will be wrapped. */
CREATE PROCEDURE wraptest AUTHID CURRENT_USER /* C style comment in procedure declaration */ IS
TYPE emp_tab IS TABLE OF employees%ROWTYPE INDEX BY PLS_INTEGER;
all_emps emp_tab;
BEGIN
SELECT * BULK COLLECT INTO all_emps FROM employees;
FOR i IN 1..10 LOOP /* C style in pl/sql source */
DBMS_OUTPUT.PUT_LINE('Emp Id: ' || all_emps(i).employee_id);
END LOOP;
END;
/
CREATE OR REPLACE FUNCTION fibonacci (
n PLS_INTEGER
) RETURN PLS_INTEGER
AUTHID CURRENT_USER -- PL/SQL style comment inside fibonacci function spec
IS
fib_1 PLS_INTEGER := 0;
fib_2 PLS_INTEGER := 1;
BEGIN
IF n = 1 THEN -- terminating condition
RETURN fib_1;
ELSIF n = 2 THEN
RETURN fib_2; -- terminating condition
ELSE
RETURN fibonacci(n-2) + fibonacci(n-1); -- recursive invocations
END IF;
END;
/
其中,wraptest 过程和 fibonacci 函数是可加密的 PL/SQL 单元;另外该文件中还包含了一些注释以及一个 SELECT 语句。
从操作系统提示符中运行以下命令进行加密:
> wrap keep_comments=yes iname=wraptest2.sql
1
执行成功后输出的信息如下:
Processing wraptest2.sql to wraptest2.plb
1
加密后的 wraptest2.plb 文件内容如下:
-- The following statement will not change.
SELECT COUNT(*) FROM EMPLOYEES
/
/* The PL/SQL source text of the following two CREATE statements will be wrapped. */
CREATE OR REPLACE PROCEDURE wraptest wrapped