什么是数据安全
依据《中华人民共和国数据安全法》中第三条,给出了数据安全的定义,是指通过采取必要措施,确保数据处于无效爱护和非法利用的状态,以及具备保障继续平安状态的能力。
为什么企业要做数据安全
在互联网流行的明天,不法分子能够通过网络攻击,网络坑骗等伎俩窃取用户的个人信息甚至企业的机密信息。而且在拿到局部用户信息后就能够惟一的锁定具体某一个人,因而数据的窃密显得分外重要。
GrowingIO 数据安全落地
为了保障客户数据的安全性,GrowingIO 通过构建一个平安的软件运行时与数据动态存储加密来进步数据生产安全性。上面咱们将具体介绍数据安全落地的过程。
软件运行平安
软件运行平安也就是企业的零碎运行平安,这次要蕴含两个方面:
数据逻辑隔离:零碎通过用户的权限与角色,给出专有的数据操作汇合。
KMS 秘钥治理:零碎所依赖的数据库,中间件不会因为秘钥的泄露而造成数据泄露。
数据逻辑隔离
数据逻辑隔离次要是对平台上操作的用户进行身份,角色,权限的认证。
认证流程:
所有平台的用户通过 RBAC 权限模型调配不同的角色和权限。只有领有对应角色权限的用户能力查看或进行对应的操作。
KMS 秘钥治理
KMS 即(key manage system)秘钥管理系统。目前亚马逊云和阿里云等云产品都有本人的解决方案。KMS 反对多种类型的的数据库,中间件,以及利用秘钥治理等性能。应用 KMS 之后所有数据库,中间件等的用户名,明码对产研均不可见,利用静态数据加密对应的秘钥也不可见。
目前反对数据库和中间件以及零碎秘钥:
【交互流程】
【示例展现】
以亚马逊云 (AWS) 为例:
利用配置
kms:
enabled: false
aws:
region: ""access_key_id:""
secret_access_key: ""
#利用中增加
spring:
redis:
kms-key: "test/json/redis"
datasource:
kms-key: "test/postgresql/accounts"
运行初始化
示例以 postgresql 数据库 HikariCP 连接池为例:
@Bean
@ConditionalOnProperty(value = "kms.enabled",havingValue = "true")
public HikariDataSource dataSource(DataSourceProperties properties, KmsProperties kms,Configs configs) {SecretsManagerClient client = SecretsManagerClientBuilder.build(kms.getRegion(),kms.getAwsAccessKeyId(),kms.getAwsSecretAccessKey());
AwsSecretProvider secretProvider = new AwsSecretProvider(client);
String secret;
try{secret = secretProvider.getSecret(configs.getDataSourceKmsKey());
//secret 是 json 格局的链接信息
final HashMap<String,String> map = Jackson.readValue(secret, HashMap.class);
String url = String.format("jdbc:postgresql://%s:%s/%s?useUnicode=true&useSSL=false&characterEncoding=utf8",map.get("host"),map.get("port"),map.get("dbname"));
properties.setUrl(url);
properties.setUsername(map.get("username"));
properties.setPassword(map.get("password"));
}catch (Exception e) {log.error("kms database error",e);
}
HikariDataSource dataSource = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
if (StringUtils.hasText(properties.getName())) {dataSource.setPoolName(properties.getName());
}
return dataSource;
}
在理论开发中用到的任何数据库,中间件都能够通过 KMS 来治理对应的用户名,明码等敏感信息。
动态存储平安
PII 治理
【什么是 PII】
PII 即个人身份信息 (Personally identifiable information) 是任何可能辨认特定集体的数据。任何可用于将一个人与另一个人辨别开来并可用于对以前匿名数据进行去匿名化的信息都能够被视为 PII。
PII 能够独自应用或与其余相干数据一起应用来辨认集体,并且蕴含能够惟一辨认集体的间接标识符(例如护照信息)或准标识符(例如种族),能够与其余准标识符联合应用标识符,如出生日期,以胜利辨认集体。
【PII 意义】
爱护 PII 对于个人隐私、数据隐衷、数据保护、信息隐衷和信息安全至关重要。仅凭个人信息的一小部分,窃贼就能够以该人的名义创立虚伪账户、产生债权、伪造护照或将个人身份发售给犯罪分子。随着集体的集体数据每天被记录、跟踪和应用——例如在应用指纹的生物辨认扫描和用于解锁设施的面部识别系统中——爱护个人身份和他们独有的任何辨认信息变得越来越重要。
【PII 加解密】
PII 加密:对于所有入库的用户敏感数据应用加密算法进行加密。
PII 解密:普通用户只能查看加密的密文数据,对于有业务须要的通过受权能够查看明文数据。
GrowingIO 默认抉择 AES(AES/CBC/PKCS5Padding) 算法,采纳 256 长度的秘钥来作为 PII 数据加密的实现。
执行流程
数据加密
数据解密
示例展现
PII 能够从配置核心或 KMS 中来获取加解密须要的秘钥数据。
秘钥获取:
// KMS 形式
SecretsManagerClient client = SecretsManagerClientBuilder.build(kms.getRegion(),kms.getAwsAccessKeyId(),kms.getAwsSecretAccessKey());
AwsSecretProvider secretProvider = new AwsSecretProvider(client);
String secret = secretProvider.getSecret("test/pii/json");
//secret 是 json 格局的链接信息
final HashMap<String,String> map = Jackson.readValue(secret, HashMap.class);
String algorithmIv = map.getOrElse("algorithm_iv", "");
// 向量
String iv = DatatypeConverter.parseHexBinary(algorithmIv);
// 秘钥
String encryptionKey = DatatypeConverter.parseHexBinary(map("encryption_key"));
String decryptionKey = DatatypeConverter.parseHexBinary(map("decryption_key"));
// 配置核心形式
// 向量
String iv = Hex.decodeHex(Configs.Encry.configCenterIv);
// 秘钥
String secret = Hex.decodeHex(Configs.Encry.configCenterSecret);
执行加密或者解密操作:
通过 PII 进行数据处理后,数据库中敏感数据全为加密存储。页面渲染根据用户权限判断是否加密或者解密展现。
数据存储与渲染
数据库数据:
只有管理员登录后渲染解密后的数据:
常见问题
一、向量 IV 的反对
在 AES 加密算法中:AES_ECB_PKCS5Padding 不反对向量,AES_CBC_PKCS5Padding 反对向量且安全性更高。如果原来曾经有用到 AES 算法要思考兼容性。
二、Base 64 编码带来的问题
景象:如果加密的字符串比拟长,加密后的密文将长度超过 76 时,密文中会被退出一个换行符,导致后续按行解析异样。
在 JDK1.8 之后 Base64 工具类移到了 java.util 包中,为了向低版本的 JDK 兼容,Base64 中 MimeEncode,采纳的形式:
private static final int MIMELINEMAX = 76;
private static final byte[] CRLF = new byte[] {'\r', '\n'};
static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
也就是说在加密串的长度超过 76 时会加上 ‘\r’ 或者 ‘\n’,这就导致如果按行进行数据的某些操作将会产生致命谬误。所以举荐应用 Base64 中 Encode 的实现:
static final Encoder RFC4648 = new Encoder(false, null, -1, true);
static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
这样不论加密后的字符串长度有多长都不会产生换行的问题。
参考 JDK 源码和秘钥规范:
RFC 4648 http://www.ietf.org/rfc/rfc46…
RFC 2045 http://www.ietf.org/rfc/rfc20…