[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;
    }
}

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_45297578/article/details/129367804