[SpringBoot Advanced] SpringBoot は jasypt データの感度低下を統合します
構成の鈍感化
使用シーン
データベースのパスワードは、application.yml 構成に平文で直接書き込まれますが、これはセキュリティ上の大きな課題です。パスワードが漏洩すると、大きなセキュリティリスクが発生します。特に高度なセキュリティ要件を持つ一部の企業では、パスワードを暗号化する方法を検討しています。
オープン ソース フレームワーク Jasypt は、上記の問題を解決できます。
-
Jasypt オープン ソース セキュリティ フレームワークは、Spring ブート属性の暗号化を処理するように特別に設計されています. 特定の形式を使用して、構成ファイルで暗号文を直接構成すると、アプリケーションが起動すると、Jasypt は自動的にパスワードを平文に復号化し、プログラムで使用できるようにします.
-
jasyptは同じコンテンツを同じ鍵(secretKey)で暗号化しており、毎回生成される暗号文は異なりますが、これらの暗号文に従って元のコンテンツを復号することが可能です。
構成マスキングの実践
<!--配置文件加密-->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
キー構成項目を構成ファイルに追加しjasypt.encryptor.password
、感度を下げる必要がある値をvalue
事前に暗号化されたコンテンツに置き換えますENC(zxcvb/asdfg)
。
この形式は自由に定義できます. たとえば、abc[zxcvb/asdfg]
形式が必要な場合は、プレフィックスとサフィックスを構成するだけで済みます.
jasypt:
encryptor:
property:
prefix: "abc["
suffix: "]"
ENC(XXX)
この形式は主に、値を復号化する必要があるかどうかを識別するためのものです。この形式に従って構成されていない場合、構成アイテムが読み込まれるときにjasypt
元の値が保持され、復号化されません。
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/order_db_1?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username: root
password: ENC(ipHBo9hH/W756iU3HjAZJA==)
# 秘钥
jasypt:
encryptor:
password: csdn
コードで API を呼び出すことにより、事前に生成された暗号化された値を生成できます。
@Autowired
private StringEncryptor stringEncryptor;
@GetMapping("/encode")
public String encrypt(String content) {
String encryptStr = stringEncryptor.encrypt(content);
System.out.println("加密后的内容:" + encryptStr);
return "加密后的内容:" + encryptStr;
}
データ感度低下
携帯電話番号、ID カード、または一部のアカウント構成情報など、運用環境のユーザーの個人データは、倉庫に入るときに着陸せずに感度を下げる必要があります。つまり、システムに入るときにリアルタイムで感度を下げる必要があります。
ユーザー データはシステムに入力され、感度が低下してデータベースに保存されます。ユーザーがデータを照会すると逆復号化が実行されます。この種のシーンは一般的にグローバルな処理が必要なため、AOP
アスペクトを使用してそれを実現するのは適していません。
まず、2 つのアノテーションをカスタマイズし@EncryptField
、フィールド プロパティとメソッドでそれぞれ使用します. 実装のアイデアは非常に単純です.アノテーションがメソッドに適用されている@EncryptMethod
限り、入力フィールドがアノテーションでマークされているかどうかを確認し、そうであれば、対応するフィールドを暗号化しますフィールドの内容。@EncryptMethod
@EncryptField
ポンポン
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
yml
# 秘钥
jasypt:
encryptor:
password: csdn
Encrypt メソッド
@Documented
@Target({
ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptMethod {
String type() default EncryptConstant.ENCRYPT;
}
暗号化フィールド
@Documented
@Target({
ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptField {
String[] value() default "";
}
EncryptConstant
public interface EncryptConstant {
// 加密
String ENCRYPT = "encrypt";
// 解密
String DECRYPT = "decrypt";
}
EncryptHandler
@Slf4j
@Aspect
@Component
public class EncryptHandler {
@Autowired
private StringEncryptor stringEncryptor;
@Pointcut("@annotation(cn.zysheep.annotation.EncryptMethod)")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) {
/**
* 加密
*/
Object[] encrypt = encrypt(joinPoint);
/**
* 解密
*/
Object decrypt = decrypt(joinPoint,encrypt);
return decrypt;
}
public Object[] encrypt(ProceedingJoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
try {
if (args.length != 0) {
for (int i = 0; i < args.length; i++) {
Object o = args[i];
if (o instanceof String) {
args[i] = encryptValue(o);
} else {
args[i] = handler(o, EncryptConstant.ENCRYPT);
}
//TODO 其余类型自己看实际情况加
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return args;
}
public Object decrypt(ProceedingJoinPoint joinPoint,Object[] args) {
Object result = null;
try {
Object obj = joinPoint.proceed(args);
if (obj != null) {
if (obj instanceof String) {
result = decryptValue(obj);
} else {
result = handler(obj, EncryptConstant.DECRYPT);
}
//TODO 其余类型自己看实际情况加
}
} catch (Throwable e) {
e.printStackTrace();
}
return result;
}
private Object handler(Object obj, String type) throws IllegalAccessException {
if (Objects.isNull(obj)) {
return null;
}
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
boolean annotationPresent = field.isAnnotationPresent(EncryptField.class);
if (annotationPresent) {
field.setAccessible(true);
String value;
String realValue = (String) field.get(obj);
if (EncryptConstant.DECRYPT.equals(type)) {
value = stringEncryptor.decrypt(realValue);
} else {
value = stringEncryptor.encrypt(realValue);
}
field.set(obj, value);
}
}
return obj;
}
public String encryptValue(Object realValue) {
String value = null;
try {
value = stringEncryptor.encrypt(String.valueOf(realValue));
} catch (Exception ex) {
return value;
}
return value;
}
public String decryptValue(Object realValue) {
String value = String.valueOf(realValue);
try {
value = stringEncryptor.decrypt(value);
} catch (Exception ex) {
return value;
}
return value;
}
}
人
@Data
public class Person {
private Integer id;
@EncryptField
private String mobile;
@EncryptField
private String address;
private Integer age;
private BigDecimal wages;
}
Jasyptアプリケーション
@RestController
@SpringBootApplication
public class JasyptApplication {
@Autowired
private StringEncryptor stringEncryptor;
public static void main(String[] args) {
SpringApplication.run(JasyptApplication.class, args);
}
@GetMapping("/encode")
public String encrypt(String content) {
String encryptStr = stringEncryptor.encrypt(content);
System.out.println("加密后的内容:" + encryptStr);
return "加密后的内容:" + encryptStr;
}
@EncryptMethod
@PostMapping("/dataEnc")
public Person encrypt(@RequestBody Person person, @EncryptField String username) throws JsonProcessingException {
ObjectMapper json = new ObjectMapper();
String writeValueAsString = json.writeValueAsString(person);
System.out.println(writeValueAsString);
System.out.println(username);
return person;
}
@EncryptMethod
@GetMapping("/getParam")
public String getParam( @EncryptField String username) {
System.out.println("保存数据库业务操作===>username: "+username);
return username;
}
}