这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

Voltage SecureData 集成

Voltage SecureData 是一套加密技术,可让您将端到端数据加密集成到其他应用程序中。该技术使用格式保留加密 (FPE):加密值与未加密数据的整体格式相同。此功能意味着您不必更改要加密的表列的数据类型。此功能还保留了引用完整性:加密值与未加密数据具有相同的排序顺序,且加密值可以在表之间交叉引用,只要值的每个实例都使用相同的密钥进行加密。

有关 SecureData 的详细信息,请参阅 Voltage 网站

此部分介绍如何将 SecureData 加密功能集成到 Vertica。

1 - Vertica 和 SecureData 如何协同工作

Vertica 提供使用 SecureData 对数据进行加密和解密的函数。

Voltage SecureData 为应用程序提供了多个接口来使用其加密:基于 Web 的 API、命令行工具以及用于 C、C# 和 Java 的 SDK。Vertica 开发了一个用于调用 SecureData API 的接口,可让您:

  • 在使用 SecueData 的 FPE 功能将敏感数据加载到 Vertica 时对其进行加密。您可以确保数据以加密状态(称为“静态加密”)存储在 Vertica 中。授权用户可以根据需要对数据进行解密。未经授权的用户只能看到加密的值。可以使用视图或访问策略为授权用户自动执行解密操作。数据解密操作对于授权用户是透明的。

  • 对以未加密状态存储在 Vertica 中的半敏感数据进行加密,以便未经授权的用户只能看到数据的屏蔽版本。您还可以使用访问策略自动执行此动态加密。

选择的加密方法取决于当前处理的数据。例如,法规或合同可能要求您加密特定的数据。在这些情况下,请在加载数据时使用 SecureData 对其进行加密,以便其不会以未加密的格式存储在 Vertica 中。

在其他情况下,比如针对半敏感数据,您可以在两个选项之间进行选择。在这些情况下,选择所需的加密或解密(调用 SecureData)次数最少的方法。如果需要屏蔽用户对数据的大多数查询,以免其查看未加密的值,则对数据进行静态加密。或者,如果大多数查询来自授权用户,只有个别查询需要屏蔽数据,则以未加密格式存储数据并使用动态加密来屏蔽数据。

2 - 针对与 SecureData 集成的要求

在将 SecureData 与 Vertica 结合使用之前,必须确认以下内容:

  • 您当前使用的是 SecureData 6.0 或更高版本。Vertica 集成函数使用的是 SecureData 6.0 版中引入的 API。

  • Vertica 群集中的所有节点都能够与所有 SecureData 设备主机进行通信。Vertica 群集和 SecureData 设备之间的任何防火墙都必须允许 SecureData 用于通信的端口上的连接。有关 SecureData 使用的端口列表,请参阅《SecureData 设备安装指南》中的“确保具有对 SecureData 服务的访问权限”。

  • 您的 Vertica 数据库当前未使用美国联邦信息处理标准 (FIPS) 模式。FIPS 与 Voltage SecureData 集成不兼容。当 FIPS 模式处于活动状态时,默认情况下不安装 SecureData 集成库。如果您使用 FIPS,请不要手动安装此库。

  • 您在使用安全 Unicode FPE 格式时遵循最佳实践

3 - 安全 unicode FPE 的最佳实践

从 Voltage SecureData Simple API 6.0 开始,您可以使用安全 Unicode 格式保留加密 (FPE) 格式来对 Unicode 字符串进行加密和解密。

使用安全 Unicode FPE 格式加密 Unicode 时,将先使用所有 Unicode 代码点的字母表对传递给 VoltageSecureProtect 函数的纯文本进行加密,然后使用 Base32K 编码对其进行编码,以生成 Unicode 标准化形式 C (NFC) 的加密文本。加密文本通常由 3 字节的中文和日文字符,因为这些字符占具有稳定 NFC 的字母表的比例很大。 VoltageSecureAccess 反转此过程。

与处理由单字节组成的 ASCII 字符串的常规 FPE 不同,安全 Unicode FPE 用于处理由长度可变的代码点组成的字符串。这种可变性引入了一个重要的问题:诸如 UNICODE_BASE32K 的安全 Unicode FPE 格式不保留长度。加密算法会使加密文本大于原始文本,如果未考虑此扩展,可能会导致加密文本被截断或以不正确的方式存储,从而导致无法解密。

此外,Unicode 允许以不同方式对语义相同的字符进行编码,这意味着语义相同的非规范纯文本在加密后可能具有不同的形式,从而会破坏引用完整性。为了防止这种情况,您应该始终在加密之前将您的纯文本字符串标准化为 NFC 形式。有关 Unicode 标准化的详细信息,请参阅 Unicode Consortium 的 标准化常见问题解答

加密文本必然会在以下方面大于纯文本:

  • 字符长度增加 16/15 倍(四舍五入)

  • 大小增加 4 倍(以字节为单位)

有关安全 Unicode FPE 的预定义格式列表,请参阅 Voltage SecureData Simple API 文档副本。

安全 unicode FPE 检查清单

使用安全 Unicode FPE 之前:

  • 在加密之前将纯文本标准化为 NFC 形式。

  • 对于固定长度的数据类型:从纯文本字符串中移除任何填充。

  • 要存储加密文本,请确保用于存储加密文本的列可以处理:

    • 比最长的纯文本字符串长 16/15 倍的字符串

    • 比最大的纯文本字符串大 4 倍(以字节为单位)的字符串

4 - 验证 Vertica 服务器对 SecureData CA 证书的访问权限

在将 SecureData 与 Vertica 结合使用之前,必须确认根证书颁发机构 (CA) 和用于对 SecureData 设备证书进行签名的任何中间证书颁发机构位于 Vertica 服务器的信任库 (/opt/vertica/packages/voltagesecure/trustStore/) 中。Vertica 在此目录中列出了许多标准根证书。如果您的 SecureData 设备使用由标准 CA 颁发机构签名的证书,则它可能已经存在于信任库中。

如果您的 SecureData 设备使用由您自己的内部 CA 颁发机构签名的证书,则必须将此 CA 证书添加到 Vertica 信任库中。

如果不确定您的 CA 证书是否在 Vertica 信任库中,请按照疑难解答证书问题下的步骤测试 Vertica 是否已经拥有 CA 证书。如果您能够从 SecureData 设备中检索到客户端策略 XML 文件,则您的 Vertica 群集拥有用于访问 SecureData 的正确的 CA 证书。

将 CA 证书添加到 Vertica

如果您使用了以下各项,则必须在使用 SecureData 集成之前将 CA 添加到 Vertica 信任库:

  • 您自己的 CA 证书来对 SecureData 设备的证书进行签名。

  • 不在 Vertica 信任库中的第三方 CA。

要将 CA 证书添加到 Vertica 信任库,您需要拥有:

  • 用于对 SecureData 设备的证书进行签名的证书颁发机构 (CA) 文件。此文件必须使用增强型私人邮件 (pem) 格式。文件名无关紧要,只要具有 .pem 扩展名即可。

  • 对 Vertica 节点上的 dbadmin 帐户的访问权限。需要此访问权限才能将证书文件复制到 Vertica 安装中的信任存储目录。

要将所需的 CA 文件添加到 Vertica,请执行以下操作:

  1. 以 dbadmin 用户身份登录到 Vertica 节点之一。

  2. 将 .pem 文件复制到 /opt/vertica/packages/voltagesecure/trustStore/ 目录。您只需将此文件复制到单个节点。Vertica 会将文件分发给群集中的其余节点。

  3. 在 Linux 命令行中,执行以下命令以重新安装 SecureData 集成库:

    $ admintools -t install_package -d database_name -p 'password' --package voltagesecure --force-reinstall
    

当 Vertica 重新安装 SecureData 集成库时,它会将 CA 授权文件复制到群集中的所有节点。文件分发完成后,所有 Vertica 节点都可以使用 SecureData 设备进行身份验证。

例如,假设:

  • 您的证书文件名为 my_ca.cert.pem,且您已将其复制到群集中节点上的 dbadmin 主目录。

  • 您的数据库名为 VMart。

则安装 CA 文件的过程将如下所示:

$ cp my_ca.cert.pem /opt/vertica/packages/voltagesecure/trustStore/
$ admintools -t install_package -d VMart -p dbadminpassword --package voltagesecure --force-reinstall
Installing package voltagesecure...
...Success!

疑难解答证书问题

您可以通过从 Linux 命令行执行以下语句来测试 Vertica 信任库是否具有正确的证书:

curl --capath /vertica_catalog_directory/Libraries/\
$(vsql -A -t -c "SELECT sal_storage_id from user_libraries WHERE lib_name = 'VoltageSecureLib';")\
https://SecureData_applicance_hostname/policy/clientPolicy.xml

其中:

  • vertica_catalog_directory 是 Vertica 编录目录的绝对路径。有关编录目录的详细信息,请参阅了解编录目录

  • SecureData_appliance_hostname 是 SecureData 设备的主机名。

例如,假设您连接到示例 VMart 数据库的 node0001。此外,您的 Voltage SecureData 设备的主机名为 voltage-pp-0000.example.com。那么,您可以使用以下命令来测试您的证书安装。

$ curl --capath /home/dbadmin/VMart/v_vmart_node0001_catalog/Libraries/\
$(vsql -A -t -c "SELECT sal_storage_id from user_libraries WHERE lib_name = 'VoltageSecureLib';") \
https://voltage-pp-0000.example.com/policy/clientPolicy.xml


<clientPolicy version="2">

<server name="SecureDataAppliance" version="6.4.2.232000" />

<localDomains>example.com</localDomains>

<userWhitelist></userWhitelist>

<defaultDistrict value="0" />

<sendUniversalReader value="1" />

<messageFooterGlobal></messageFooterGlobal>

<parameterAggressiveDistricts>example.com</parameterAggressiveDistricts>

<localPolicyLocked value="0" />

<trustedDistricts></trustedDistricts>

<fallThroughDistrict>example.com</fallThroughDistrict>
      .    .    .

<clientPolicy>... 输出(即 clientPolicy.xml 文件的内容)表明 Vertica 节点能够使用其 CA 证书连接到 SecureData 设备。

如果您在 Vertica 上安装的 CA 证书与在 SecureData 设备上安装的证书不匹配,您将看到类似于以下内容的错误:

$ curl --capath /home/dbadmin/VMart/v_vmart_node0001_catalog/Libraries/$(vsql\
 -A -t -c "SELECT sal_storage_id from user_libraries WHERE lib_name = 'VoltageSecureLib';")\
 https://voltage-pp-0000.example.com/policy/clientPolicy.xml

curl: (60) Peer certificate cannot be authenticated with known CA certificates
More details here: http://curl.haxx.se/docs/sslcerts.html

在这种情况下,请确认您已在 Vertica 中安装了正确的 CA 证书,并且其文件名具有 .pem 扩展名。

如果看到其他错误,例如“无法连接到主机”,请验证您的防火墙配置是否允许 Vertica 节点访问 SecureData 设备。

5 - 配置对 SecureData 的访问权限

Vertica 集成函数需要使用多条信息才能连接到 SecureData 并对其进行身份验证。

SecureData 全局配置设置

SecureData 集成具有一个必需的设置和两个可选设置,您可以使用 VoltageSecureConfigureGlobal 函数对其进行全局设置。此函数将设置保存到名为 /voltagesecure/conf.global 的配置文件中,该文件存储在 Vertica 分布式文件系统 (DFS) 中。Vertica 使用此文件系统来存储所有节点都可以访问的数据。在使用任何其他 SecureData 集成函数之前,必须使用此函数创建该文件。所有可以访问 SecureData 函数的用户都可以访问此文件中的设置。

必需设置的是 SecureData 策略文件的 URL。此文件为 SecureData 集成库提供有关如何配置 SecureData 设备的详细信息。此库还使用此 URL 来确定 SecureData 设备的地址。

两个可选设置是:

  • allow_short_fpe: 设置为 True 时,SecureData 将忽略编码 FPE 值的长度下限。通常,SecureData 不使用 FPE 来加密短于下限(通常为 8 位)的数据。有关详细信息,请参阅《SecureData 架构指南》的“数据长度限制”部分。

  • enable_file_cache: 设置为 True 时,Vertica 会将 SecureData 策略文件和加密密钥缓存到磁盘,而不仅仅是内存。默认为 false。

此示例将策略 URL 全局设置为 https://voltage-pp-0000.example.com/policy/clientPolicy.xml 并将网络超时设置为 200 秒。

=> SELECT VoltageSecureConfigureGlobal(USING PARAMETERS
                                       policy_url='https://voltage-pp-0000.example.com/policy/clientPolicy.xml',
                                       NETWORK_TIMEOUT=200)
                                       OVER ();

                           policy_url                            | allow_short_fpe | enable_file_cache | network_timeout
-----------------------------------------------------------------+-----------------+-------------------+-----------------
 https://voltage-pp-0000.example.com/policy/clientPolicy.xml     |                 |                   | 200
(1 row)

跨节点手动刷新客户端策略:

=> SELECT VoltageSecureRefreshPolicy() OVER ();
                                  PolicyRefresh
-------------------------------------------------------------------------------------
Successfully refreshed policy on node [v_sandbox_node0001]. Policy on other nodes
will be refreshed the next time a Voltage operation is run on them.
(1 row)

SecureData 用户配置设置

其余的 SecureData 设置用于定义 SecureData 用户信息。这些设置通常特定于访问集成函数的每个用户。但是,您可以让所有 Vertica 用户共享相同的 SecureData 用户配置。这些设置是:

  • SecureData 的身份验证凭据。所需的确切信息取决于 SecureData 设备的配置。可以使用以下四种设置:
    • username:用于标识自己的用户名。用户名由 LDAP(使用 LDAP 身份验证时)定义,或由 SecureData 设备(使用共享密钥身份验证时)定义。

    • identity:要使用的 SecureData 身份。有关 SecureData 中身份的详细信息,请参阅《SecureData 管理员指南》。身份通常采用电子邮件地址的形式。当 SecureData 设备使用 LDAP 身份验证时,LDAP 帐户必须具有对该身份的访问权限。

    • shared_secret:在 SecureData 中设置的密码。

    • password:使用 SecureData 进行身份验证时要使用的 LDAP 密码。

您可以同时提供用户名和身份,具体取决于 SecureData 设备的配置。可以将 SecureData 设备配置为根据 SecureData 用户名提供身份。

但是,只能使用 shared_secret 或密码。如果同时设置了这两个参数,Vertica SecureData 函数将退出并返回错误。

您可以使用以下两个选项来设置这些配置值:在用户定义的会话参数中进行设置,或者将值保存到存储在 Vertica 分布式文件系统中的配置文件中。

设置 SecureDate 用户会话参数

使用 ALTER SESSION 语句为 voltagesecurelib 库设置参数。此库包含所有 SecureData 函数。以下示例演示如何配置会话以使用共享密钥身份验证访问 SecureData。


=> ALTER SESSION SET UDPARAMETER FOR voltagesecurelib identity='alice@example.com';
ALTER SESSION
=> ALTER SESSION SET UDPARAMETER FOR voltagesecurelib username='alice';
ALTER SESSION
=> ALTER SESSION SET UDPARAMETER FOR voltagesecurelib shared_secret='my_shared_secret';
ALTER SESSION

设置后,这些参数仅在会话期间使用。

将参数保存到配置文件中

可以使用 VoltageSecureConfigure 函数将 SecureData 用户参数保存到 DFS 中的配置文件中。必须为配置文件提供文件名。可以选择将 SecureData 参数存储在用户特定的文件中,只需提供一个文件名,例如 securedata.conf。在后台,配置文件将存储在 DFS 中以您的用户名命名的目录下。此目录可防止您的配置文件与其他用户的文件发生冲突。访问配置文件时不需要使用此目录名称。

还可以将配置参数存储在名为 /voltagesecure/conf 的绝对文件中。所有有权访问 SecureData 集成函数的用户都可以在其函数调用中使用此配置文件。如果访问 SecureData 函数的所有用户共享相同的 SecureData 用户设置,则您也可以使用此文件。

会话参数中的值会覆盖配置文件中的值。

您可以使用要保存到配置文件的参数调用 VoltageSecureConfigure。未在此函数调用中设置的值也不会在配置文件中设置。必须使用会话参数将这些值提供给其他 SecureData 集成函数。

如果选择将密码或共享密钥保存到配置文件中,则不会直接将其传递给 VoltageSecureConfigure 函数。而是在适当的会话变量中设置值,然后将 VoltageSecureConfigure 的 store_passwordstore_shared_secret 参数设置为 true。当这些参数中的任何一个为 true 时,VoltageSecureConfigure 会从会话变量中读取值并将其保存到配置文件中。

示例:创建用户特定的配置文件

以下示例显示了如何创建用户特定的配置文件。此示例不存储密码或共享密钥等信息,因此仍必须为这些值设置会话参数,然后才能调用其他 SecureData 集成函数。

=> \x
Expanded display is on.
=> SELECT VoltageSecureConfigure(USING PARAMETERS config_dfs_path='voltage.conf',
                                 username='alice', identity='alice@example.com', store_password=false
                                ) OVER ();
-[ RECORD 1 ]-----+----------------------------------------------------------------
config_dfs_path   | voltage.conf
identity          | alice@example.com
username          | alice

6 - 对数据进行加密、解密和哈希操作

使用 SecureData Appliance (SDA) 设置身份验证后,请调用 VoltageSecureProtectVoltageSecureAccess 函数分别对数据进行加密/哈希操作或解密。至少,您需向这些函数传递要进行加密、哈希操作或解密的值,以及 Voltage SDA 中定义的值的 FPE 格式。您还可以捕获 SQL 宏访问策略中的这些参数。

将 Vertica 连接到 SecureData Appliance

以下示例演示如何使用 Vertica 获取 SDA 客户端策略,然后演示如何设置会话参数以对 SDA 进行身份验证。

  1. 将 SecureData CA 证书添加到 Vertica

  2. 使用 VoltageSecureConfigureGlobal 设置客户端策略。

    => SELECT VoltageSecureConfigureGlobal(USING PARAMETERS
        policy_url='https://voltage-pp-0000.example.com/policy/clientPolicy.xml')
        OVER ();
                               policy_url                            | allow_short_fpe | enable_file_cache
    -----------------------------------------------------------------+-----------------+-------------------
     https://voltage-pp-0000.example.com/policy/clientPolicy.xml     |                 |
    (1 row)
    
  3. (可选)使用 VoltageSecureRefreshPolicy 检索客户端策略的最新版本。

    => SELECT VoltageSecureRefreshPolicy() OVER ();
                                      PolicyRefresh
    -------------------------------------------------------------------------------------
    Successfully refreshed policy on node [v_node0001]. Policy on other nodes
    will be refreshed the next time a Voltage operation is run on them.
    (1 row)
    
  4. 设置身份验证参数,以便使用 ALTER SESSIONVoltageSecureConfigure 以 Vertica 用户身份对 SDA 进行身份验证。有关此过程的详细信息,请参阅配置对 SecureData 的访问权限

    ALTER SESSION 将在会话期间设置这些参数,并覆盖配置文件中设置的参数。

    
    => ALTER SESSION SET UDPARAMETER FOR voltagesecurelib identity='alice@example.com';
    ALTER SESSION
    => ALTER SESSION SET UDPARAMETER FOR voltagesecurelib username='alice';
    ALTER SESSION
    => ALTER SESSION SET UDPARAMETER FOR voltagesecurelib shared_secret='my_secret';
    ALTER SESSION
    

    VoltageSecureConfigure 将这些参数保存到指定的 config_dfs_path。稍后,此配置文件也可以传递给其他 Voltage 函数。

    => SELECT VoltageSecureConfigure(USING PARAMETERS config_dfs_path='voltage.conf',
       username='alice', identity='alice@example.com', store_password=false) OVER ();
    
     config_dfs_path | identity          | username
    -----------------+-------------------+----------
     voltage.conf    | alice@example.com | alice
    
    => SELECT VoltageSecureProtect('123-45-6789' USING PARAMETERS
        format='ssn',
        config_dfs_path='voltage.conf');
    
     VoltageSecureProtect
    ----------------------
     376-69-6789
    

对数据进行加密和解密

VoltageSecureProtect 采用在 SDA 和 VARCHAR 数据中定义的“格式保留加密 (FPE)”格式并返回保留格式的密文,稍后可以使用 VoltageSecureAccess 对此密文进行解密。也就是说,如果纯文本遵循电话号码的形式 (###-###-####),则生成的密文将采用相同的形式。可以通过多种方式自定义格式,例如:屏蔽某些值、不加密字符串的某些部分等。

SDA 中的许多预定义格式之一是 ssnssn 格式将对除社会保险号 (SSN) 的最后四位之外的所有数字进行加密。这对客户支持等某些角色很有用,因为他们可能需要 SSN 的最后四位数字来通过电话验证个人身份。


=> SELECT VoltageSecureProtect('123-45-6789' USING PARAMETERS format='ssn');
 VoltageSecureProtect
----------------------
 376-69-6789
(1 row)

=> SELECT VoltageSecureAccess('376-69-6789' USING PARAMETERS format='ssn');
 VoltageSecureAccess
---------------------
 123-45-6789
(1 row)

另一种预定义格式是 auto,它可以处理各种数据(包括 SSN)。与 ssn 相比,auto 在 SDA 中配置为对纯文本中的所有字符进行加密。


=> SELECT VoltageSecureProtect('123-45-6789' USING PARAMETERS format='auto');
 VoltageSecureProtect
----------------------
 820-31-5110
 (1 row)

请注意,对密文进行解密时,您只能使用生成密文时所用的相同格式。因此,使用 ssn 创建的密文必须使用 ssn 进行解密。例如,使用 ssn 生成的密文传递格式 auto 只会返回不正确的纯文本。

在加载期间对数据进行加密

处理敏感数据时,您通常希望在加载时进行加密,从而使未加密的值不会存储在您的数据库中。

以下示例演示使用 COPY 加载数据。假设您的数据已填充客户信息,包含以下字段:身份证号、名字、姓氏、社会保险号、卡验证码和出生日期:

5345,Thane,Ross,559-32-0670,376765616314013,618,05-09-1996
5346,Talon,Wilkins,540-48-0784,4716511603424923,111,09-17-1941
5347,Daquan,Phelps,785-34-0092,342226134491834,294,05-08-1963
5348,Basia,Lopez,011-85-0705,4595818418314603,503,04-29-1940
5349,Kaseem,Hendrix,672-57-0309,4556 078 73 7944,693,03-11-1942
5350,Omar,Lott,825-45-0131,6462 0541 0799 6261,555,02-17-1956
5351,Nell,Cooke,637-50-0105,646 59756 30903 530,818,02-14-1995
5352,Illana,Middleton,831-47-0929,648 23640 86684 267,883,12-29-1949
5353,Garrett,Williamson,408-73-0207,5334 2702 1360 8370,869,11-06-1955
5354,Hanna,Ware,694-97-0394,543 38494 19219 254,586,08-08-1967

要对社会保险号和信用卡号列进行加密,请调用 VoltageSecureProtect 对用于加载数据的 COPY 语句中的上述列进行加密:

=> CREATE TABLE customers (id INTEGER, first_name VARCHAR, last_name VARCHAR,
                           ssn VARCHAR(11), cc_num VARCHAR(25), cvv VARCHAR(5), dob DATE);
CREATE TABLE
=> COPY customers (id, first_name, last_name, ssn_raw FILLER VARCHAR(11),
        cc_num_raw FILLER VARCHAR(25), cvv, dob,
        ssn AS VoltageSecureProtect(ssn_raw USING PARAMETERS format='ssn',
                                    config_dfs_path='voltage.conf'),
     cc_num AS VoltageSecureProtect(cc_num_raw USING PARAMETERS format='cc',
                                       config_dfs_path='voltage.conf'))
     FROM '/home/dbadmin/customer_data.csv' DELIMITER ',';
 Rows Loaded
-------------
         100
(1 row)

=> SELECT * FROM customers ORDER BY id ASC LIMIT 10;
  id  | first_name | last_name  |     ssn     |       cc_num        | cvv |    dob
------+------------+------------+-------------+---------------------+-----+------------
 5345 | Thane      | Ross       | 072-52-0670 | 405939553794013     | 618 | 1996-05-09
 5346 | Talon      | Wilkins    | 348-30-0784 | 5350908688294923    | 111 | 1941-09-17
 5347 | Daquan     | Phelps     | 983-53-0092 | 133383311411834     | 294 | 1963-05-08
 5348 | Basia      | Lopez      | 490-63-0705 | 7979155436134603    | 503 | 1940-04-29
 5349 | Kaseem     | Hendrix    | 268-74-0309 | 3212 314 45 7944    | 693 | 1942-03-11
 5350 | Omar       | Lott       | 872-03-0131 | 4914 1839 6801 6261 | 555 | 1956-02-17
 5351 | Nell       | Cooke      | 785-90-0105 | 332 34312 95233 530 | 818 | 1995-02-14
 5352 | Illana     | Middleton  | 947-60-0929 | 219 06376 36044 267 | 883 | 1949-12-29
 5353 | Garrett    | Williamson | 333-23-0207 | 1126 1022 5922 8370 | 869 | 1955-11-06
 5354 | Hanna      | Ware       | 661-57-0394 | 106 09915 59049 254 | 586 | 1967-08-08
(10 rows)

对非 VARCHAR 数据进行加密

VoltageSecureProtect 函数仅对 VARCHAR 值进行加密,因此如果您需要对其他数据类型(例如 DATE 或 INTEGER)进行加密,则必须在函数调用中将这些值转换为 VARCHAR,然后在存储时将其转换回 DATE 或 INTEGER。

在上述示例的基础上,以下内容对包含日期类型 DATE 的出生日期 (dob) 列进行加密。

=> CREATE TABLE customers2 (id INTEGER, first_name VARCHAR, last_name VARCHAR, ssn VARCHAR(11),
                            cc_num VARCHAR(25), cvv VARCHAR(5), dob DATE);
CREATE TABLE
=> COPY customers2 (id, first_name, last_name, ssn, cc_num, cvv, dob_raw FILLER DATE,
                    dob AS VoltageSecureProtect(dob_raw::VARCHAR USING PARAMETERS
                                                format='birthday',
                                                config_dfs_path='voltage.conf')::DATE)
        FROM '/home/dbadmin/customer_data.csv' DELIMITER ',';
 Rows Loaded
-------------
         100
(1 row)

=> SELECT * FROM customers2 ORDER BY id ASC LIMIT 10;
  id  | first_name | last_name  |     ssn     |       cc_num        | cvv |    dob
------+------------+------------+-------------+---------------------+-----+------------
 5345 | Thane      | Ross       | 559-32-0670 | 376765616314013     | 618 | 1902-03-09
 5346 | Talon      | Wilkins    | 540-48-0784 | 4716511603424923    | 111 | 2023-07-22
 5347 | Daquan     | Phelps     | 785-34-0092 | 342226134491834     | 294 | 2091-01-18
 5348 | Basia      | Lopez      | 011-85-0705 | 4595818418314603    | 503 | 1921-08-17
 5349 | Kaseem     | Hendrix    | 672-57-0309 | 4556 078 73 7944    | 693 | 1962-08-23
 5350 | Omar       | Lott       | 825-45-0131 | 6462 0541 0799 6261 | 555 | 1930-01-12
 5351 | Nell       | Cooke      | 637-50-0105 | 646 59756 30903 530 | 818 | 2098-01-01
 5352 | Illana     | Middleton  | 831-47-0929 | 648 23640 86684 267 | 883 | 1956-09-07
 5353 | Garrett    | Williamson | 408-73-0207 | 5334 2702 1360 8370 | 869 | 2079-03-25
 5354 | Hanna      | Ware       | 694-97-0394 | 543 38494 19219 254 | 586 | 1903-07-16
(10 rows)

请注意,您不能对 DATE 类型使用 auto 格式;auto 生成的密文将使用整个范围的数字和字母,且仅保留字符数和任何分隔符,因此生成的密文通常不能转换为日期。

=> SELECT VoltageSecureProtect('07-16-1969' USING PARAMETERS format='auto',
                               config_dfs_path='/voltagesecure/conf');
 VoltageSecureProtect
----------------------
 45-86-8651
(1 row)

=> SELECT VoltageSecureProtect('07-16-1969' USING PARAMETERS format='auto',
                               config_dfs_path='/voltagesecure/conf')::DATE;
ERROR 2992:  Date/time field value out of range: "45-86-8651"
HINT:  Perhaps you need a different "datestyle" setting

对查询中的值进行解密

要对表中存储的密文进行解密,请对查询中的已加密列调用 VoltageSecureAccess。

以下示例将查询表并对 SSN 列进行解密:


=> SELECT id,
          first_name,
          last_name,
          VoltageSecureAccess(ssn USING PARAMETERS format='ssn',
                              config_dfs_path='/voltagesecure/conf') AS ssn_plaintext,
          dob
      FROM customers
      WHERE dob < '1970-1-1'
      ORDER BY id ASC
      LIMIT 10;

  id  | first_name | last_name  |     ssn_plaintext     |    dob
------+------------+------------+-----------------------+------------
 5346 | Talon      | Wilkins    | 540-48-0784           | 1941-09-17
 5347 | Daquan     | Phelps     | 785-34-0092           | 1963-05-08
 5348 | Basia      | Lopez      | 011-85-0705           | 1940-04-29
 5349 | Kaseem     | Hendrix    | 672-57-0309           | 1942-03-11
 5350 | Omar       | Lott       | 825-45-0131           | 1956-02-17
 5352 | Illana     | Middleton  | 831-47-0929           | 1949-12-29
 5353 | Garrett    | Williamson | 408-73-0207           | 1955-11-06
 5354 | Hanna      | Ware       | 694-97-0394           | 1967-08-08
 5355 | Quinn      | Pruitt     | 818-91-0359           | 1965-11-14
 5356 | Clayton    | Santiago   | 102-56-0010           | 1958-02-02
(10 rows)

对非 VARCHAR 列进行解密

与 VoltageSecureProtect 一样,VoltageSecureAccess 只能处理 VARCHAR 值。对非 VARCHAR 列中的密文进行解密时,必须先将其转换为 VARCHAR,然后再传递给 VoltageSecureAccess。如果您的查询或客户端应用程序依赖于该列的原始数据类型,则必须将返回的纯文本转换回该列的原始数据类型。

以下示例将列数据从 DATE 转换为 VARCHAR,将其传递给 VoltageSecureAccess,然后将纯文本转换回 DATE,从而完成对 dob 列的解密。


=> SELECT id, first_name, last_name,
          VoltageSecureAccess(dob::VARCHAR USING PARAMETERS format='birthday',
                              config_dfs_path='/voltagesecure/conf')::DATE AS dob
          FROM customers2 ORDER BY id LIMIT 10;
  id  | first_name | last_name  |    dob
------+------------+------------+------------
 5345 | Thane      | Ross       | 1996-05-09
 5346 | Talon      | Wilkins    | 1941-09-17
 5347 | Daquan     | Phelps     | 1963-05-08
 5348 | Basia      | Lopez      | 1940-04-29
 5349 | Kaseem     | Hendrix    | 1942-03-11
 5350 | Omar       | Lott       | 1956-02-17
 5351 | Nell       | Cooke      | 1995-02-14
 5352 | Illana     | Middleton  | 1949-12-29
 5353 | Garrett    | Williamson | 1955-11-06
 5354 | Hanna      | Ware       | 1967-08-08
(10 rows)

屏蔽已解密值

如果密文是使用指定“屏蔽”形式的格式创建的,则可使用 mask=true 参数屏蔽由 VoltageSecureAccess 返回的纯文本。如果未指定此参数,则无论格式如何,均会返回完整的纯文本。

如 Voltage SDA 中所定义,这种格式隐藏了除已解密纯文本的最后两个字符以外的所有字符。


=> SELECT VoltageSecureAccess('g3kbx6ru19', USING PARAMETERS
                                  format='maskedFormat',
                                  config_dfs_path='voltage.conf');
 VoltageSecureAccess
----------------------
 1234567890

=> SELECT VoltageSecureAccess('g3kbx6ru19', USING PARAMETERS
                                  format='maskedFormat',
                                  config_dfs_path='voltage.conf',
                                  mask=true);
 VoltageSecureAccess
----------------------
 XXXXXXXX90

调整密文

与 [salt](https://en.wikipedia.org/wiki/Salt_(cryptography) 类似,您可以额外传递“调整”值以添加到 VoltageSecureProtect 使用的密钥,以便从相同的纯文本中创建唯一的密文。稍后,“经过调整”的密文只能通过将相同的格式和“调整”值传递给 VoltageSecureAccess 来解密。可在 SDA 中设置是否支持此功能。

以下示例使用自定义格式 ssn-tweak 和值 tweakvalue123 来调整密文。


=> SELECT VoltageSecureProtect('681-09-2913', 'tweakvalue123' USING PARAMETERS
    format='ssn-tweak');

 VoltageSecureProtect
----------------------
 721-21-2913

=> SELECT VoltageSecureAccess('721-21-2913', 'tweakvalue123' USING PARAMETERS
    format='ssn-tweak');

 VoltageSecureProtect
----------------------
 681-09-2913

调整整列

常见的用例是使用一列中的值来调整另一列中的密文。

以下示例采用与上文类似的方式加载数据,但使用 last_name 列中的值来调整每个客户的出生日期。


=> CREATE TABLE customers (id INTEGER, first_name VARCHAR, last_name VARCHAR, ssn VARCHAR(11),
    cc_num VARCHAR(25), cvv VARCHAR(5), dob DATE);
CREATE TABLE

=> COPY customers (id, first_name, last_name, ssn_raw FILLER VARCHAR(11),
           cc_num_raw FILLER VARCHAR(25), cvv,
           dob_raw FILLER DATE, ssn AS VoltageSecureProtect(ssn_raw USING PARAMETERS format='ssn',
                                                            config_dfs_path='voltage.conf'),
           /* cast the dob_raw to VARCHAR and tweak with last_name, then cast back to DATE */
           dob AS VoltageSecureProtect(dob_raw::VARCHAR , last_name USING PARAMETERS format='date-tweak',
                                       config_dfs_path='voltage.conf')::DATE,
           cc_num AS VoltageSecureProtect(cc_num_raw USING PARAMETERS format='cc', config_dfs_path='voltage.conf'))
           FROM 'customers.csv' DELIMITER ',';

 Rows Loaded
-------------
         100
(1 row)

=> SELECT id, first_name, last_name, dob FROM customers ORDER BY id;
  id  | first_name | last_name  |    dob
------+------------+------------+------------
 5345 | Thane      | Ross       | 2086-03-07
 5346 | Talon      | Wilkins    | 1936-06-09
 5347 | Daquan     | Phelps     | 1953-12-01
 5348 | Basia      | Lopez      | 1979-11-30
 5349 | Kaseem     | Hendrix    | 2090-01-07
 5350 | Omar       | Lott       | 1984-07-27
 5351 | Nell       | Cooke      | 2053-03-20
 5352 | Illana     | Middleton  | 1988-03-06
 5353 | Garrett    | Williamson | 1927-03-03
 5354 | Hanna      | Ware       | 1998-08-28
 5355 | James      | May        | 1941-10-24
(11 rows)

要对该列进行解密,请在 VoltageSecureAccess 的调用中包含调整列。调整列必须包含与加密列时使用的相同数据。


=> SELECT id, first_name, last_name,
   VoltageSecureAccess(dob::VARCHAR , last_name USING PARAMETERS format='date-tweak',
   config_dfs_path='voltage.conf')::DATE AS dob
   FROM customers ORDER BY id;
 id  | first_name | last_name  |    dob
------+------------+------------+------------
 5345 | Thane      | Ross       | 1996-05-09
 5346 | Talon      | Wilkins    | 1941-09-17
 5347 | Daquan     | Phelps     | 1963-05-08
 5348 | Basia      | Lopez      | 1940-04-29
 5349 | Kaseem     | Hendrix    | 1942-03-11
 5350 | Omar       | Lott       | 1956-02-17
 5351 | Nell       | Cooke      | 1995-02-14
 5352 | Illana     | Middleton  | 1949-12-29
 5353 | Garrett    | Williamson | 1955-11-06
 5354 | Hanna      | Ware       | 1967-08-08
 5355 | James      | May        | 1967-08-08
(11 rows)

使用存储过程调整列

由于调整值成为加密密钥的一部分,因此调整列的内容在加密和解密时必须相同。为避免失去对纯文本的访问权限,在修改调整列时,您必须:

  1. 对密文进行解密

  2. 修改调整列

  3. 使用修改后的调整列的内容对纯文本数据重新进行加密

您可以使用存储过程自动执行此过程。例如,在使用姓氏进行调整时,如需更新客户出生日期,则存储过程可能如下所示:

=> CREATE PROCEDURE update_dob (employee_id INT, tweak_value VARCHAR) AS $$
  BEGIN
    PERFORM UPDATE customers
      SET dob = (
        WITH dob_ AS (SELECT VoltageSecureAccess(dob::VARCHAR , last_name
          USING PARAMETERS format='date-tweak', config_dfs_path='voltage.conf')::DATE AS dob
            FROM customers
            WHERE id = employee_id)
        SELECT VoltageSecureProtect(dob::VARCHAR, tweak_value
          USING PARAMETERS format='date-tweak', config_dfs_path='voltage.conf')::DATE
            FROM dob_)
      WHERE ID = employee_id;

    PERFORM UPDATE customers SET last_name = tweak_value WHERE ID = employee_id;

    PERFORM COMMIT;
  END;
$$;

稍后,您可以调用该过程来更新已加密值和调整值:

=> CALL update_dob(5349, 'Henderson');

对数据进行哈希操作

VoltageSecureProtect 还可以在保留数据格式的同时对数据进行哈希操作。当您需要对数据进行匿名处理以符合隐私标准,且与此同时保持客户端代码可访问性时,这一功能非常有用。

您应该记住以下几点:

  • 哈希是一种单向操作,因此原始纯文本不可恢复

  • 这种保留格式的哈希函数和熵较低的纯文本(姓名、日期、SSN 等)的性质,意味着它比标准哈希函数更有可能发生冲突

以下示例使用 customFPH 格式 ssnHash 对 SSN 进行加密。


=> SELECT VoltageSecureProtect('681-09-2913' USING PARAMETERS
                                  format='ssnHash',
                                  config_dfs_path='voltage.conf');
 VoltageSecureProtect
----------------------
 841-68-2913

7 - 使用 SQL 宏封装加密业务逻辑

VoltageSecureProtectVoltageSecureAccess 函数的级别非常低,我们需要做足准备才能正确使用。这包括但不限于了解有关正在解密/加密的数据类型、要使用的 Voltage 格式、将输入值转换为 VARCHAR 然后恢复为所需的数据类型以及身份管理的信息。使用这么多动态组件编写查询可能很乏味。

为了简化此过程,您可以将此信息封装在 SQL 宏中,并使用 case 表达式以更动态的方式决定其行为。此方法有以下优势:

  • 您可以将 Voltage 格式与数据的用途相关联,Vertica 将相应地自动加密和解密该值。

  • 您可以自动执行所需的类型转换,从所需的数据类型转换为 VARCHAR。

  • THROW_ERROR 函数可以为宏提供一种输入验证形式。

  • 您可以在加密期间为给定的 case 表达式指定 身份,以便将解密权限限制为相同的身份。

要查看您的宏,请查询 USER_FUNCTIONS 系统表。

加密和解密宏模板

在以下宏中,data_purpose 参数描述了数据的用途(例如 temperature),value 参数指示了正在加密的值及其 data_type(例如 INT)。data_type 在整个宏中必须相同。

data_purpose 参数还与 voltage_formatvoltage_identity 参数相关联,后两个参数分别用于控制数据的加密/解密方式以及可以访问数据的身份。

如果将不具有相应 case 表达式的 data_purpose 传递给函数,则 THROW_ERROR 函数将返回用户指定的错误,该错误本身必须转换为函数的返回 data_type

请注意,如果遇到与指定转换不兼容的类型,标准转换运算符 :: 将完全终止查询,这在转换较大数据集时可能会出现问题。为防止查询终止,您可以使用 ::! 运算符首先尝试指定的转换,对于不兼容的类型则返回 NULL 值。有关详细信息,请参阅转换失败

使用 VoltageSecureProtect 的加密宏

=> CREATE FUNCTION encryptDataType(data_purpose VARCHAR, value data_type) RETURN data_type
    AS BEGIN
    RETURN(CASE
        WHEN (data_purpose='data_purpose')
            then VoltageSecureProtect(value::VARCHAR USING PARAMETERS
                format='voltage_format',
                identity='voltage_identity')::data_type
        ELSE
            THROW_ERROR('no matching data_purpose')::data_type
        END);
    END;

使用 VoltageSecureAccess 的解密宏

=> CREATE FUNCTION decryptDataType(data_purpose VARCHAR, value data_type) RETURN data_type
    AS BEGIN
    RETURN(CASE
        WHEN (data_purpose='data_purpose')
            then VoltageSecureAccess(value::VARCHAR USING PARAMETERS
                format='voltage_format',
                identity='voltage_identity')::data_type
        ELSE
            THROW_ERROR('no matching data_purpose')::data_type
        END);
    END;

示例

以下示例显示如何管理含出生日期的列的加密和解密。在这种情况下,您可能需要定义一个单独的身份来对客户和员工数据进行加密。

=> SELECT * FROM customer_dob;
   dates
-----------
 1955-11-04
 1991-12-01
 1977-07-07
(3 rows)

对于加密,定义以下宏。

=> CREATE FUNCTION encryptDOB(data_purpose VARCHAR, value DATE) RETURN DATE
    AS BEGIN
    RETURN
        (CASE
            --The data_purpose parameter controls which identity is used during encryption;
            WHEN (data_purpose='customer')
            --Format, identities, and casting from DATE to VARCHAR and back to DATE are all encapsulated in the case expression;
                then VoltageSecureProtect(value::VARCHAR USING PARAMETERS
                    format='birthday',
                    identity='customer_data@example.com')::DATE
            WHEN (data_purpose='employee')
                then VoltageSecureProtect(value::VARCHAR USING PARAMETERS
                    format='birthday',
                    identity='employee_data@example.com')::DATE
            ELSE
                THROW_ERROR('Unsupported data_purpose -- You must pass ''customer'' when
                encrypting customer data or ''employee'' when encrypting employee data')::DATE
                --Because the return type of this macro is DATE, THROW_ERROR must also be casted to type DATE;
        END);
    END;

对 customer_dob 表中的日期列进行加密:

=> SELECT encryptDOB('customer', dates) FROM customer_dob;
 encryptDOB
------------
 2048-08-09
 1917-03-05
 2022-01-07

单独对某个值进行加密:

=> SELECT encryptDOB('customer', '1955-11-04');
 encryptDOB
------------
 2048-08-09

您可以为解密定义一个匹配的宏。由于加密数据只能使用匹配的身份进行解密,因此这些 case 表达式使用相同的 data_purpose 和身份进行解密。

对于解密,定义以下宏:

=> CREATE FUNCTION decryptDOB(data_purpose VARCHAR, value DATE) RETURN DATE
    AS BEGIN
    RETURN
        (CASE
            --The case expressions and parameters must match the ones for encryption;
            WHEN (data_purpose='customer')
                then VoltageSecureAccess(value::VARCHAR USING PARAMETERS
                    format='birthday',
                    identity='customer_data@example.com')::DATE
            WHEN (data_purpose='employee')
                then VoltageSecureAccess(value::VARCHAR USING PARAMETERS
                    format='birthday',
                    identity='employee_data@example.com')::DATE
            ELSE
                THROW_ERROR('Unsupported data_purpose -- You must pass ''customer'' when
                decrypting customer data or ''employee'' when decrypting employee data')::DATE
        END);
    END;

对嵌套调用中的加密列进行解密:

=> SELECT decryptDOB('customer', encryptDOB('customer', dates)) FROM customer_dob;
 decryptDOB
------------
 1955-11-04
 1991-12-01
 1977-07-07
(3 rows)

单独对某个值进行解密:

=> SELECT decryptDOB('customer', '2048-08-09');
 decryptDOB
------------
 1955-11-04

删除这些宏:

=> DROP FUNCTION encryptDOB(VARCHAR, DATE);
DROP FUNCTION
=> DROP FUNCTION decryptDOB(VARCHAR, DATE);
DROP FUNCTION

8 - 授予用户对 Voltage SecureData 集成函数的访问权限

默认情况下,Vertica 用户无权访问 Voltage SecureData 集成函数。用户在没有正确权限的情况下尝试调用集成函数将收到以下错误:

=> SELECT id,
          first_name,
          last_name,
          VoltageSecureAccess(ssn USING PARAMETERS format='ssn',
                              config_dfs_path='/voltagesecure/conf') AS ssn,
          dob
          FROM customers
          WHERE dob < '1970-1-1'
          ORDER BY id ASC
          LIMIT 10;
ERROR 6482:  Failed to parse Access Policies for table "customers" [Function
public.VoltageSecureProtect(varchar) does not exist, or permission is denied for
public.VoltageSecureProtect(varchar)]

用户必须具有对集成函数的 EXECUTE 访问权限才能使用它们。这些函数是 PUBLIC 架构的一部分。Voltage SecureData 集成库中有以下函数:

以下示例演示了如何向用户 Alice 授予对 VoltageSecureAccess 函数的访问权限,以便能够解密数据。

=> \c vmart dbadmin
You are now connected to database "vmart" as user "dbadmin".
=> GRANT EXECUTE ON FUNCTION public.VoltageSecureProtect(VARCHAR) TO alice;
GRANT PRIVILEGE
=> \c vmart alice
You are now connected to database "vmart" as user "alice".
=> SELECT id, first_name, last_name,
          VoltageSecureAccess(ssn USING PARAMETERS format='ssn',
                              config_dfs_path='/voltagesecure/conf')
                              AS ssn,
          dob
          FROM customers
          WHERE dob < '1970-1-1'
          ORDER BY id ASC
          LIMIT 10;
  id  | first_name | last_name |     ssn     |    dob
------+------------+-----------+-------------+------------
 5345 | Thane      | Ross      | 559-32-0670 | 1902-03-09
 5348 | Basia      | Lopez     | 011-85-0705 | 1921-08-17
 5349 | Kaseem     | Hendrix   | 672-57-0309 | 1962-08-23
 5350 | Omar       | Lott      | 825-45-0131 | 1930-01-12
 5352 | Illana     | Middleton | 831-47-0929 | 1956-09-07
 5354 | Hanna      | Ware      | 694-97-0394 | 1903-07-16
 5358 | Mallory    | Vaughn    | 870-53-0272 | 1961-03-09
 5363 | Kirk       | Robinson  | 155-08-0085 | 1964-06-28
 5366 | Branden    | Coffey    | 709-38-0423 | 1923-06-11
 5367 | Raven      | Keith     | 250-31-0269 | 1918-07-31
(10 rows)

有关向用户授予对 UDx 的访问权限的详细说明,请参阅 GRANT(用户定义的扩展)

为 SecureData 用户创建角色

您可以创建可以访问这些函数的角色,而不是向单个用户授予对每个函数的访问权限。然后,您可以向需要访问 SecureData 函数的用户授予对这些角色的访问权限。

考虑创建至少两个角色:一个用于访问 VoltageSecureConfigure 函数,另一个用于访问其他函数。在大多数情况下,并非所有用户都需要访问 VoltageSecureConfigure,尤其是当您选择创建单个全局配置文件时。有关使用 VoltageSecureConfigure 的详细信息,请参阅配置对 SecureData 的访问权限

下面的例子:

  • 创建两个角色:有权保护和访问函数的 secure_data_users,以及有权访问 SecureDataConfigure 函数的 secure_data_admins。

  • 将 secure_data_user 角色授予用户 Alice

  • 将新角色设置为她的默认角色。

  • 切换到 Alice

  • 调用几个 SecureData 函数。

=> \c vmart dbadmin
You are now connected to database "vmart" as user "dbadmin".
=> CREATE ROLE secure_data_users;
CREATE ROLE
=> GRANT EXECUTE ON FUNCTION public.VoltageSecureAccess(varchar)
   TO secure_data_users;
GRANT PRIVILEGE
=> GRANT EXECUTE ON FUNCTION public.VoltageSecureProtect(varchar)
   TO secure_data_users;
GRANT PRIVILEGE
=> GRANT EXECUTE ON TRANSFORM FUNCTION
         public.VoltageSecureProtectAllKeys(varchar)
   TO secure_data_users;
GRANT PRIVILEGE
=> CREATE ROLE secure_data_admins;
CREATE ROLE
=> GRANT EXECUTE ON TRANSFORM FUNCTION public.VoltageSecureConfigure()
   TO secure_data_admins;
GRANT PRIVILEGE
=> GRANT secure_data_users TO ALICE;
GRANT ROLE
=> ALTER USER alice DEFAULT ROLE secure_data_users;
ALTER USER
=> \c vmart alice
You are now connected to database "vmart" as user "alice".
=> SET ROLE secure_data_users;
SET
=> SELECT VoltageSecureProtect('123-45-6789'
                               USING PARAMETERS format='ssn',
                               config_dfs_path='/voltagesecure/conf');
 VoltageSecureProtect
----------------------
 376-69-6789
(1 row)
=> SELECT VoltageSecureAccess('376-69-6789'
                              USING PARAMETERS format='ssn',
                              config_dfs_path='/voltagesecure/conf');
 VoltageSecureAccess
---------------------
 123-45-6789
(1 row)

=> SELECT VoltageSecureConfigure(USING PARAMETERS config_dfs_path='voltage.conf',
                                 username='alice', identity='alice@example.com',
                                ) OVER ();
ERROR 3457:  Function VoltageSecureConfigure() does not exist, or permission
is denied for VoltageSecureConfigure()
HINT:  No function matches the given name and argument types. You may need to
add explicit type casts

请注意,Alice 虽然无法访问 VoltageSecureConfigure 函数,但可以使用全局配置文件。

9 - 通过访问策略自动执行加密和解密

您可以通过创建访问策略来自动执行加密和解密。通过这些策略,您可以向具有特定角色的用户显示未加密的值,而不具有这些角色的用户看到的是加密的值。或者,您可以创建一个访问策略,在缺少特定角色的用户进行查询时屏蔽存储在数据库中的未加密数据。

当创建访问策略以自动加密和解密数据时,用户不会显式调用 SecureData 集成函数。但是,他们必须仍然能够访问 SecureData 函数并设置任何必要的会话变量。有关有效的访问策略所需的配置,请参阅配置对 SecureData 的访问权限授予用户对 Voltage SecureData 集成函数的访问权限。如果无权访问 SecureData 集成函数的用户使用用于调用这些函数的访问策略查询表,则查询将生成错误。

为特权用户自动解密表列

要自动解密加密列,如果用户启用了角色,请为加密列创建一个用于调用 VoltageSecureAccess 的访问策略。如果用户没有启用角色,则只返回加密的值。

下面的例子:

  1. 创建一个名为 see_ssn 的角色并将其授予名为 Alice 的用户,并授予 Alice 对客户表的访问权限。

  2. 如果用户启用了 see_ssn 角色,则在客户表的 ssn 列上创建一个用于解密该列值的访问策略。

  3. 切换到名为 Alice 的用户。

  4. 在未启用 see_ssn 角色的情况下查询客户表。

  5. 启用 see_ssn 角色并再次查询表。

=> CREATE ROLE see_ssn;
CREATE ROLE

=> GRANT see_ssn TO alice;
GRANT ROLE

=> GRANT ALL ON TABLE customers TO alice;
GRANT PRIVILEGE

=> CREATE ACCESS POLICY ON customers FOR COLUMN ssn
     CASE
         WHEN enabled_role('see_ssn') THEN VoltageSecureAccess(ssn USING PARAMETERS format='ssn',
                                                               config_dfs_path='/voltagesecure/conf')
         ELSE ssn
     END ENABLE;
CREATE ACCESS POLICY

=> \c vmart alice;
Password:
You are now connected to database "vmart" as user "alice".

=> SELECT first_name, last_name, ssn FROM customers WHERE id < 5355 ORDER BY id ASC;
 first_name | last_name |     ssn
------------+-----------+-------------
 Gil        | Reeves    | 997-92-0657
 Robert     | Moran     | 715-02-0455
 Hall       | Rice      | 938-83-0659
 Micah      | Trevino   | 495-57-0860
(4 rows)

=> SET ROLE see_ssn;
SET
=> SELECT first_name, last_name, ssn FROM customers WHERE id < 5355 ORDER BY id ASC;
 first_name | last_name |     ssn
------------+-----------+-------------
 Gil        | Reeves    | 232-28-0657
 Robert     | Moran     | 725-79-0455
 Hall       | Rice      | 285-90-0659
 Micah      | Trevino   | 853-60-0860
(4 rows)

在以上示例中,您可以将 see_ssn 角色与授予用户对 SecureData 集成函数的访问权限的角色相结合。不具有 see_ssn 角色的用户无需拥有对 SecureData 函数的访问权限即可查看加密的值。

为非特权用户自动加密列

您还可以创建用于加密值的访问策略。使用此技术可防止某些用户查看列中的特定值,这些值不够敏感,无需在数据库中进行加密,但又不能被所有用户看到。此技术与动态加密相反:在动态加密中,具有特定角色的用户从表中获取值;如果他们不具有角色,则访问策略会对该值进行加密。

下面的例子:

  1. 创建一个名为 see_dob 的角色并将其分配给用户 Alice。

  2. 在客户表的 dob 列上创建访问策略。如果用户激活了 see_dob 角色,则返回列中的值,否则将对该值进行加密。

  3. 切换到名为 Alice 的用户。

  4. 查询包含 dob 列的客户表。

  5. 设置 see_dob 角色并再次查询客户。

=> CREATE ROLE see_dob;
CREATE ROLE

=> GRANT see_dob TO alice;
GRANT ROLE

=> CREATE ACCESS POLICY ON customers FOR COLUMN dob
     CASE
         WHEN enabled_role('see_dob') THEN dob
         ELSE VoltageSecureProtect(dob::varchar USING PARAMETERS format='birthday',
                                   config_dfs_path='/voltagesecure/conf')::date
     END ENABLE;
CREATE ACCESS POLICY

=> \c vmart alice
Password:
You are now connected to database "vmart" as user "alice".

=> SELECT first_name, last_name, dob FROM customers ORDER BY id ASC LIMIT 10;
 first_name | last_name  |    dob
------------+------------+------------
 Gil        | Reeves     | 2048-08-09
 Robert     | Moran      | 1917-03-05
 Hall       | Rice       | 2022-01-07
 Micah      | Trevino    | 2018-06-01
 Kuame      | Stephenson | 2053-02-13
 Hedda      | Cooper     | 2002-03-12
 MacKenzie  | Burks      | 2061-10-30
 Anne       | Marquez    | 2078-08-02
 Dominic    | Avery      | 1940-08-10
 Alfreda    | Mcdaniel   | 1904-04-27
(10 rows)

=> SET ROLE see_dob;
SET

=> SELECT first_name, last_name, dob FROM customers ORDER BY id ASC LIMIT 10;
 first_name | last_name  |    dob
------------+------------+------------
 Gil        | Reeves     | 1955-11-04
 Robert     | Moran      | 1991-12-01
 Hall       | Rice       | 1977-07-07
 Micah      | Trevino    | 1980-12-05
 Kuame      | Stephenson | 1979-09-12
 Hedda      | Cooper     | 1987-05-02
 MacKenzie  | Burks      | 1982-11-07
 Anne       | Marquez    | 1949-07-09
 Dominic    | Avery      | 1976-12-02
 Alfreda    | Mcdaniel   | 1975-02-08
(10 rows)

在前面的示例中,未启用 see_dob 角色的用户必须具有对 SecureData 函数的访问权限才能查看屏蔽的值。如果他们不具有对 SecureData 函数的访问权限,则查询客户表时会出现错误消息。以下示例创建了一个名为 Bob 的新用户,并授予他对客户表的访问权限,但未授予其对 SecureData 函数的任何访问权限。

=> CREATE USER bob;
CREATE USER
=> GRANT ALL ON TABLE customers TO bob;
GRANT PRIVILEGE
=> \c vmart bob
You are now connected to database "vmart" as user "bob".
=> SELECT * FROM customers LIMIT 10;
ERROR 6482:  Failed to parse Access Policies for table "customers"
[Function public.VoltageSecureProtect(varchar) does not exist, or permission
is denied for public.VoltageSecureProtect(varchar)]

10 - 查询 eFPE 加密列

您可以使用 Voltage SecureData 中的嵌入格式保留加密功能来加密数据。在 SecureData 设备中定义格式时,可以选择使用 eFPE。此格式与标准 FPE 格式略有不同。此格式使用密钥轮换,并将标识信息嵌入到加密值中。由于这些因素,使用 eFPE 格式调用 VoltageSecureProtect 可能会生成不同的加密值,具体取决于密钥轮换计划和调用方的身份。此功能使查询使用 eFPE 格式加密的列更具挑战性。

如果要搜索标准 FPE 加密列中的某个值,只需使用 VoltageSecureProtect 加密纯文本并在查询中使用输出。例如,假设要在客户表中搜索社会保险号为 559-32-0670 的条目。那么您可以使用以下查询:

=> SELECT id, first_name, last_name FROM customers
       WHERE ssn = VoltageSecureProtect('559-32-0670' USING PARAMETERS
                                        format='ssn',
                                        config_dfs_path='voltage.conf');

  id  | first_name | last_name
------+------------+-----------
 5345 | Thane      | Ross
(1 row)

查询使用 eFPE 格式加密的列并不简单,因为您不知道加密数据所使用的嵌入式密钥。您可以使用 VoltageSecureAccess 函数来解密表列的全部内容并在结果中搜索您需要的值。但是,这样效率过低,因为必须为表中的每一行数据调用 SecureData 函数。

更好的解决方案是使用 VoltageSecureProtectAllKeys 函数。此函数类似于 VoltageSecureProtect。但是,它不是返回单个加密值,而是返回一个包含使用为 eFPE 格式定义的每个密钥加密的值的表。

=> SELECT VoltageSecureProtectAllKeys('376765616314013' USING PARAMETERS
                                      format='cc_num',
                                      config_dfs_path='/voltagesecure/conf')
          OVER ();

      data       |    protected
-----------------+-----------------
 376765616314013 | XMVMRU9RJVU4013
 376765616314013 | X5FD4KO1UEE4013
 376765616314013 | M7ZXTIQVCPB4013
 376765616314013 | UBOSC9K3EXZ4013
 376765616314013 | ZJ1C50C9L9R4013
(5 rows)

在前面的示例中,cc_num 列使用 eFPE 格式进行加密。VoltageSecureProtectAllKeys 输出中显示此 eFPE 格式定义了 5 个密钥。受保护列的内容中包含使用每个密钥加密的相同值。

要在查询 eFPE 列中的值时使用此函数,请在当前搜索的表和 VoltageSecureProtectAllKeys 生成的结果表上使用 JOIN。以下示例演示了如何查询客户表以查找 cc_num 值与未加密信用卡值 376765616314013 匹配的所有行。

=> SELECT id, first_name, last_name FROM customers3 u
          JOIN (SELECT VoltageSecureProtectAllKeys('376765616314013' USING PARAMETERS
                                                   format='cc_num',
                                                   config_dfs_path='/voltagesecure/conf')
          OVER ()) pak
          ON u.cc_num = pak.protected;

  id  | first_name | last_name
------+------------+-----------
 5345 | Thane      | Ross

(1 row)

11 - Voltage SecureData 集成函数引用

本节中的函数是 Vertica voltagesecure 库的一部分,用于与 Voltage SecureData 集成。这些函数会在安装或升级 Vertica 时自动安装。但是,必须重新安装 voltagesecure 库才能将 CA 证书分发给 Vertica 群集中的所有节点。有关说明,请参阅验证 Vertica 服务器对 SecureData CA 证书的访问权限

11.1 - VoltageSecureAccess

调用 SecureData 对使用 VoltageSecureProtect 加密的密文进行解密。

语法

VoltageSecureAccess('ciphertext' [, 'tweak'] USING PARAMETERS
                    format='format_name'
                    [, mask=is_masked]
                    [, config_dfs_path='config_file']
                    [, identity=sd_identity]);

参数

示例

以下示例解密最初使用预定义格式加密的社会安全号码 (SSN)。


=> SELECT VoltageSecureAccess('376-69-6789' USING PARAMETERS format='ssn');

 VoltageSecureAccess
---------------------
 123-45-6789
(1 row)

此示例演示解密查询中的加密列。

=> SELECT id,
          first_name,
          last_name,
          VoltageSecureAccess(ssn USING PARAMETERS format='ssn',
                              config_dfs_path='/voltagesecure/conf') AS ssn,
          dob
      FROM customers
      WHERE dob < '1970-1-1'
      ORDER BY id ASC
      LIMIT 10;

  id  | first_name | last_name  |     ssn     |    dob
------+------------+------------+-------------+------------
 5346 | Talon      | Wilkins    | 540-48-0784 | 1941-09-17
 5347 | Daquan     | Phelps     | 785-34-0092 | 1963-05-08
 5348 | Basia      | Lopez      | 011-85-0705 | 1940-04-29
 5349 | Kaseem     | Hendrix    | 672-57-0309 | 1942-03-11
 5350 | Omar       | Lott       | 825-45-0131 | 1956-02-17
 5352 | Illana     | Middleton  | 831-47-0929 | 1949-12-29
 5353 | Garrett    | Williamson | 408-73-0207 | 1955-11-06
 5354 | Hanna      | Ware       | 694-97-0394 | 1967-08-08
 5355 | Quinn      | Pruitt     | 818-91-0359 | 1965-11-14
 5356 | Clayton    | Santiago   | 102-56-0010 | 1958-02-02
(10 rows)

以下示例使用预定义的格式解密 Unicode。有关预定义格式的完整列表,请参阅 Voltage SecureData 文档。


=> SELECT VoltageSecureAccess('607-Òdìçç-ぶてぴねら' using parameters format='PREDEFINED::JU_AUTO_TYPE');

 VoltageSecureAccess
----------------------
 123-Hello-こんにちは

使用原始 FPE 格式解密 SSN 密文并调整值:

=> SELECT VoltageSecureAccess('721-21-2913', 'tweakvalue123' USING PARAMETERS
                                  format='ssn-tweak',
                                  config_dfs_path='voltage.conf');
 VoltageSecureProtect
----------------------
 681-09-2913

解密使用掩码格式加密的密文。这种格式将隐藏除解密纯文本的最后两个字符以外的所有字符。


=> SELECT VoltageSecureAccess('g3kbx6ru19', USING PARAMETERS
                                  format='maskedFormat',
                                  config_dfs_path='voltage.conf');
 VoltageSecureAccess
----------------------
 1234567890

=> SELECT VoltageSecureAccess('g3kbx6ru19', USING PARAMETERS
                                  format='maskedFormat',
                                  config_dfs_path='voltage.conf',
                                  mask=true);
 VoltageSecureAccess
----------------------
 XXXXXXXX90

另请参阅

11.2 - VoltageSecureConfigure

将 SecureData 用户访问配置参数保存到 Vertica 分布式文件系统 (DFS) 的文件中。然后将文件名传递给其他 SecureData 集成函数。此函数可以将配置文件存储在用户自己的 DFS 目录中,也可以存储在一个全局可访问的名为 /voltagesecure/conf 的文件中。

语法

VoltageSecureConfigure(USING PARAMETERS config_dfs_path='filename'
                              [, identity=sd_identity]
                              [, store_password=Boolean]
                              [, store_shared_secret=Boolean]
                              [, username=sd_user]
                  ) OVER ();

参数

注意

  • 设置的任何 SecureData 会话变量都会覆盖配置文件中的值。有关详细信息,请参阅配置对 SecureData 的访问权限

  • SecureData 集成一次仅支持 SecureData 设备的一个配置。
  • 一般情况下,用户无法直接从 DFS 中存储的文件中读取数据。但是,对于所有有权访问从 DFS 读取 UDx 函数的用户而言,均有权从 Vertica 中访问这些文件。

    此外,这些文件以纯文本形式存储在每个节点的文件系统中。任何对节点具有适当文件系统访问权限的人员均可读取该文件的内容。

    决定是否将密码或共享机密等敏感信息存储在共享的或每个用户的配置文件中时,您均应考虑上述这两个事实。

示例

以下示例演示了如何将配置信息保存到用户自己的 Vertica DFS 目录的 voltage.conf 配置文件中。

=> \x
Expanded display is on.
=> SELECT VoltageSecureConfigure(USING PARAMETERS config_dfs_path='voltage.conf',
                                 username='alice', identity='alice@example.com', store_password=false
                                ) OVER ();
-[ RECORD 1 ]-----+----------------------------------------------------------------
config_dfs_path   | voltage.conf
identity          | alice@example.com
username          | alice

11.3 - VoltageSecureConfigureGlobal

将所有用户的全局 SecureData 访问配置参数保存到 Vertica 分布式文件系统 (DFS) 中的文件中。此函数将名为 /voltagesecure/conf.global 的配置文件存储在分布式文件系统 (DFS) 中。您必须使用此函数至少配置 SecureData 策略 URL,然后才能使用任何其他 Voltage SecureData 集成函数。

要刷新客户端策略,请参阅 VoltageSecureRefreshPolicy

语法

VoltageSecureConfigureGlobal(USING PARAMETERS policy_url=url
                              [, allow_short_fpe=Boolean]
                              [, allow_file_cache=Boolean]
                              [, network_timeout=Integer]
                            ) OVER ();

参数

示例

将策略 URL 设置为 https://voltage-pp-0000.example.com/policy/clientPolicy.xml 并将网络超时设置为 200 秒:

=> SELECT VoltageSecureConfigureGlobal(USING PARAMETERS
                                       policy_url='https://voltage-pp-0000.example.com/policy/clientPolicy.xml',
                                       NETWORK_TIMEOUT=200)
                                       OVER ();

                           policy_url                            | allow_short_fpe | enable_file_cache | network_timeout
-----------------------------------------------------------------+-----------------+-------------------+-----------------
 https://voltage-pp-0000.example.com/policy/clientPolicy.xml     |                 |                   | 200
(1 row)

查看当前策略:

=> SELECT VoltageSecureConfigureGlobal() OVER();
                           policy_url                            | allow_short_fpe | enable_file_cache | network_timeout
-----------------------------------------------------------------+-----------------+-------------------+-----------------
 https://voltage-pp-0000.example.com/policy/clientPolicy.xml     |                 |                   | 200
(1 row)

跨节点手动刷新客户端策略:

=> SELECT VoltageSecureRefreshPolicy() OVER ();
                                  PolicyRefresh
-------------------------------------------------------------------------------------
Successfully refreshed policy on node [v_sandbox_node0001]. Policy on other nodes
will be refreshed the next time a Voltage operation is run on them.
(1 row)

11.4 - VoltageSecureProtect

调用 SecureData 对值进行加密或 Hash ,与此同时保留原始纯文本的结构。

语法

VoltageSecureProtect('plaintext' [, 'tweak'] USING PARAMETERS
                    format='format_name'
                    [, config_dfs_path='config_file']
                    [, identity=sd_identity]);

参数

示例

使用 ssnauto FPE 格式加密社会保险号 (SSN) 值(此示例假定已在会话中设置了所有必要的 SecureData 身份验证信息变量):


=> SELECT VoltageSecureProtect('123-45-6789' USING PARAMETERS format='ssn');
 VoltageSecureProtect
----------------------
 376-69-6789
(1 row)

=> SELECT VoltageSecureProtect('123-45-6789' USING PARAMETERS format='auto');
 VoltageSecureProtect
----------------------
 820-31-5110
(1 row)

在 COPY 语句中加密两个表列,使用保存在 DFS 中的用户私有配置文件对 SecureData Appliance 进行身份验证:


=> COPY customers (id, first_name, last_name, ssn_raw FILLER VARCHAR(11),
                   cc_num_raw FILLER VARCHAR(25), cvv, dob,
                   ssn AS VoltageSecureProtect(ssn_raw USING PARAMETERS
                                               format='ssn',
                                               config_dfs_path='voltage.conf'),
                   cc_num AS VoltageSecureProtect(cc_num_raw USING PARAMETERS
                                                  format='cc',
                                                  config_dfs_path='voltage.conf'))
        FROM '/home/dbadmin/customer_data.csv' DELIMITER ',';
 Rows Loaded
-------------
         100
(1 row)

查询加密列中的特定值:

=> SELECT id, first_name, last_name FROM customers
       WHERE ssn = VoltageSecureProtect('559-32-0670' USING PARAMETERS
                                        format='ssn',
                                        config_dfs_path='voltage.conf');

  id  | first_name | last_name
------+------------+-----------
 5345 | Thane      | Ross
(1 row)

加密 NULL 值返回 NULL:


=> CREATE TABLE nulltable(n VARCHAR (20));
=> INSERT INTO nulltable VALUES (NULL);

=> SELECT VoltageSecureProtect(n USING PARAMETERS format='auto') FROM nulltable;
VoltageSecureProtect
---------------------

(1 row)

使用预定义的格式加密 Unicode 字符串。有关预定义格式的完整列表,请参阅 Voltage SecureData 文档。


=> SELECT VoltageSecureProtect('123-Hello-こんにちは' USING PARAMETERS format='PREDEFINED::JU_AUTO_TYPE');
VoltageSecureProtect
----------------------
607-Òdìçç-ぶてぴねら

使用调整值加密 SSN:


=> SELECT VoltageSecureProtect('681-09-2913', 'tweakvalue123' USING PARAMETERS
    format='ssn-tweak');

 VoltageSecureProtect
----------------------
 721-21-2913

=> SELECT VoltageSecureAccess('721-21-2913', 'tweakvalue123' USING PARAMETERS
    format='ssn-tweak');

 VoltageSecureProtect
----------------------
 681-09-2913

Hash 具有 FPH 格式和调整值的 SSN:


=> SELECT VoltageSecureProtect('681-09-2913', 'tweakvalue123' USING PARAMETERS
                                  format='ssnHash',
                                  config_dfs_path='voltage.conf');
VoltageSecureProtect
----------------------
841-68-2913

另请参阅

11.5 - VoltageSecureProtectAllKeys

此函数可帮助您定位使用嵌入式格式保留加密 (eFPE) 格式加密的列中的值。这些格式采样密钥轮换,因此您为一段纯文本返回的加密值会不断变化。如果向此函数传递一个未加密的值,它将返回一个包含两列的表:未加密的值以及使用为 eFPE 定义的每个密钥加密的值。表中的行数由 eFPE 格式包含的密钥数决定。通常,您可以在联接中使用此函数的输出来定位表中匹配的加密值。

语法

VoltageSecureProtectAllKeys(value USING PARAMETERS format='eFPE_format'
                            [, config_dfs_path=config_file]
                            [, identity=sd_identity] )

参数

示例

以下示例演示了对 VoltageSecureProtectAllKeys 的简单调用。

=> SELECT VoltageSecureProtectAllKeys('376765616314013' USING PARAMETERS
                                      format='cc_num',
                                      config_dfs_path='/voltagesecure/conf')
          OVER ();

      data       |    protected
-----------------+-----------------
 376765616314013 | XMVMRU9RJVU4013
 376765616314013 | X5FD4KO1UEE4013
 376765616314013 | M7ZXTIQVCPB4013
 376765616314013 | UBOSC9K3EXZ4013
 376765616314013 | ZJ1C50C9L9R4013
(5 rows)

在此示例中,cc_num eFPE 格式定义了 5 个密钥,因此将返回一个包含 5 行的表。

以下示例显示了更常见的用法:查询使用 eFPE 格式加密的表列。

=> SELECT id, first_name, last_name FROM customers3 u
          JOIN (SELECT VoltageSecureProtectAllKeys('376765616314013' USING PARAMETERS
                                                   format='cc_num',
                                                   config_dfs_path='/voltagesecure/conf')
          OVER ()) pak
          ON u.cc_num = pak.protected;

  id  | first_name | last_name
------+------------+-----------
 5345 | Thane      | Ross

(1 row)

在前面的示例中,customers3 表与 VoltageSecureProtectAllKeys 的输出相联接。如果 customers3 表中加密的 cc_num 列值与 VoltageSecureProtectAllKeys 的受保护列中的值匹配,则该表中的所有行都会出现在输出中。

如果您在非 eFPE 格式下使用此函数,将返回错误:

=> SELECT first_name, last_name, ssn FROM customers u
        JOIN (
            SELECT VoltageSecureProtectAllKeys('232-28-0657' USING PARAMETERS format='ssn',
                                               config_dfs_path='/voltagesecure/conf')
            OVER ()
        )
        pak ON u.ssn = pak.protected;
ERROR 5861:  Error calling processPartition() in User Function VoltageSecureProtectAllKeys
at [ProtectAllKeys.cpp:21], error code: 1711, message: Error getting key numbers:
eFPE format required

另请参阅

11.6 - VoltageSecureRefreshPolicy

立即刷新启动程序节点上的客户端策略。下次在非启动程序节点上调用 Voltage 函数时,将刷新其上的策略。

语法

VoltageSecureRefreshPolicy()

参数

示例

跨节点手动刷新客户端策略:

=> SELECT VoltageSecureRefreshPolicy() OVER ();
                                  PolicyRefresh
-------------------------------------------------------------------------------------
Successfully refreshed policy on node [v_sandbox_node0001]. Policy on other nodes
will be refreshed the next time a Voltage operation is run on them.
(1 row)

另请参阅