Spring Boot如何在属性文件中隐藏密码

122

Spring Boot 使用属性文件,至少默认情况下,密码是明文的。是否有可能以某种方式隐藏/解密这些密码?

7个回答

124

您可以使用Jasypt来加密属性,这样您就可以拥有如下的属性:

db.password=ENC(XcBjfjDDjxeyFBoaEPhG14wEzc6Ja+Xx+hNPrJyQT88=)

Jasypt允许您使用不同的算法加密属性,一旦您获得了加密的属性,就将其放入ENC(...)中。例如,您可以通过终端使用Jasypt以这种方式进行加密:

encrypted-pwd$ java -cp ~/.m2/repository/org/jasypt/jasypt/1.9.2/jasypt-1.9.2.jar  org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="contactspassword" password=supersecretz algorithm=PBEWithMD5AndDES

----ENVIRONMENT-----------------

Runtime: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 24.45-b08



----ARGUMENTS-------------------

algorithm: PBEWithMD5AndDES
input: contactspassword
password: supersecretz



----OUTPUT----------------------

XcBjfjDDjxeyFBoaEPhG14wEzc6Ja+Xx+hNPrJyQT88=

如果想要使用Spring Boot轻松配置它,可以使用其starter jasypt-spring-boot-starter,其组ID为com.github.ulisesbocchio

请记住,您需要使用加密属性时使用的相同密码启动应用程序。因此,您可以按照以下方式启动应用程序:

mvn -Djasypt.encryptor.password=supersecretz spring-boot:run

或者使用环境变量(感谢Spring Boot松散绑定):

export JASYPT_ENCRYPTOR_PASSWORD=supersecretz
mvn spring-boot:run

您可以查看下面的链接获取更多详细信息:

https://www.north-47.com/knowledge-base/spring-boot-password-encryption-with-jasypt/

要在应用程序中使用加密的属性,只需像往常一样使用它,使用您喜欢的任何方法(Spring Boot将自动连接到魔法,但属性必须当然位于类路径中):

使用@Value注解

@Value("${db.password}")
private String password;

或者使用环境变量

@Autowired
private Environment environment;

public void doSomething(Environment env) {
    System.out.println(env.getProperty("db.password"));
}

更新:对于生产环境,为避免在命令行中公开密码,因为您可以使用 ps 查询进程,使用 history 查询之前的命令等等。您可以:
  • 创建一个脚本,如下所示:touch setEnv.sh

  • 编辑 setEnv.sh 以导出 JASYPT_ENCRYPTOR_PASSWORD 变量

    #!/bin/bash

    export JASYPT_ENCRYPTOR_PASSWORD=supersecretz

  • 使用 . setEnv.sh 执行该文件

  • 使用 mvn spring-boot:run & 在后台运行应用程序

  • 删除文件 setEnv.sh

  • 使用以下命令取消设置先前的环境变量:unset JASYPT_ENCRYPTOR_PASSWORD


2
请问您能否使用Gradle更详细地解释一下?@Frerica Piazza - testuser
2
@FedericoPiazza,mvn -Djasypt.encryptor.password=supersecretz spring-boot:run 不会在 ps 输出中显示密码,从而暴露密码吗? - Srki Rakic
1
@SrkiRakic 当然可以。这只是用于开发,如果您想用于生产环境,应该使用环境变量。Spring Boot 允许您使用 JASYPT_ENCRYPTOR_PASSWORD - Federico Piazza
1
哈哈,它是如何进入环境变量的呢?可能是从另一个文件中,比如服务定义文件:D 此外,当涉及到密码派生时,jasypt已经过时了,所以请确保使用完全随机的32个字符密码。 - Roman Plášil
1
@pixel,我已更新网址,请再次检查。 - Federico Piazza
显示剩余18条评论

21

除了已经提出的解决方案之外,我还可以添加一种选项来配置外部Secrets Manager,例如Vault

  1. 配置Vault服务器vault server -dev(仅限DEV而不是PROD)
  2. 编写秘密vault write secret/somename key1=value1 key2=value2
  3. 验证秘密vault read secret/somename

将以下依赖项添加到您的SpringBoot项目中:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>

添加Vault配置属性:

spring.cloud.vault.host=localhost
spring.cloud.vault.port=8200
spring.cloud.vault.scheme=http
spring.cloud.vault.authentication=token
spring.cloud.vault.token=${VAULT_TOKEN}

VAULT_TOKEN作为环境变量传递。

请参阅此处的文档

还有一个Spring Vault项目,也可用于访问、存储和撤销密钥。

依赖项:

<dependency>
    <groupId>org.springframework.vault</groupId>
    <artifactId>spring-vault-core</artifactId>
</dependency>

配置 Vault 模板:

@Configuration
class VaultConfiguration extends AbstractVaultConfiguration {

  @Override
  public VaultEndpoint vaultEndpoint() {
    return new VaultEndpoint();
  }

  @Override
  public ClientAuthentication clientAuthentication() {
    return new TokenAuthentication("…");
  }
}

注入并使用VaultTemplate:

public class Example {

  @Autowired
  private VaultOperations operations;

  public void writeSecrets(String userId, String password) {
      Map<String, String> data = new HashMap<String, String>();
      data.put("password", password);
      operations.write(userId, data);
  }

  public Person readSecrets(String userId) {
      VaultResponseSupport<Person> response = operations.read(userId, Person.class);
      return response.getBody();
  }
}

使用 Vault PropertySource

@VaultPropertySource(value = "aws/creds/s3",
  propertyNamePrefix = "aws."
  renewal = Renewal.RENEW)
public class Config {

}

使用示例:

public class S3Client {

  // inject the actual values
  @Value("${aws.access_key}")
  private String awsAccessKey;
  @Value("${aws.secret_key}")
  private String awsSecretKey;

  public InputStream getFileFromS3(String filenname) {
    // …
  }
}

使用类似于Vault / etcd(或任何其他)的系统是正确的方法。https://diogomonica.com/2017/03/27/why-you-shouldnt-use-env-variables-for-secret-data/ - Book Of Zeus
4
-1是因为这段内容没有解释“主”密钥(VAULT_TOKEN)的安全性。VAULT_TOKEN环境变量是从哪里来的?它是如何被保护的?如果不保护好这个密钥,攻击者就可以使用Spring Boot jar中打包的代码来检索vault中的秘密。 - corporatedrone
同时,保护生产环境是主要问题。因此,在这里必须谈论它。对于开发/测试环境的指导是可以的。 - sofs1
这个在有多个密码时可行。虽然只需要一个密码连接,但把保险库密码放在环境变量中,也可以避免把其他密码放在同一环境中,这听起来很有趣。 - Lee Meador
1
为什么我们只想用于开发?生产环境同样重要。 - Cem Dırman

19

更新:我注意到一些人对此进行了负面评价,所以我必须说,尽管这不是一个理想的解决方案,但在某些情况下,它能够起作用并且被接受。

当服务绑定到应用程序时,Cloudfoundry使用环境变量来注入凭据。更多信息请参见https://docs.cloudfoundry.org/devguide/services/application-binding.html

如果您的系统不是共享的,那么这种方法也是可以接受的,特别是在本地开发中。当然,更加安全的方式由@J-Alex在答案中进行了解释。

答案:

如果您想隐藏密码,最简单的解决方法就是在application.properties文件或直接在代码中使用环境变量

application.properties文件中:

mypassword=${password}

然后在您的配置类中:

@Autowired
private Environment environment;

[...]//Inside a method
System.out.println(environment.getProperty("mypassword"));

在你的configuration类中:

@Value("${password}")
private String herokuPath;

[...]//Inside a method
System.out.println(herokuPath);

注意: 设置环境变量后,您可能需要重新启动。 对于Windows操作系统:

在Windows中

有关更多信息,请参阅此文档


31
我不认为在环境变量中设置主密码是一个好主意。这样做会导致密码比必要的更容易被泄露。像Federico所示,在启动时提供密码比将其设置在环境变量中更加隐蔽和安全。 - Jaavaaan
是的,如果你正在使用共享计算机,那么这并不适用。但是,如果你是计算机的唯一管理员,那么其他用户就无法看到环境变量。我回答了隐藏部分和更简单的部分。但是,我同意Federico建议的方法更好。 - Sanjay Rawat
请参见:https://diogomonica.com/2017/03/27/why-you-shouldnt-use-env-variables-for-secret-data/ - Book Of Zeus
@Jaavaaan在环境变量中提供JASYPT_ENCRYPTOR_PASSWORD以解码数据库密码与此答案一样不安全。 - m1ld
@Jaavaaan 请阅读更新。我已经提到这种方法并不在所有情况下都是安全的,但是有一些合法的使用场景,比如CF。同时,我也指出了使用HashiCorp Vault更加安全可靠的解决方案。 - Sanjay Rawat
在运行Spring Boot应用程序时,环境变量是否安全? - Shashi Ranjan

12

1

除了流行的K8s、jasypt或vault解决方案外,还有Karmahostage。它使您能够执行以下操作:

@EncryptedValue("${application.secret}")
private String application;

它的工作方式与jasypt相同,但加密是在专用的saas解决方案上进行的,并附有更细粒度的ACL模型。

1

如果你在使用Spring Boot环境下流行的Kubernetes(K8S)或OpenShift,那么有可能在运行时存储和检索应用程序属性。这种技术称为secrets。在Kubernetes或OpenShift的配置yaml文件中,您声明变量和占位符,并在K8S\OpenShift侧声明与此占位符对应的实际值。 有关实现细节,请参见: K8S:https://kubernetes.io/docs/concepts/configuration/secret/ OpenShift:https://docs.openshift.com/container-platform/3.11/dev_guide/secrets.html


0

我在Spring Boot应用程序中隐藏DB密码的解决方案application.properties已经实现here

场景:在启动时从application.properties读取一些虚假密码并保存在全局Spring对象ConfigurableEnvironment中。在运行时,它将被编程方式替换为真实的DB密码。 真实密码将从另一个配置文件中读取,该文件保存在安全的项目外部位置。

不要忘记:使用以下方式从主类调用Bean

@Autowired
private SchedUtilility utl;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接