【问题标题】:Spring Properties DecryptionSpring属性解密
【发布时间】:2019-09-23 14:03:09
【问题描述】:

我们混合了一些尚未迁移到 spring-boot 或 spring cloud 的遗留 spring 应用程序以及 spring boot 应用程序。我正在创建一个 Spring 组件,如果属性值已加密并具有前缀,则该组件将在加载环境时自动解密 spring 属性。属性可以在 .properties 文件中(用于旧版应用程序)或 .yaml 文件中(较新的 Spring Boot 应用程序)。

无论来源如何,组件都应该能够解密任何 spring 属性,并且应该可以与任何 spring 版本一起使用,并且不依赖于 spring boot。组件还应该透明地解密属性。它应该从属性文件中读取密码,因此需要在开头加载密码文件。

我们有自己的 ecrypt/decrypt,不想使用 jaspyt。

到目前为止尝试过的事情:

我喜欢 this 创建 ApplicationListener 的方法,但这与 spring boot(ApplicationEnvironmentPreparedEvent) 相关。对于像 ContextRefreshed 或 ContextStart 这样的 Spring 事件,我看不到如何获得 ConfigurableApplicationContext/ConfigurableEnvironment。有人在没有 spring boot/cloud 的情况下创建了用于加密/解密的侦听器吗?

我还创建了一个自定义 ApplicationContextInitializer,并将其添加到 web.xml 的上下文参数中,但这似乎不起作用。当我调试它时,我认为它不会从我的 app.properties 文件中加载/读取属性。

       @Component
    public class DecryptingPropertyContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

        @Override
       public void initialize( ConfigurableApplicationContext applicationContext ) {
          ConfigurableEnvironment environment = applicationContext.getEnvironment();
          for ( PropertySource<?> propertySource : environment.getPropertySources() ) {
             Map<String, Object> propertyOverrides = new LinkedHashMap<>();
             decodePasswords( propertySource, propertyOverrides );
             if ( !propertyOverrides.isEmpty() ) {
                PropertySource<?> decodedProperties = new MapPropertySource( "decoded " + propertySource.getName(),
                      propertyOverrides );
                environment.getPropertySources().addBefore( propertySource.getName(), decodedProperties );
             }
          }
       }

        private void decodePasswords(PropertySource<?> source, Map<String, Object> propertyOverrides) {
          if ( source instanceof EnumerablePropertySource ) {
             EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) source;
             for ( String key : enumerablePropertySource.getPropertyNames() ) {
                Object rawValue = source.getProperty( key );
                if ( rawValue instanceof String ) {
                   //decrypt logic here
propertyOverrides.put( key, decryptedValue );
                }
             }
          }
        }
    }

是否有人必须做类似的事情或有更好的想法?有没有办法我可以监听应用程序事件然后处理? 感谢您的帮助

【问题讨论】:

  • 你可以写一个自定义的SPEL函数来解密。
  • 您可以尝试 AOP 并将其配置为在每次调用 Proprties.load() 时运行
  • @Ivan 有没有办法可以监听应用程序事件然后进行处理?
  • @AkshayKhopka 谢谢。就像在一个应用程序中事件然后处理?

标签: java spring spring-boot encryption properties


【解决方案1】:

您可以编写自己的PropertiesFactoryBean 并覆盖createProperties 来解密加密值:

public class DecryptingPropertiesFactoryBean extends PropertiesFactoryBean {
  @Override
  protected Properties createProperties() throws IOException {
    final Properties encryptedProperties = super.createProperties();
    final Properties decryptedProperties = decrypt(encryptedProperties);
    return decryptedProperties;
  }
}

还有一个使用这些属性的PropertySourcesPlaceholderConfigurer bean:

@Configuration
public class PropertiesConfiguration {

  @Bean
  public static DecryptingPropertiesFactoryBean propertyFactory() {
    final DecryptingPropertiesFactoryBean factory = new DecryptingPropertiesFactoryBean();
    final Resource[] propertyLocations = new Resource[] {
        new FileSystemResource(new File("path/to/file.properties"))
    };
    factory.setLocations(propertyLocations);
    return factory;
  }

  @Bean
  public static Properties properties() throws Exception {
    return propertyFactory().getObject();
  }

  @Bean
  public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    final PropertySourcesPlaceholderConfigurer bean = new PropertySourcesPlaceholderConfigurer();
    bean.setIgnoreResourceNotFound(true);
    bean.setIgnoreUnresolvablePlaceholders(false);
    bean.setProperties(properties());
    return bean;
  }
}

【讨论】:

  • 非常感谢,我要试试这个方法。只是几个问题,所以需要在 spring 环境中设置密码(来自 spring 属性源文件)。我需要在开始时阅读密码(例如:encryp.passphrase)并在创建解密器实例时传递它。您认为最好的方法是什么?
  • 考虑到这块将在一个jar中,webapp应该如何使用应用中配置的这个PropertySourcesPlaceholderConfigurer bean来解密属性?
  • @MaverickRiz 我不明白你关于罐子里的一些作品的意思(实际上是哪个“作品”?密码?)。在被覆盖的DecryptingPropertiesFactoryBean.createProperties 方法中,您可以做任何您想做的事情。您可以从super.createProperties() 获得的属性中读取密码,从环境变量中读取或访问其他外部资源。满足您的需求。
  • 我的意思是,我想在实际解密任何其他属性之前将密码属性作为第一个属性加载。所以我试图调试,但看起来我的应用程序没有击中 DecryptingPropertiesFactoryBean。如何配置应用程序以使用此 bean?
  • 我认为我的示例中有错误。 @Bean-methods 在属性配置的特殊情况下需要是静态的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-11
  • 2020-06-11
  • 2015-12-29
  • 2019-02-28
  • 1970-01-01
  • 2018-12-18
  • 2017-09-25
相关资源
最近更新 更多