Spring Boot cách ẩn mật khẩu trong tệp thuộc tính


81

Spring Boot sử dụng tệp thuộc tính và ít nhất theo mặc định, mật khẩu ở dạng văn bản thuần túy. Có thể ẩn / giải mã chúng bằng cách nào đó không?

Câu trả lời:


86

Bạn có thể sử dụng Jasypt để mã hóa các thuộc tính, vì vậy bạn có thể có thuộc tính của mình như sau:

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

Jasypt cho phép bạn mã hóa các thuộc tính của mình bằng các thuật toán khác nhau, sau khi bạn có được thuộc tính được mã hóa mà bạn đặt bên trong ENC(...). Ví dụ: bạn có thể mã hóa theo cách này thông qua Jasypt bằng cách sử dụng thiết bị đầu cuối:

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=

Để dễ dàng cấu hình nó với Spring Boot, bạn có thể sử dụng bộ khởi động jasypt-spring-boot-starter với ID nhómcom.github.ulisesbocchio

Hãy nhớ rằng bạn sẽ cần khởi động ứng dụng của mình bằng chính mật khẩu bạn đã sử dụng để mã hóa các thuộc tính. Vì vậy, bạn có thể khởi động ứng dụng của mình theo cách này:

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

Hoặc sử dụng biến môi trường (nhờ liên kết thư giãn khởi động lò xo):

export JASYPT_ENCRYPTOR_PASSWORD=supersecretz
mvn spring-boot:run

Bạn có thể kiểm tra liên kết dưới đây để biết thêm chi tiết:

https://www.ricston.com/blog/encrypting-properties-in-spring-boot-with-jasypt-spring-boot/

Để sử dụng các thuộc tính được mã hóa trong ứng dụng của bạn, chỉ cần sử dụng nó như bình thường, sử dụng một trong hai phương pháp bạn thích (Spring Boot kết nối điều kỳ diệu, dù sao thì thuộc tính tất nhiên phải nằm trong classpath):

Sử dụng @Valuechú thích

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

Hoặc sử dụng Environment

@Autowired
private Environment environment;

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

Cập nhật: cho môi trường sản xuất, để tránh lộ mật khẩu trong dòng lệnh, vì bạn có thể truy vấn các quy trình với ps, các lệnh trước đó với history, v.v. Bạn có thể:

  • Tạo một tập lệnh như sau: touch setEnv.sh
  • Chỉnh sửa setEnv.shđể xuất JASYPT_ENCRYPTOR_PASSWORDbiến

    #! / bin / bash

    xuất JASYPT_ENCRYPTOR_PASSWORD = supersecretz

  • Thực thi tệp với . setEnv.sh
  • Chạy ứng dụng trong nền với mvn spring-boot:run &
  • Xóa tệp setEnv.sh
  • Bỏ đặt biến môi trường trước đó bằng: unset JASYPT_ENCRYPTOR_PASSWORD

2
Bạn có thể vui lòng giải thích thêm chi tiết sử dụng gradle @Frerica Piazza
testuser

Nó không rõ ràng về việc sử dụng với maven. bạn vượt qua một số tài sản và những gì hơn nữa? Tệp tài sản ở đâu? làm thế nào để hiện giá trị này trong mã?
gstackoverflow

1
@FedericoPiazza Sẽ không mvn -Djasypt.encryptor.password=supersecretz spring-boot:runhiển thị trong psđầu ra, lộ mật khẩu sao?
Srki Rakic

1
@SrkiRakic, tất nhiên là có. Đây chỉ là để phát triển, nếu bạn muốn nó cho sản xuất, bạn nên sử dụng các biến môi trường. Khởi động mùa xuân cho phép bạn sử dụngJASYPT_ENCRYPTOR_PASSWORD
Federico Piazza

1
haha và làm thế nào để nó vào được các biến môi trường? Có lẽ từ một tập tin như dịch vụ difinition: D Cũng jasypt là lỗi thời khi nói đến nguồn gốc mật khẩu để đảm bảo sử dụng hoàn toàn ngẫu nhiên mật khẩu 32 ký tự
La Mã Plasil

14

CẬP NHẬT: Tôi nhận thấy mọi người bỏ phiếu cho điều này, vì vậy tôi phải nói rằng mặc dù đây không phải là một giải pháp lý tưởng, nhưng điều này hoạt động và có thể chấp nhận được trong một số trường hợp sử dụng. Cloudfoundry sử dụng các biến Môi trường để đưa thông tin xác thực khi Dịch vụ được liên kết với một ứng dụng. Thông tin thêm https://docs.cloudfoundry.org/devguide/services/application-binding.html

Và cũng như nếu hệ thống của bạn không được chia sẻ, thì đối với sự phát triển cục bộ, điều này cũng có thể chấp nhận được. Tất nhiên, cách an toàn và bảo mật hơn được giải thích trong Trả lời của @ J-Alex.

Câu trả lời:

Nếu bạn muốn ẩn mật khẩu của mình thì giải pháp đơn giản nhất là sử dụng các biến Môi trường trong application.propertiestệp hoặc trực tiếp trong mã của bạn.

Trong application.properties:

mypassword=${password}

Sau đó, trong lớp cấu hình của bạn:

@Autowired
private Environment environment;

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

Trong configurationlớp học của bạn :

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

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

Lưu ý: Bạn có thể phải khởi động lại sau khi đặt biến môi trường. Cho cửa sổ:

Trong Windows

Tham khảo Tài liệu này để biết thêm thông tin.


25
Tôi không nghĩ rằng việc đặt mật khẩu chính trong môi trường vars là một ý kiến ​​hay. Mật khẩu bây giờ bị lộ nhiều hơn mức cần thiết. Cung cấp cho nó một khởi động như được hiển thị bởi Federico ít bị lộ và "an toàn" hơn so với thiết lập nó trong môi trường.
Jaavaaan

Yaa, không phải nếu bạn đang sử dụng máy tính chia sẻ. Nhưng nếu bạn là quản trị viên duy nhất của máy tính thì không người dùng nào khác có thể nhìn thấy các env vars. Tôi trả lời phần ẩn và phần dễ hơn. Nhưng có, tôi đồng ý rằng phương pháp được đề xuất của Federico là cách tốt hơn.
Sanjay Rawat



11

Đối với các giải pháp đã được đề xuất, tôi có thể thêm một tùy chọn để định cấu hình bên ngoài Secrets Managerchẳng hạn như Vault .

  1. Định cấu hình máy chủ Vault vault server -dev( Chỉ dành cho DEV và không dành cho PROD )
  2. Viết bí mật vault write secret/somename key1=value1 key2=value2
  3. Xác minh bí mật vault read secret/somename

Thêm phần phụ thuộc sau vào dự án SpringBoot của bạn:

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

Thêm thuộc tính cấu hình 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}

Truyền VAULT_TOKENnhư một biến môi trường.

Tham khảo tài liệu tại đây.

Có một dự án Spring Vault cũng có thể được sử dụng để truy cập, lưu trữ và thu hồi các bí mật.

Sự phụ thuộc:

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

Định cấu hình Mẫu Vault:

@Configuration
class VaultConfiguration extends AbstractVaultConfiguration {

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

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

Tiêm và sử dụng 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();
  }
}

Sử dụng Vault PropertySource:

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

}

Ví dụ sử dụng:

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) {
    // …
  }
}

+1 cho giải pháp này. Sử dụng một hệ thống như vault / etcd (hoặc bất kỳ hệ thống nào khác) là cách tốt nhất. diogomonica.com/2017/03/27/…
Book Of Zeus

3
-1 vì điều này không giải thích cách khóa "chính" (VAULT_TOKEN) được bảo mật. Biến môi trường VAULT_TOKEN đến từ đâu? Nó được bảo mật như thế nào? Nếu không bảo vệ khóa đó, kẻ tấn công có thể sử dụng nó để lấy các bí mật từ vault bằng cách sử dụng mã được đóng gói trong Spring Boot jar.
corporatedrone

Ngoài ra, đảm bảo sản phẩm là vấn đề chính. Vì vậy, nó phải được nói ở đây. Hướng dẫn cho môi trường Dev / QA nếu tốt.
sofs1

Điều này hoạt động khi có nhiều mật khẩu. Nó hoạt động với một mật khẩu để kết nối nhưng thật buồn cười khi nói rằng hãy đặt mật khẩu vault vào môi trường để bạn không phải đặt mật khẩu khác trong cùng môi trường.
Lee Meador

0

Trong trường hợp bạn đang sử dụng khá phổ biến trong môi trường Spring Boot Kubernetes (K8S) hoặc OpenShift, có khả năng lưu trữ và truy xuất các thuộc tính của ứng dụng trong thời gian chạy. Kỹ thuật này được gọi là bí mật . Trong tệp yaml cấu hình của bạn cho Kubernetes hoặc OpenShift, bạn khai báo biến và trình giữ chỗ cho nó và ở phía K8S \ OpenShift khai báo giá trị thực tương ứng với trình giữ chỗ này. Để biết chi tiết triển khai, hãy xem: K8S: https://kubernetes.io/docs/concept/configuration/secret/ OpenShift: https://docs.openshift.com/container-platform/3.11/dev_guide/secrets.html


0

Giải pháp của tôi để che giấu một DB-mật khẩu trong mùa xuân Boot App của application.properties không thực hiện ở đây .

Tình huống: một số mật khẩu giả đã được đọc và lưu từ application.properties khi bắt đầu, trong đối tượng Spring toàn cầu ConfigurableEn Môi trường sẽ được, trong Run-Time được thay thế lập trình bằng DB-Password thực. Mật khẩu thực sẽ được đọc từ một tệp cấu hình khác, được lưu ở nơi an toàn, bên ngoài dự án.

Đừng quên: gọi Bean từ lớp chính bằng:

@Autowired
private SchedUtilility utl;

0

Ngoài các giải pháp K8s, jasypt hoặc vault phổ biến, còn có Karmahostage . Nó cho phép bạn làm:

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

Nó hoạt động giống như cách jasypt làm, nhưng mã hóa xảy ra trên một giải pháp saas chuyên dụng, với một mô hình ACL chi tiết hơn được gắn vào nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.