共计 8928 个字符,预计需要花费 23 分钟才能阅读完成。
背景
安全控制始终是治理的重要环节,数据脱敏属于安全控制的领域。对互联网公司、传统行业来说,数据安全始终是极为器重和敏感的话题。数据脱敏是指对某些敏感信息通过脱敏规定进行数据的变形,实现敏感隐衷数据的牢靠爱护。波及客户平安数据或者一些商业性敏感数据,如身份证号、手机号、卡号、客户号等个人信息依照相干部门规定,都须要进行数据脱敏。
在实在业务场景中,相干业务开发团队则往往须要针对公司安全部门需要,自行履行并保护一套加解密零碎,而当脱敏场景产生扭转时,自行保护的脱敏零碎往往又面临着重构或批改危险。此外,对于曾经上线的业务,如何在不批改业务逻辑、业务 SQL 的状况下,透明化、平安低危险地实现无缝进行脱敏革新呢?
Apache ShardingSphere 依据业界对脱敏的需要及业务革新痛点,提供了一套残缺、平安、透明化、低革新老本的数据脱敏整合解决方案。
前序
Apache ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由 Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar(布局中)这 3 款互相独立,却又可能混合部署配合应用的产品组成。它们均可能提供标准化的数据分片、分布式事务和分布式治理性能,可实用于如 Java 同构、异构语言、容器、云原生等各种多样化的利用场景。
数据脱敏模块属于 ShardingSphere 分布式治理这一外围性能下的子功能模块。它通过对用户输出的 SQL 进行解析,并根据用户提供的脱敏配置对 SQL 进行改写,从而实现对原文数据进行加密,并将原文数据 (可选) 及密文数据同时存储到底层数据库。在用户查问数据时,它又从数据库中取出密文数据,并对其解密,最终将解密后的原始数据返回给用户。Apache ShardingSphere 分布式数据库中间件自动化 & 透明化了数据脱敏过程,让用户无需关注数据脱敏的实现细节,像应用一般数据那样应用脱敏数据。此外,无论是已在线业务进行脱敏革新,还是新上线业务应用脱敏性能,ShardingSphere 都能够提供一套绝对欠缺的解决方案。
需要场景剖析
对于数据脱敏的需要,在事实的业务场景中个别分为两种状况:
- 新业务上线,安全部门规定需将波及用户敏感信息,例如银行、手机号码等进行加密后存储到数据库,在应用的时候再进行解密解决。因为是全新零碎,因此没有存量数据荡涤问题,所以实现绝对简略。
- 已上线业务,之前始终将明文存储在数据库中。相干部门忽然须要对已上线业务进行脱敏整改。这种场景个别须要解决三个问题:
a) 历史数据须要如何进行脱敏解决,即洗数。
b) 如何能在不改变业务 SQL 和逻辑状况下,将新增数据进行脱敏解决,并存储到数据库;在应用时,再进行解密取出。
c) 如何较为平安、无缝、透明化地实现业务零碎在明文与密文数据间的迁徙。
解决流程详解
整体架构
ShardingSphere 提供的 Encrypt-JDBC 和业务代码部署在一起。业务方需面向 Encrypt-JDBC 进行 JDBC 编程。因为 Encrypt-JDBC 实现所有 JDBC 标准接口,业务代码无需做额定革新即可兼容应用。此时,业务代码所有与数据库的交互行为交由 Encrypt-JDBC 负责。业务只需提供脱敏规定即可。作为业务代码与底层数据库两头的桥梁,Encrypt-JDBC 便可拦挡用户行为,并在革新行为后与数据库交互。
Encrypt-JDBC 将用户发动的 SQL 进行拦挡,并通过 SQL 语法解析器进行解析、了解 SQL 行为,再根据用户传入的脱敏规定,找出须要脱敏的字段和所应用的加解密器对指标字段进行加解密解决后,再与底层数据库进行交互。ShardingSphere 会将用户申请的明文进行加密后存储到底层数据库;并在用户查问时,将密文从数据库中取出进行解密后返回给终端用户。ShardingSphere 通过屏蔽对数据的脱敏解决,使用户无需感知解析 SQL、数据加密、数据解密的处理过程,就像在应用一般数据一样应用脱敏数据。
脱敏规定
在详解整套流程之前,咱们须要先理解下脱敏规定与配置,这是意识整套流程的根底。脱敏配置次要分为四局部:数据源配置,加密器配置,脱敏表配置以及查问属性配置,其详情如下图所示:
数据源配置:是指 DataSource 的配置。
加密器配置:是指应用什么加密策略进行加解密。目前 ShardingSphere 内置了两种加解密策略:AES/MD5。用户还能够通过实现 ShardingSphere 提供的接口,自行实现一套加解密算法。
脱敏表配置:用于通知 ShardingSphere 数据表里哪个列用于存储密文数据(cipherColumn)、哪个列用于存储明文数据(plainColumn)以及用户想应用哪个列进行 SQL 编写(logicColumn)。
如何了解
用户想应用哪个列进行 SQL 编写(logicColumn)
?咱们能够从 Encrypt-JDBC 存在的意义来了解。Encrypt-JDBC 最终目标是心愿屏蔽底层对数据的脱敏解决,也就是说咱们不心愿用户晓得数据是如何被加解密的、如何将明文数据存储到 plainColumn,将密文数据存储到 cipherColumn。换句话说,咱们不心愿用户晓得 plainColumn 和 cipherColumn 的存在和应用。所以,咱们须要给用户提供一个概念意义上的列,这个列能够脱离底层数据库的实在列,它能够是数据库表里的一个实在列,也能够不是,从而使得用户能够随便扭转底层数据库的 plainColumn 和 cipherColumn 的列名。或者删除 plainColumn,抉择永远不再存储明文,只存储密文。只有用户的 SQL 面向这个逻辑列进行编写,并在脱敏规定里给出 logicColumn 和 plainColumn、cipherColumn 之间正确的映射关系即可。
为什么要这么做呢?答案在文章前面,即为了让已上线的业务能无缝、通明、平安地进行数据脱敏迁徙。
查问属性的配置:当底层数据库表里同时存储了明文数据、密文数据后,该属性开关用于决定是间接查询数据库表里的明文数据进行返回,还是查问密文数据通过 Encrypt-JDBC 解密后返回。
脱敏处理过程
举个栗子,如果数据库里有一张表叫做 t_user,这张表里理论有两个字段 pwd_plain,用于寄存明文数据、pwd_cipher,用于寄存密文数据,同时定义 logicColumn 为 pwd。那么,用户在编写 SQL 时应该面向 logicColumn 进行编写,即 INSERT INTO t_user SET pwd = ‘123’。ShardingSphere 接管到该 SQL,通过用户提供的脱敏配置,发现 pwd 是 logicColumn,于是便对逻辑列及其对应的明文数据进行脱敏解决。能够看出 ShardingSphere 将面向用户的逻辑列与面向底层数据库的明文列和密文列进行了列名以及数据的脱敏映射转换。 如下图所示:
这也正是 Encrypt-JDBC 外围意义所在,即根据用户提供的脱敏规定,将用户 SQL 与底层数据表构造割裂开来,使得用户的 SQL 编写不再依赖于实在的数据库表构造。而用户与底层数据库之间的连接、映射、转换交由 ShardingSphere 进行解决。为什么咱们要这么做?还是那句话:为了让已上线的业务能无缝、通明、平安地进行数据脱敏迁徙。
为了让读者更清晰理解到 Encrypt-JDBC 的外围解决流程,下方图片展现了应用 Encrypt-JDBC 进行增删改查时,其中的解决流程和转换逻辑,如下图所示。
解决方案详解
在理解了 ShardingSphere 脱敏解决流程后,即可将脱敏配置、脱敏解决流程与理论场景进行联合。所有的设计开发都是为了解决业务场景遇到的痛点。那么面对之前提到的业务场景需要,又应该如何应用 ShardingSphere 这把利器来满足业务需要呢?
新上线业务
业务场景剖析:新上线业务因为所有从零开始,不存在历史数据荡涤问题,所以绝对简略。
解决方案阐明:抉择适合的加密器,如 AES 后,只需配置逻辑列(面向用户编写 SQL)和密文列(数据表存密文数据)即可,逻辑列和密文列能够雷同也能够不同。倡议配置如下(Yaml 格局展现):
encryptRule:
encryptors:
aes_encryptor:
type: aes
props:
aes.key.value: 123456abc
tables:
t_user:
columns:
pwd:
cipherColumn: pwd
encryptor: aes_encryptor
应用这套配置,Encrypt-JDBC 只需将 logicColumn 和 cipherColumn 进行转换,底层数据表不存储明文,只存储了密文,这也是平安审计局部的要求所在。如果用户心愿将明文、密文一起存储到数据库,只需增加 plainColumn 配置即可。整体解决流程如下图所示:
已上线业务革新
业务场景剖析:因为业务曾经在线上运行,数据库里必然存有大量明文历史数据。当初的问题是如何让历史数据得以加密荡涤、如何让增量数据得以加密解决、如何让业务在新旧两套数据系统之间进行无缝、透明化迁徙。
解决方案阐明:在提供解决方案之前,咱们先来头脑风暴一下:首先,既然是旧业务须要进行脱敏革新,那肯定存储了十分重要且敏感的信息。这些信息含金量高且业务绝对根底重要。如果搞错了,整个团队 KPI 就再见了。所以不可能一上来就停业务,禁止新数据写入,再找个加密器把历史数据全副加密荡涤,再把之前重构的代码部署上线,使其能把存量和增量数据进行在线加密解密。如此简略粗犷的形式,依照历史教训来谈,肯定凉凉。
那么另一种绝对平安的做法是:从新搭建一套和生产环境截然不同的预发环境,而后通过相干迁徙洗数工具把生产环境的 存量原文数据 加密后存储到预发环境,而 新增数据 则通过例如 MySQL 主从复制及业务方自行开发的工具加密后存储到预发环境的数据库里,再把重构后能够进行加解密的代码部署到预发环境。这样生产环境是一套 以明文为外围的查问批改 的环境;预发环境是一套 以密文为外围加解密查问批改 的环境。在比照一段时间无误后,能够夜间操作将生产流量切到预发环境中。此计划绝对安全可靠,只是工夫、人力、资金、老本较高,次要包含:预发环境搭建、生产代码整改、相干辅助工具开发等。除非无路可走,否则业务开发人员个别是从入门到放弃。
业务开发人员最心愿的做法是:缩小资金费用的承当、最好不要批改业务代码、可能平安平滑迁徙零碎。于是,ShardingSphere 的脱敏功能模块便利用而生。可分为三步进行:
-
零碎迁徙前
假如零碎须要对 t_user 的 pwd 字段进行脱敏解决,业务方应用 Encrypt-JDBC 来代替标准化的 JDBC 接口,此举根本不须要额定革新(咱们还提供了 SpringBoot,SpringNameSpace,Yaml 等接入形式,满足不同业务方需要)。另外,提供一套脱敏配置规定,如下所示:
encryptRule: encryptors: aes_encryptor: type: aes props: aes.key.value: 123456abc tables: t_user: columns: pwd: plainColumn: pwd cipherColumn: pwd_cipher encryptor: aes_encryptor props: query.with.cipher.column: false
根据上述脱敏规定可知,首先须要在数据库表 t_user 里新增一个字段叫做 pwd_cipher,即 cipherColumn,用于寄存密文数据,同时咱们把 plainColumn 设置为 pwd,用于寄存明文数据,而把 logicColumn 也设置为 pwd。因为之前的代码 SQL 就是应用 pwd 进行编写,即面向逻辑列进行 SQL 编写,所以业务代码无需改变。通过 Encrypt-JDBC,针对新增的数据,会把明文写到 pwd 列,并同时把明文进行加密存储到 pwd_cipher 列。此时,因为 query.with.cipher.column 设置为 false,对业务利用来说,仍旧应用 pwd 这一明文列进行查问存储,却在底层数据库表 pwd_cipher 上额定存储了新增数据的密文数据,其解决流程如下图所示:
新增数据在插入时,就通过 Encrypt-JDBC 加密为密文数据,并被存储到了 cipherColumn。而当初就须要解决历史明文存量数据。因为 Apache ShardingSphere 目前并未提供相干迁徙洗数工具,此时须要业务方自行将 pwd 中的明文数据进行加密解决存储到 pwd_cipher。
- 零碎迁徙中
新增的数据已被 Encrypt-JDBC 将密文存储到密文列,明文存储到明文列;历史数据被业务方自行加密荡涤后,将密文也存储到密文列。也就是说当初的数据库里即寄存着明文也寄存着密文,只是因为配置项中的 query.with.cipher.column=false,所以密文始终没有被应用过。当初咱们为了让零碎能切到密文数据进行查问,须要将脱敏配置中的 query.with.cipher.column 设置为 true。在重启零碎后,咱们发现零碎业务一切正常,然而 Encrypt-JDBC 曾经开始从数据库里取出密文列的数据,解密后返回给用户;而对于用户的增删改需要,则依旧会把原文数据存储到明文列,加密后密文数据存储到密文列。
尽管当初业务零碎通过将密文列的数据取出,解密后返回;然而,在存储的时候仍旧会存一份原文数据到明文列,这是为什么呢?答案是:为了可能进行零碎回滚。因为只有密文和明文永远同时存在,咱们就能够通过开关项配置自在将业务查问切换到 cipherColumn 或 plainColumn。也就是说,如果将零碎切到密文列进行查问时,发现零碎报错,须要回滚。那么只需将 query.with.cipher.column=false,Encrypt-JDBC 将会还原,即又从新开始应用 plainColumn 进行查问。解决流程如下图所示:
-
零碎迁徙后
因为平安审计部门要求,业务零碎个别不可能让数据库的明文列和密文列永恒同步保留,咱们须要在零碎稳固后将明文列数据删除。即咱们须要在零碎迁徙后将 plainColumn,即 pwd 进行删除。那问题来了,当初业务代码都是面向 pwd 进行编写 SQL 的,把底层数据表中的寄存明文的 pwd 删除了,换用 pwd_cipher 进行解密失去原文数据,那岂不是意味着业务方须要整改所有 SQL,从而不应用行将要被删除的 pwd 列?还记得咱们 Encrypt-JDBC 的外围意义所在吗?
这也正是 Encrypt-JDBC 外围意义所在,即根据用户提供的脱敏规定,将用户 SQL 与底层数据库表构造割裂开来,使得用户的 SQL 编写不再依赖于实在的数据库表构造。而用户与底层数据库之间的连接、映射、转换交由 ShardingSphere 进行解决。
是的,因为有 logicColumn 存在,用户的编写 SQL 都面向这个虚构列,Encrypt-JDBC 就能够把这个逻辑列和底层数据表中的密文列进行映射转换。于是迁徙后的脱敏配置即为:
encryptRule: encryptors: aes_encryptor: type: aes props: aes.key.value: 123456abc tables: t_user: columns: pwd: # pwd 与 pwd_cipher 的转换映射 cipherColumn: pwd_cipher encryptor: aes_encryptor props: query.with.cipher.column: true
其解决流程如下:
至此,已在线业务脱敏整改解决方案全副叙述结束。咱们提供了 Java、Yaml、SpringBoot、SpringNameSpace 多种形式供用户抉择接入,力求满足业务不同的接入需要。该解决方案目前已在京东数科一直落地上线,提供对内根底服务撑持。
中间件脱敏服务劣势
- 自动化 & 透明化数据脱敏过程,用户无需关注脱敏两头实现细节。
- 提供多种内置、第三方 (AKS) 的脱敏策略,用户仅需简略配置即可应用。
- 提供脱敏策略 API 接口,用户可实现接口,从而应用自定义脱敏策略进行数据脱敏。
- 反对切换不同的脱敏策略。
- 针对已上线业务,可实现明文数据与密文数据同步存储,并通过配置决定应用明文列还是密文列进行查问。可实现在不扭转业务查问 SQL 前提下,已上线系统对加密前后数据进行平安、透明化迁徙。
实用场景阐明
- 用户我的项目应用 Java 语言进行编程。
- 后端数据库为 MySQL、Oracle、PostgreSQL、SQLServer。
- 用户须要对数据库表中某个或多个列进行脱敏(数据加密 & 解密)。
- 兼容所有罕用 SQL。
限度条件
- 用户须要自行处理数据库中原始的存量数据、洗数。
- 应用脱敏性能 + 分库分表性能,局部非凡 SQL 不反对,请参考 SQL 应用标准。
- 脱敏字段无奈反对比拟操作,如:大于小于、ORDER BY、BETWEEN、LIKE 等。
- 脱敏字段无奈反对计算操作,如:AVG、SUM 以及计算表达式。
加密策略解析
ShardingSphere 提供了两种加密策略用于数据脱敏,该两种策略别离对应 ShardingSphere 的两种加解密的接口,即 ShardingEncryptor 和 ShardingQueryAssistedEncryptor。
一方面,ShardingSphere 为用户提供了内置的加解密实现类,用户只需进行配置即可应用;另一方面,为了满足用户不同场景的需要,咱们还凋谢了相干加解密接口,用户可根据该两种类型的接口提供具体实现类。再进行简略配置,即可让 ShardingSphere 调用用户自定义的加解密计划进行数据脱敏。
ShardingEncryptor
该解决方案通过提供 encrypt()
, decrypt()
两种办法对须要脱敏的数据进行加解密。在用户进行 INSERT
, DELETE
, UPDATE
时,ShardingSphere 会依照用户配置,对 SQL 进行解析、改写、路由,并会调用 encrypt()
将数据加密后存储到数据库, 而在 SELECT
时,则调用 decrypt()
办法将从数据库中取出的脱敏数据进行逆向解密,最终将原始数据返回给用户。
以后,ShardingSphere 针对这种类型的脱敏解决方案提供了两种具体实现类,别离是 MD5(不可逆),AES(可逆),用户只需配置即可应用这两种内置的计划。
ShardingQueryAssistedEncryptor
相比拟于第一种脱敏计划,该计划更为平安和简单。它的理念是:即便是雷同的数据,如两个用户的明码雷同,它们在数据库里存储的脱敏数据也该当是不一样的。这种理念更有利于爱护用户信息,避免撞库胜利。
它提供三种函数进行实现,别离是 encrypt()
, decrypt()
, queryAssistedEncrypt()
。在encrypt()
阶段,用户通过设置某个变动种子,例如工夫戳。针对原始数据 + 变动种子组合的内容进行加密,就能保障即便原始数据雷同,也因为有变动种子的存在,以致加密后的脱敏数据是不一样的。在 decrypt()
可根据之前规定的加密算法,利用种子数据进行解密。
尽管这种形式的确能够减少数据的保密性,然而另一个问题却随之呈现:雷同的数据在数据库里存储的内容是不一样的,那么当用户依照这个加密列进行等值查问 (SELECT FROM table WHERE encryptedColumnn = ?
) 时会发现无奈将所有雷同的原始数据查问进去。为此,咱们提出了辅助查问列的概念。该辅助查问列通过 queryAssistedEncrypt()
生成,与 decrypt()
不同的是,该办法通过对原始数据进行另一种形式的加密,然而针对原始数据雷同的数据,这种加密形式产生的加密数据是统一的。将 queryAssistedEncrypt()
后的数据存储到数据中用于辅助查问实在数据。因而,数据库表中多出这一个辅助查问列。
因为 queryAssistedEncrypt()
和encrypt()
产生不同加密数据进行存储,而 decrypt()
可逆,queryAssistedEncrypt()
不可逆。在查问原始数据的时候,咱们会主动对 SQL 进行解析、改写、路由,利用辅助查问列进行 WHERE
条件的查问,却利用 decrypt()
对 encrypt()
加密后的数据进行解密,并将原始数据返回给用户。这一切都是对用户透明化的。
以后,ShardingSphere 针对这种类型的脱敏解决方案并没有提供具体实现类,却将该理念形象成接口,提供给用户自行实现。ShardingSphere 将调用用户提供的该计划的具体实现类进行数据脱敏。
后续
本篇文章介绍了如何应用 ShardingSphere 产品之一的 Encrypt-JDBC 进行接入,接入模式还能够抉择应用 SpringBoot、SpringNameSpace 等,这种状态的接入端次要面向 JAVA 同构,并与业务代码独特部署在生产环境中。面向异构语言,ShardingSphere 还提供 Encrypt-Proxy 客户端。Encrypt-Proxy 是一款实现 MySQL、PostgreSQL 的二进制协定的服务器端产品,用户可独立部署 Encrypt-Proxy 服务,并且像应用一般 MySQL、PostgreSQL 数据库一样,应用例如 Navicat 第三方数据库管理工具、JAVA 连接池、命令行的形式拜访这台具备脱敏性能的 虚构数据库服务器
。
脱敏性能属于 Apache ShardingSphere 分布式治理的性能领域。事实上,Apache ShardingSphere 这个生态还领有其余更弱小的能力,例如数据分片、读写拆散、分布式事务、监控治理等。您甚至能够抉择任意多种功能模块进行叠加应用,例如同时应用数据脱敏 + 数据分片,或是数据分片 + 读写拆散,再或者是监控治理 + 数据分片等。除了在性能层面的叠加抉择,ShardingSphere 还提供了各种接入端模式,例如 Sharding-JDBC 或 Sharding-Proxy 等以满足大家不同场景需要。