PostgreSQL 透明加密(TDE,FDE) - 块级加密

简介:

PostgreSQL 透明加密(TDE,FDE) - 块级加密

作者

digoal

日期

2016-10-31

标签

PostgreSQL , 透明加密 , TDE , FDE , 块级加密


背景

在数据库应用中,为了提高数据的安全性,可以选择很多中安全加固的方法。

例如,

1. 可以对敏感字段进行加密,可以使用服务端加密,也可以使用数据库端加密,例如pgcrypto加密插件。

服务端加解密相对来说比较安全,因为在数据库端存储的是加密后的数据,只要服务端的秘钥保护好,基本上数据都是安全的。

但是服务端加密有一个痛点,失去了对数据的高效访问能力,例如数据库无法对加密后的数据很好的构建索引,或者处理函数。(通常只能对未加密的数据进行处理)。

当然PG是一个比较开放的平台,用户可以自定义对加密数据类型操作的UDF,索引方法,操作符等。

用户也可以自定义加密的数据类型,基于此构建新的OP, AM, FUNC。

2. 有些商业数据库支持TDE,类似我前面说的(自定义加密类型,同时还自定义了对应的OP, AM, FUNC)。

3. 网络层加密,这种加密方法主要是防止网络层泄露数据。

4. 数据块层面的加密,这种加密方法主要是防止数据文件被拷贝后泄露数据。

加密会损失一定的计算资源,损耗性能。

本文要讲的则是数据块层面的加密,这是cybertec开源的一个PostgreSQL版本,支持所有数据文件的加密(FDE),采用Industry standard 128-bit XTS-AES block cipher。

块级加密,FDE

The idea behind the patch is to store all the files making up a PostgreSQL cluster securely on disk in encrypted format (data-at-rest encryption) and then decrypt blocks as they are read from disk.

This only requires that the database is initialized with encryption in mind and that the key used for initializing the database is accessible to the server during startup.

The encryption-key can be provided in two ways –

1. through an environment variable or

2. through a special configuration parameter specifying a custom key setup command for implementing special security requirements.

pic1

加密解密是在读写文件时完成的,所以如果数据已经在shared buffer中了,对性能的影响就很小了。

For encryption 128-bit AES algorithm in XTS mode is used, sometimes called also XTS-AES.

It’s a block cipher with a “tweak” for extra security and adheres to IEEE P1619 standard.

The key needs to be provided to the server during every startup and when it doesn’t match, the server will refuse to start.

Encrypted will be more or less everything – heap files (tables, indexes, sequences), xlog (as they also contain data), clog, temporary files being generated during execution of a larger query.

Performance penalty incurred by encryption/decryption depends heavily on concrete use cases.

For cases where working set fits well into PostgreSQL shared buffers, it is practically negligible though.

测试

下载

$ wget http://www.cybertec.at/download/postgresql-9.6.0-fde.tar.bz2

$ tar -jxvf postgresql-9.6.0-fde.tar.bz2
$ cd postgresql-9.6.0-fde

$ ll
total 1108
-rw-r--r--  1 digoal users    384 Sep 27 04:26 aclocal.m4
-rw-r--r--  1 digoal users   5357 Oct 24 19:11 brg_endian.h
-rw-r--r--  1 digoal users   7855 Oct 24 19:11 brg_types.h
drwxr-xr-x  2 digoal users   4096 Sep 27 04:30 config
-rw-r--r--  1 digoal users 368646 Oct 31 09:50 config.log
-rwxr-xr-x  1 digoal users  39393 Oct 31 09:50 config.status
-rwxr-xr-x  1 digoal users 471157 Sep 27 04:26 configure
-rw-r--r--  1 digoal users  75195 Sep 27 04:26 configure.in
drwxr-xr-x 55 digoal users   4096 Sep 27 04:30 contrib
-rw-r--r--  1 digoal users   1192 Sep 27 04:26 COPYRIGHT
drwxr-xr-x  3 digoal users   4096 Sep 27 04:30 doc
-rw-r--r--  1 digoal users   3638 Oct 31 09:50 GNUmakefile
-rw-r--r--  1 digoal users   3638 Sep 27 04:26 GNUmakefile.in
-rw-r--r--  1 digoal users    283 Sep 27 04:26 HISTORY
-rw-r--r--  1 digoal users  75065 Sep 27 04:33 INSTALL
-rw-r--r--  1 digoal users    676 Oct 24 19:11 Makefile.rej
-rw-r--r--  1 digoal users  11026 Oct 24 19:11 mode_hdr.h
-rw-r--r--  1 digoal users   1209 Sep 27 04:26 README
-rw-r--r--  1 digoal users   4455 Oct 24 19:10 README.encryption
drwxr-xr-x 16 digoal users   4096 Oct 31 09:50 src

编译, 与普通版本pg没什么不同

$ ./configure --prefix=/home/digoal/pgsql9.6-fde
$ make world -j 32
$ make install-world

设置环境变量

$ vi ~/env_pg96fde.sh 
export PS1="$USER@`/bin/hostname -s`-> "
export PGPORT=5388
export PGDATA=/disk1/digoal/pgdata/pg_root9.6fde
export LANG=en_US.utf8
export PGHOME=/home/digoal/pgsql9.6-fde
export LD_LIBRARY_PATH=$PGHOME/lib:/lib64:/usr/lib64:/usr/local/lib64:/lib:/usr/lib:/usr/local/lib:$LD_LIBRARY_PATH
export DATE=`date +"%Y%m%d%H%M"`
export PATH=$PGHOME/bin:/opt/rh/devtoolset-2/root/usr/bin:$PATH:.
export MANPATH=$PGHOME/share/man:$MANPATH
export PGHOST=127.0.0.1
export PGUSER=postgres
export PGDATABASE=postgres
alias rm='rm -i'
alias ll='ls -lh'
unalias vi


$ . ~/env_pg96fde.sh 

设置加密秘钥, 初始化数据库集群, 需要读取PGENCRYPTIONKEY这个环境变量的值.

初始化时已经对所有的文件进行了块级别的加密, 建议打开checksum.

$ read -sp "Postgres passphrase: " PGENCRYPTIONKEY
$ export PGENCRYPTIONKEY
$ echo $PGENCRYPTIONKEY
$ initdb --data-encryption pgcrypto --data-checksums -D $PGDATA -E SQL_ASCII --locale=C -U postgres

初始化好之后,postgresql.conf会自动新增一个guc配置

$ less $PGDATA/postgresql.conf
encryption_library = 'pgcrypto'

启动数据库,注意每次启动数据库前,必须设置好 PGENCRYPTIONKEY这个环境变量的值.

$ pg_ctl start

加解密会对性能带来一定的损耗,简单的测试如下。

加密版本PostgreSQL

$ psql
Type "help" for help.
postgres=# create unlogged table test(id int);
CREATE TABLE
postgres=# \timing
Timing is on.
postgres=# insert into test select generate_series(1,10000000);
INSERT 0 10000000
Time: 8157.507 ms
postgres=# select max(ctid) from test;
     max     
-------------
 (44247,178)
(1 row)
Time: 5331.924 ms

profile

3358.00 21.9% rijndael_encrypt                               /home/digoal/pgsql9.6-fde/lib/pgcrypto.so                         
 591.00  3.9% ExecModifyTable                                /home/digoal/pgsql9.6-fde/bin/postgres                            
 487.00  3.2% LWLockRelease                                  /home/digoal/pgsql9.6-fde/bin/postgres                            
 404.00  2.6% heap_insert                                    /home/digoal/pgsql9.6-fde/bin/postgres                            
 395.00  2.6% LWLockAttemptLock                              /home/digoal/pgsql9.6-fde/bin/postgres                            
 373.00  2.4% ExecProject                                    /home/digoal/pgsql9.6-fde/bin/postgres                            
 372.00  2.4% RelationPutHeapTuple                           /home/digoal/pgsql9.6-fde/bin/postgres                            
 360.00  2.3% hash_any                                       /home/digoal/pgsql9.6-fde/bin/postgres                            
 344.00  2.2% xor_block_aligned                              /home/digoal/pgsql9.6-fde/lib/pgcrypto.so                         
 332.00  2.2% hash_search_with_hash_value                    /home/digoal/pgsql9.6-fde/bin/postgres                            
 295.00  1.9% PageAddItemExtended                            /home/digoal/pgsql9.6-fde/bin/postgres                            
 294.00  1.9% PinBuffer.isra.3                               /home/digoal/pgsql9.6-fde/bin/postgres                            
 292.00  1.9% RelationGetBufferForTuple                      /home/digoal/pgsql9.6-fde/bin/postgres                            
 284.00  1.9% PageGetHeapFreeSpace                           /home/digoal/pgsql9.6-fde/bin/postgres                            
 273.00  1.8% ReadBuffer_common                              /home/digoal/pgsql9.6-fde/bin/postgres                            
 267.00  1.7% IsCatalogRelation                              /home/digoal/pgsql9.6-fde/bin/postgres                            
 252.00  1.6% ExecMakeFunctionResult                         /home/digoal/pgsql9.6-fde/bin/postgres                            
 242.00  1.6% heap_form_tuple                                /home/digoal/pgsql9.6-fde/bin/postgres                            
 239.00  1.6% ftrace_raw_init_event_xfs_dir2_leafn_add       /lib/modules/2.6.32-358.23.2.ali1195.el6.x86_64/kernel/fs/xfs/xfs.ko
 223.00  1.5% tag_hash                                       /home/digoal/pgsql9.6-fde/bin/postgres                            
 221.00  1.4% copy_user_generic_string                       [kernel.kallsyms]                                                   
 201.00  1.3% UnpinBuffer.constprop.10                       /home/digoal/pgsql9.6-fde/bin/postgres                            
 195.00  1.3% heap_prepare_insert                            /home/digoal/pgsql9.6-fde/bin/postgres                            
 161.00  1.0% MarkBufferDirty                                /home/digoal/pgsql9.6-fde/bin/postgres                            
 157.00  1.0% LWLockAcquire                                  /home/digoal/pgsql9.6-fde/bin/postgres                            
 145.00  0.9% ReadBufferExtended                             /home/digoal/pgsql9.6-fde/bin/postgres                            
 143.00  0.9% heap_fill_tuple                                /home/digoal/pgsql9.6-fde/bin/postgres                            
 141.00  0.9% GetPrivateRefCountEntry                        /home/digoal/pgsql9.6-fde/bin/postgres                            
 128.00  0.8% generate_series_step_int4                      /home/digoal/pgsql9.6-fde/bin/postgres                            
 127.00  0.8% xts_encrypt_block                              /home/digoal/pgsql9.6-fde/lib/pgcrypto.so

非加密版本PostgreSQL

$ psql
Type "help" for help.
postgres=# create unlogged table test(id int);
CREATE TABLE
postgres=# \timing
Timing is on.
postgres=# insert into test select generate_series(1,10000000);
INSERT 0 10000000
Time: 6930.947 ms
postgres=# select max(ctid) from test;
     max     
-------------
 (44247,178)
(1 row)
Time: 1779.663 ms

profile

702.00  3.4% ExecMakeFunctionResult                         /home/digoal/pgsql9.6/bin/postgres
689.00  3.4% heap_prepare_insert                            /home/digoal/pgsql9.6/bin/postgres
671.00  3.3% LWLockRelease                                  /home/digoal/pgsql9.6/bin/postgres
521.00  2.6% ExecModifyTable                                /home/digoal/pgsql9.6/bin/postgres
493.00  2.4% ExecProject                                    /home/digoal/pgsql9.6/bin/postgres
482.00  2.4% LWLockAttemptLock                              /home/digoal/pgsql9.6/bin/postgres
458.00  2.2% pgstat_count_heap_insert                       /home/digoal/pgsql9.6/bin/postgres
451.00  2.2% PageAddItemExtended                            /home/digoal/pgsql9.6/bin/postgres
446.00  2.2% ReadBuffer_common                              /home/digoal/pgsql9.6/bin/postgres

除了使用PGENCRYPTIONKEY环境变量,还可以使用pgcrypto.keysetup_command参数来指定

$ pg_ctl start
server starting
$ LOG:  encryption key not provided
DETAIL:  The database cluster was initialized with encryption but the server was started without an encryption key.
HINT:  Set the key using PGENCRYPTIONKEY environment variable.
FATAL:  data encryption could not be initialized
LOG:  database system is shut down



Optionally if you want to implement a custom procedure for looking up the 
encryption key using pgcrypto.keysetup_command postgresql.conf parameter. 
When this parameter is present it will be executed by PostgreSQL at startup 
and the output processed. Expected output is a string containing 
encryptionkey= and the 256bit key encoded as a hex string (64 hex 
characters):

    "encryptionkey=" ( [0-9a-f]{64} )

To calculate the key from the passphrase hash it using SHA-256.

秘钥传输相关的代码

void
_PG_init(void)
{
        EncryptionRoutines routines;
        routines.SetupEncryption = &pgcrypto_encryption_setup;
        routines.EncryptBlock = &pgcrypto_encrypt_block;
        routines.DecryptBlock = &pgcrypto_decrypt_block;

        register_encryption_module("pgcrypto", &routines);

        DefineCustomStringVariable("pgcrypto.keysetup_command",
                           "Command to fetch database encryption key",
                           "This command will be run at database startup to set up database"
                           " encryption key.",
                           &pgcrypto_keysetup_command,
                           "",
                           PGC_POSTMASTER,
                           0,
                           NULL,
                           NULL,
                           NULL);

        EmitWarningsOnPlaceholders("pgcrypto");
}



const char* encryptionkey_prefix = "encryptionkey=";
const int encryption_key_length = 32;

static bool pgcrypto_run_keysetup_command(uint8 *key)
{
        FILE *fp;
        char buf[encryption_key_length*2+1];
        int bytes_read;
        int i;

        if (pgcrypto_keysetup_command == NULL)
                return false;

        if (!strlen(pgcrypto_keysetup_command))
                return false;

        elog(INFO, "Executing \"%s\" to set up encryption key", pgcrypto_keysetup_command);

        fp = popen(pgcrypto_keysetup_command, "r");
        if (fp == NULL)
                elog(ERROR, "Failed to execute pgcrypto.keysetup_command \"%s\"",
                        pgcrypto_keysetup_command);

        if (fread(buf, 1, strlen(encryptionkey_prefix), fp) != strlen(encryptionkey_prefix))
                elog(ERROR, "Not enough data received from pgcrypto.keysetup_command");

        if (strncmp(buf, encryptionkey_prefix, strlen(encryptionkey_prefix)) != 0)
                elog(ERROR, "Unknown data received from pgcrypto.keysetup_command");

        bytes_read = fread(buf, 1, encryption_key_length*2 + 1, fp);
        if (bytes_read < encryption_key_length*2)
        {
                if (feof(fp))
                        elog(ERROR, "Encryption key provided by pgcrypto.keysetup_command too short");
                else
                        elog(ERROR, "pgcrypto.keysetup_command returned error code %d", ferror(fp));
        }

        for (i = 0; i < encryption_key_length; i++)
        {
                if (sscanf(buf+2*i, "%2hhx", key + i) == 0)
                        elog(ERROR, "Invalid character in encryption key at position %d", 2*i);
        }
        if (bytes_read > encryption_key_length*2)
        {
                if (buf[encryption_key_length*2] != '\n')
                        elog(ERROR, "Encryption key too long '%s' %d.", buf, buf[encryption_key_length*2]);
        }

        while (fread(buf, 1, sizeof(buf), fp) != 0)
        {
                /* Discard rest of the output */
        }

        pclose(fp);


        return true;
}
目录
相关文章
|
6月前
|
存储 安全 Cloud Native
云原生安全必修课:RDS透明加密(TDE)与数据脱敏联动实施方案
云原生环境下,数据泄露风险日益严峻,传统安全方案面临加密与脱敏割裂、保护不连续、权限控制粗放三大挑战。本方案融合TDE透明加密与动态数据脱敏技术,构建存储-传输-计算全链路防护体系,通过SQL级加密与角色化脱敏规则,实现细粒度数据保护。结合密钥管理、权限控制与多云适配,提升安全性与性能,广泛适用于金融、医疗等高安全要求场景。
221 3
|
5月前
|
安全 关系型数据库 网络安全
安全加固:启动PostgreSQL 14服务器SSL加密的方法指南在CentOS 7环境中
通过上述步骤,你可以为PostgreSQL数据库服务器设置SSL加密,从而增加数据在传输中的安全性。确保维持证书的有效性,并且定期更新和管理密钥,以防止未授权访问。
277 0
|
关系型数据库 MySQL 分布式数据库
PolarDB产品使用合集之polardb支持透明数据加密TDE吗
PolarDB是阿里云推出的一种云原生数据库服务,专为云设计,提供兼容MySQL、PostgreSQL的高性能、低成本、弹性可扩展的数据库解决方案,可以有效地管理和优化PolarDB实例,确保数据库服务的稳定、高效运行。以下是使用PolarDB产品的一些建议和最佳实践合集。
173 0
PolarDB产品使用合集之polardb支持透明数据加密TDE吗
|
关系型数据库 分布式数据库 数据库
如何为PolarDB数据库设置透明数据加密(TDE)
如何为PolarDB数据库设置透明数据加密(TDE) 透明数据加密(TDE,Transparent Data Encryption)是PolarDB数据库提供的一种实时I/O加密和解密功能,数据在写入磁盘之前进行加密,从磁盘读入内存时进行解密,而不会增加数据文件的大小。开发人员无需更改任何应用程序,即可使用TDE功能。
362 3
|
关系型数据库 数据安全/隐私保护 PostgreSQL
Cybertec PostgreSQL透明加密解析
Cybertec PostgreSQL透明加密解析
489 0
|
存储 搜索推荐 算法
PolarDB for PostgreSQL透明加密
PolarDB for PostgreSQL透明加密
366 0
|
存储 安全 关系型数据库
PostgreSQL透明数据加密
PostgreSQL透明数据加密
491 0
|
存储 安全 关系型数据库
【DB吐槽大会】第80期 - PG 不支持透明加密(TDE)功能
大家好,这里是DB吐槽大会,第80期 - PG 不支持透明加密(TDE)功能
|
存储 SQL 安全
数据库必知词汇: 透明数据加密(TDE)
企业一般可以采取多种预防措施来帮助保护数据库,例如,设计安全系统、加密机密资产,以及围绕数据库服务器构建防火墙。但是,如果物理媒体(如驱动器或备份磁带)失窃,恶意方可能会还原或附加数据库并浏览数据。一种解决方案是加密数据库中的敏感数据,并通过证书保护用于加密数据的密钥。这可以防止任何没有密钥的人使用这些数据,但这种保护必须事先计划。
1426 0
|
关系型数据库 数据安全/隐私保护 PostgreSQL
RDS for PostgreSQL 云盘加密功能使用方法
RDS for PostgreSQL支持数据盘的加密功能,提供更高的数据存储安全等级。(加密KEY可以由用户提供,也可以由KMS服务生成。) 使用方法: 1、选中可用区(香港、上海),创建加密KEY。
4549 0

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版
  • 推荐镜像

    更多