这几天公司在排查内部数据账号泄漏,原因是发现某些实习生小可爱居然连带着账号、密码将源码私传到GitHub
上,导致核心数据外漏,孩子还是没挨过社会毒打,这种事的后果可大可小。
说起这个我是比较有感触的,之前[我TM被删库] 的经历,到现在想起来心里还难受,我也是把数据库账号明文密码误提交到GitHub
,然后被哪个大宝贝给我测试库删了,后边我长记性了把配置文件内容都加密了,数据安全问题真的不容小觑,不管工作汇还是生活,敏感数据一定要做脱敏处理。
如果对脱敏概念不熟悉,可以看一下我之前写过的一篇[大厂也在用的6种数据脱敏方案] ,里边对脱敏做了简单的描述,接下来分享工作中两个比较常见的脱敏场景。
实现配置的脱敏我使用了Java
的一个加解密工具Jasypt
,它提供了单密钥对称加密
和非对称加密
两种脱敏方式。
单密钥对称加密:一个密钥加盐,可以同时用作内容的加密和解密依据;
非对称加密:使用公钥和私钥两个密钥,才可以对内容加密和解密;
以上两种加密方式使用都非常简单,咱们以springboot
集成单密钥对称加密方式做示例。
首先引入jasypt-spring-boot-starter
jar
<!--配置文件加密-->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
配置文件加入秘钥配置项jasypt.encryptor.password
,并将需要脱敏的value
值替换成预先经过加密的内容ENC(mVTvp4IddqdaYGqPl9lCQbzM3H/b0B6l)
。
这个格式我们是可以随意定义的,比如想要abc[mVTvp4IddqdaYGqPl9lCQbzM3H/b0B6l]
格式,只要配置前缀和后缀即可。
jasypt:
encryptor:
property:
prefix: "abc["
suffix: "]"
ENC(XXX)格式主要为了便于识别该值是否需要解密,如不按照该格式配置,在加载配置项的时候jasypt
将保持原值,不进行解密。
spring:
datasource:
url: jdbc:mysql://1.2.3.4:3306/xiaofu?useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&ze oDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
username: xiaofu
password: ENC(mVTvp4IddqdaYGqPl9lCQbzM3H/b0B6l)
# 秘钥
jasypt:
encryptor:
password: 程序员内点事(然而不支持中文)
秘钥是个安全性要求比较高的属性,所以一般不建议直接放在项目内,可以通过启动时-D
参数注入,或者放在配置中心,避免泄露。
java -jar -Djasypt.encryptor.password=1123 springboot-jasypt-2.3.3.RELEASE.jar
预先生成的加密值,可以通过代码内调用API生成
@Autowired
private StringEncryptor stringEncryptor;
public void encrypt(String content) {
String encryptStr = stringEncryptor.encrypt(content);
System.out.println("加密后的内容:" + encryptStr);
}
或者通过如下Java命令生成,几个参数D:\maven_lib\org\jasypt\jasypt\1.9.3\jasypt-1.9.3.jar
为jasypt核心jar包,input
待加密文本,password
秘钥,algorithm
为使用的加密算法。
java -cp D:\maven_lib\org\jasypt\jasypt\1.9.3\jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="root" password=xiaofu algorithm=PBEWithMD5AndDES
一顿操作后如果还能正常启动,说明配置文件脱敏就没问题了。
生产环境用户的隐私数据,比如手机号、身份证或者一些账号配置等信息,入库时都要进行不落地脱敏,也就是在进入我们系统时就要实时的脱敏处理。
用户数据进入系统,脱敏处理后持久化到数据库,用户查询数据时还要进行反向解密。这种场景一般需要全局处理,那么用AOP
切面来实现在适合不过了。
首先自定义两个注解@EncryptField
、@EncryptMethod
分别用在字段属性和方法上,实现思路很简单,只要方法上应用到@EncryptMethod
注解,则检查入参字段是否标注@EncryptField
注解,有则将对应字段内容加密。
@Documented
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptField {
String[] value() default "";
}
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptMethod {
String type() default ENCRYPT;
}
切面的实现也比较简单,对入参加密,返回结果解密。为了方便阅读这里就只贴出部分代码,完整案例Github地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/springboot-jasypt
@Slf4j
@Aspect
@Component
public class EncryptHandler {
@Autowired
private StringEncryptor stringEncryptor;
@Pointcut("@annotation(com.xiaofu.annotation.EncryptMethod)")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) {
/**
* 加密
*/
encrypt(joinPoint);
/**
* 解密
*/
Object decrypt = decrypt(joinPoint);
return decrypt;
}
public void encrypt(ProceedingJoinPoint joinPoint) {
try {
Object[] objects = joinPoint.getArgs();
if (objects.length != 0) {
for (Object o : objects) {
if (o instanceof String) {
encryptValue(o);
} else {
handler(o, ENCRYPT);
}
//TODO 其余类型自己看实际情况加
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public Object decrypt(ProceedingJoinPoint joinPoint) {
Object result = null;
try {
Object obj = joinPoint.proceed();
if (obj != null) {
if (obj instanceof String) {
decryptValue(obj);
} else {
result = handler(obj, DECRYPT);
}
//TODO 其余类型自己看实际情况加
}
} catch (Throwable e) {
e.printStackTrace();
}
return result;
}
。。。
}
紧接着测试一下切面注解的效果,我们对字段mobile
、address
加上注解@EncryptField
做脱敏处理。
@EncryptMethod
@PostMapping(value = "test")
@ResponseBody
public Object testEncrypt(@RequestBody UserVo user, @EncryptField String name) {
return insertUser(user, name);
}
private UserVo insertUser(UserVo user, String name) {
System.out.println("加密后的数据:user" + JSON.toJSONString(user));
return user;
}
@Data
public class UserVo implements Serializable {
private Long userId;
@EncryptField
private String mobile;
@EncryptField
private String address;
private String age;
}
请求这个接口,看到参数被成功加密,而返回给用户的数据依然是脱敏前的数据,符合我们的预期,那到这简单的脱敏实现就完事了。
Jasypt
工具虽然简单好用,但作为程序员我们不能仅满足于熟练使用,底层实现原理还是有必要了解下的,这对后续调试bug、二次开发扩展功能很重要。
个人认为Jasypt
配置文件脱敏的原理很简单,无非就是在具体使用配置信息之前,先拦截获取配置的操作,将对应的加密配置解密后再使用。
具体是不是如此我们简单看下源码的实现,既然是以springboot
方式集成,那么就先从jasypt-spring-boot-starter
源码开始入手。
starter
代码很少,主要的工作就是通过SPI
机制注册服务和@Import
注解来注入需前置处理的类JasyptSpringBootAutoConfiguration
。
在前置加载类EnableEncryptablePropertiesConfiguration
中注册了一个核心处理类EnableEncryptablePropertiesBeanFactoryPostProcessor
。
它的构造器有两个参数,ConfigurableEnvironment
用来获取所有配属信息,EncryptablePropertySourceConverter
对配置信息做解析处理。
顺藤摸瓜发现具体负责解密的处理类EncryptablePropertySourceWrapper
,它通过对Spring
属性管理类PropertySource<T>
做拓展,重写了getProperty(String name)
方法,在获取配置时,凡是指定格式如ENC(x) 包裹的值全部解密处理。
既然知道了原理那么后续我们二次开发,比如:切换加密算法或者实现自己的脱敏工具就容易的多了。
“案例Github地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/springboot-jasypt
PBE算法
再来聊一下Jasypt
中用的加密算法,其实它是在JDK的JCE.jar
包基础上做了封装,本质上还是用的JDK提供的算法,默认使用的是PBE
算法PBEWITHMD5ANDDES
,看到这个算法命名很有意思,段个句看看,PBE、WITH、MD5、AND、DES 好像有点故事,继续看。
PBE
算法(Password Based Encryption
,基于口令(密码)的加密)是一种基于口令的加密算法,其特点在于口令是由用户自己掌握,在加上随机数多重加密等方法保证数据的安全性。
PBE算法本质上并没有真正构建新的加密、解密算法,而是对我们已知的算法做了包装。比如:常用的消息摘要算法MD5
和SHA
算法,对称加密算法DES
、RC2
等,而PBE
算法就是将这些算法进行合理组合,这也呼应上前边算法的名字。
既然PBE算法使用我们较为常用的对称加密算法,那就会涉及密钥的问题。但它本身又没有钥的概念,只有口令密码,密钥则是口令经过加密算法计算得来的。
口令本身并不会很长,所以不能用来替代密钥,只用口令很容易通过穷举攻击方式破译,这时候就得加点盐了。
盐通常会是一些随机信息,比如随机数、时间戳,将盐附加在口令上,通过算法计算加大破译的难度。
源码里的猫腻
简单了解PBE算法,回过头看看Jasypt
源码是如何实现加解密的。
在加密的时候首先实例化秘钥工厂SecretKeyFactory
,生成八位盐值,默认使用的jasypt.encryptor.RandomSaltGenerator
生成器。
public byte[] encrypt(byte[] message) {
// 根据指定算法,初始化秘钥工厂
final SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm1);
// 盐值生成器,只选八位
byte[] salt = saltGenerator.generateSalt(8);
//
final PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, iterations);
// 盐值、口令生成秘钥
SecretKey key = factory.generateSecret(keySpec);
// 构建加密器
final Cipher cipherEncrypt = Cipher.getInstance(algorithm1);
cipherEncrypt.init(Cipher.ENCRYPT_MODE, key);
// 密文头部(盐值)
byte[] params = cipherEncrypt.getParameters().getEncoded();
// 调用底层实现加密
byte[] encryptedMessage = cipherEncrypt.doFinal(message);
// 组装最终密文内容并分配内存(盐值+密文)
return ByteBuffer
.allocate(1 + params.length + encryptedMessage.length)
.put((byte) params.length)
.put(params)
.put(encryptedMessage)
.array();
}
由于默认使用的是随机盐值生成器,导致相同内容每次加密后的内容都是不同的。
那么解密时该怎么对应上呢?
看上边的源码发现,最终的加密文本是由两部分组成的,params
消息头里边包含口令和随机生成的盐值,encryptedMessage
密文。
加密而在解密时会根据密文encryptedMessage
的内容拆解出params
内容解析出盐值和口令,在调用JDK底层算法解密出实际内容。
@Override
@SneakyThrows
public byte[] decrypt(byte[] encryptedMessage) {
// 获取密文头部内容
int paramsLength = Byte.toUnsignedInt(encryptedMessage[0]);
// 获取密文内容
int messageLength = encryptedMessage.length - paramsLength - 1;
byte[] params = new byte[paramsLength];
byte[] message = new byte[messageLength];
System.arraycopy(encryptedMessage, 1, params, 0, paramsLength);
System.arraycopy(encryptedMessage, paramsLength + 1, message, 0, messageLength);
// 初始化秘钥工厂
final SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm1);
final PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKey key = factory.generateSecret(keySpec);
// 构建头部盐值口令参数
AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance(algorithm1);
algorithmParameters.init(params);
// 构建加密器,调用底层算法
final Cipher cipherDecrypt = Cipher.getInstance(algorithm1);
cipherDecrypt.init(
Cipher.DECRYPT_MODE,
key,
algorithmParameters
);
return cipherDecrypt.doFinal(message);
}
解密
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/cy31gsjRi6S4ug2RuJ1yjw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。