【发布时间】:2016-09-21 03:26:33
【问题描述】:
Spring Boot 使用属性文件,至少默认情况下,密码是纯文本的。是否有可能以某种方式隐藏/解密这些?
【问题讨论】:
标签: java spring spring-boot
Spring Boot 使用属性文件,至少默认情况下,密码是纯文本的。是否有可能以某种方式隐藏/解密这些?
【问题讨论】:
标签: java spring spring-boot
Spring Cloud Config Server 将允许这种类型的行为。使用 JCE,您可以在服务器上设置一个密钥并使用它来加密应用程序属性。
http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html
【讨论】:
更新:我注意到人们对此投了反对票,所以我不得不说,虽然这不是一个理想的解决方案,但在某些用例中这是可行的并且可以接受。 当服务绑定到应用程序时,Cloudfoundry 使用环境变量注入凭据。更多信息https://docs.cloudfoundry.org/devguide/services/application-binding.html
如果你的系统不是共享的,那么对于本地开发来说这也是可以接受的。当然,更安全可靠的方式在@J-Alex 的Answer 中进行了说明。
答案:
如果您想隐藏您的密码,那么最简单的解决方案是在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);
注意:设置环境变量后可能需要重新启动。 对于窗户:
请参阅此Documentation 了解更多信息。
【讨论】:
您可以使用 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 轻松配置它,您可以使用其启动器 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.ricston.com/blog/encrypting-properties-in-spring-boot-with-jasypt-spring-boot/
要在您的应用程序中使用您的加密属性,只需像往常一样使用它,使用您喜欢的任何一种方法(Spring Boot 具有魔力,无论如何属性当然必须在类路径中):
使用@Value注解
@Value("${db.password}")
private String password;
或者使用Environment
@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
导出 JASYPT_ENCRYPTOR_PASSWORD=supersecretz
. setEnv.sh执行文件
mvn spring-boot:run & 在后台运行应用程序
setEnv.sh
unset JASYPT_ENCRYPTOR_PASSWORD
【讨论】:
mvn -Djasypt.encryptor.password=supersecretz spring-boot:run 不会出现在ps 输出中,暴露密码吗?
JASYPT_ENCRYPTOR_PASSWORD
input="this is the text I want to encrypt" 和 password="this is the key used to encrypt the input"
对于已经提出的解决方案,我可以添加一个选项来配置外部Secrets Manager,例如Vault。
vault server -dev(仅适用于 DEV,不适用于 PROD)vault write secret/somename key1=value1 key2=value2
vault read secret/somename
将以下依赖项添加到您的 SpringBoot 项目中:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>
添加保险柜配置属性:
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 作为环境变量传递。
参考文档here.
有一个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();
}
}
使用保险柜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) {
// …
}
}
【讨论】:
如果您在 Spring Boot 环境中使用非常流行的 Kubernetes (K8S) 或 OpenShift,则可以在运行时存储和检索应用程序属性。这种技术称为秘密。在 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
【讨论】:
我在 Spring Boot App 的 application.properties 中隐藏 DB-Password 的解决方案确实实现了 here。
场景:一些假密码已经在启动时从application.properties 读取并保存,在全局 Spring 对象 ConfigurableEnvironment 中,将在运行时以编程方式替换为真正的 DB-Password。 真正的密码将从另一个配置文件中读取,保存在安全的项目外部位置。
不要忘记:从main class 调用Bean 使用:
@Autowired
private SchedUtilility utl;
【讨论】:
除了流行的 K8s、jasypt 或 vault 解决方案之外,还有Karmahostage。它使您能够:
@EncryptedValue("${application.secret}")
private String application;
它的工作方式与 jasypt 相同,但加密发生在专用 saas 解决方案上,并附加了更细粒度的 ACL 模型。
【讨论】: