真要字段级加密必须用tde列加密,而非pl/sql手动加密;tde密钥由wallet管理,alter table ... encrypt会触发全表重写,加密列支持等值索引但不支持like和函数索引,wallet关闭时查询直接报ora-28365。
oracle 字段加密不能靠 pl/sql 函数“手动包一层”就完事——那样只是应用层混淆,数据在数据库里仍是明文,dba、备份文件、导出 dump 都能直接看到。真要字段级加密,必须用透明数据加密(tde)列加密,pl/sql 只能辅助管理或做兜底逻辑。
ALTER TABLE ... ENCRYPT 会触发全表重写
对已有表添加加密列或修改列为 ENCRYPT,Oracle 实际执行的是在线重定义(online redefinition)或锁表重建,取决于版本和参数。不是简单改个元数据。
- 如果表有上亿行,
ALTER TABLE t ADD (ssn VARCHAR2(11) ENCRYPT)可能卡住数小时,期间 DML 被阻塞(除非用DBMS_REDEFINITION做联机操作) -
ENCRYPT默认使用 AES-192,但可显式指定:ENCRYPT USING 'AES256';注意:算法一旦设定,后续无法直接修改,只能重建列 - 加密列**不能**作为主键、外键、分区键或物化视图日志列——这些限制在
ORA-28345错误里会明确报出
DBMS_CRYPTO 加密的数据不被 TDE 管理
用 DBMS_CRYPTO.ENCRYPT 手动加密后存进普通 VARCHAR2 列,看起来像密文,但本质是“应用自己管密钥+自己转码”的伪加密:
- 密钥硬编码在 PL/SQL 包里?等于把密码写在源码里;存在表里?DBA 一样能查
- 备份恢复后,只要知道密钥和 IV,就能用相同函数解出原始值——没解决“防 DBA 窥探”这个核心诉求
- TDE 的密钥由 wallet 管理,master key 存在操作系统文件中,且 wallet 可设为关闭状态;而
DBMS_CRYPTO的密钥完全在数据库上下文里流转
加密列的 WHERE 查询仍走索引,但 LIKE 和函数索引失效
TDE 列加密后,等值查询(=)、范围扫描(BETWEEN)仍可用索引,因为 Oracle 在内存中解密后比对;但模糊匹配和函数依赖会断链:
-
WHERE ssn LIKE '123%'→ 全表扫描,ssn是加密列时无法用前缀索引 -
WHERE UPPER(ssn) = 'ABC'→ 不走索引,因为UPPER()作用于加密后的二进制 blob,不是原始字符串 - 想支持模糊查?得额外建虚拟列 + 函数索引,例如:
ADD (ssn_prefix AS SUBSTR(ssn,1,3)),但该列本身不加密,敏感性需重新评估
Wallet 关闭后 SELECT 直接报 ORA-28365,不是权限问题
很多人以为是用户没授权,其实 ORA-28365: wallet is not open 是硬性拦截:wallet 关闭时,所有加密列读取请求在解析阶段就被拒绝,连执行计划都不生成。
- 检查状态用:
SELECT * FROM V$ENCRYPTION_WALLET,关键看WALLET_STATUS是OPEN还是CLOSED - 自动打开 wallet 需配置
sqlnet.ora中的WALLET_LOCATION,并确保数据库启动时 wallet 已存在且口令正确;否则实例能启,但首次查加密列就挂 - 不要在应用连接串里加
ENCRYPTION=REQUIRED——那是给网络传输加密用的,和 TDE 无关,加了反而可能连不上
真正难的不是命令怎么敲,而是决定哪些列必须加密、哪些可以脱敏、哪些干脆不该进数据库;wallet 密码谁保管、怎么轮换、关库前是否强制 close wallet,这些运维决策比写一条 ALTER TABLE ... ENCRYPT 影响深远得多。











