Spring Boot: application.properties’te bulunan propertylerin şifrelenmesi

Aslında başlıkta application.properties diye belirttiysem de bu mini tutorial application.yaml dosyaları için de geçerli. Database şifreleri gibi bazı kritik değerleri property dosyasında tutmamız gerekebiliyor ve bu değerleri açık olarak tutmayı güvenlik gerekçeleriyle istemeyebiliriz. Bunun için Jasypt(Java Simplified Encryption) kütüphanesini kullanacağım.

İlk olarak gerekli bağımlılıkları projemize ekliyoruz. Maven kullandığım için maven dependency’sini pom.xml‘ime ekleyeceğim.

<!-- https://mvnrepository.com/artifact/com.github.ulisesbocchio/jasypt-spring-boot-starter -->
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>2.0.0</version>
</dependency>
Şifreli olarak kullanmak istediğimiz değerleri application.properties (veya yaml) içerisinde parantez içerisine alarak başına ENC eki getiriyoruz. Örneğin;

MyProperty=ENC(23ClLWiedLx8v6XT6Wk+Bg==)

Peki bu şifreleri değerleri nasıl üreteceğiz? Bunun için Jasypt‘i kullanacağız. http://www.jasypt.org/ adresine gidin ve en son versiyonu indirin. Daha sonra jasypt\bin altında bulunan, işletim sistemimize bağlı olarak encrypt.sh veya encrypt.bat skriptini kullanarak istediğimiz her şeyi şifreleyebiliriz. Şifreleme sırasında algoritma listesinden dilediğimiz algoritmayıda belirtebiliriz fakat ben bu ayarı varsayılan değerde bırakıp sadece şifrelemek istediğim değeri ve bu değeri şifrelerken kullanacağım gizli anahtarı vereceğim. Bu gizli anahtar daha sonra değerleri deşifre ederken de gerekli olacak.

Spring Boot uygulamamızın bu değerleri deşifre etmesi için uygulamamızın başına @EnableConfigurationProperties yazmamız yeterli. Daha sonra Jasypt, properties dosyasında ENC ile başlayan değerleri otomatik olarak deşifre etmeye çalışacaktır. Aşağıdaki örnekte eklediğim CommandLineRunner’ı sadece deşifre mekanizmasının işleyişini göstermek için koydum.

@EnableEncryptableProperties
@SpringBootApplication
public class JasyptExampleApplication {

  public static void main(String[] args) {
    SpringApplication.run(JasyptExampleApplication.class, args);
  }
 
  @Component
  public class MyRunner implements CommandLineRunner {
   
    @Value("${myProperty}")
    private String myProperty;

    @Override
    public void run(String... args) throws Exception {
      System.out.println("My property is " + myProperty);
    }
   
  }
}
Fakat kodu bu şekilde koştuğunuz durumda aşağıdaki hatayı alacaksınız:

Error creating bean with name 'demo.JasyptExampleApplication$MyRunner': Injection of autowired dependencies failed; nested exception is java.lang.IllegalStateException: Required Encryption configuration property missing: jasypt.encryptor.password

Bunun sebebi Jasypt‘in değerleri deşifre edecek gizli anahtarı bilmiyor oluşu. Bu gizli anahtarı uygulamamıza bir kaç şekilde söyleyebiliriz:
1- Uygulamayı koşarken komut satırı parametresi olarak verebiliriz;
–jasypt.encryptor.password=MY_SECRET
2- Environment değeri olarak atayabiliriz, bu yöntem eğer uygulamayı Tomcat üzerinde koşacaksanız çok işe yarayabilir. Tomcat‘in setenv.sh dosyasına aşağıdaki şekilde yazarsak Tomcat ayağa kalkarken bu değeri atayacağı için uygulamamız anahtarı bulacaktır;
export CATALINA_OPTS=”-Djasypt.encryptor.password=MY_SECRET”
Hatta daha güvenli hale getirmek için uygulama ayağa kalktıktan sonra Environment’tan değeri silebiliriz ve böylelikle arkada açık kapı bırakmamış oluruz
3- Gizli anahtarı application.properties içerisinde belirtebiliriz fakat bu çok saçma bir yöntem çünkü zaten amacımız application.properties içerisinde bulunan değerlerin insanlar tarafından okunmaması. Ama bu anahtarı burada vererek değerleri deşifre etmenin de önünü açmış oluyoruz. Yani değerleri hiç şifrelememekle pek bir farkı yok.

Eğer daha iyi bir yöntem biliyorsanız lütfen yorumda belirtin!

Şimdi asıl sonuca gelelim:

2018-04-25 14:03:26.413 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource configurationProperties [org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertySource] to AOP Proxy
2018-04-25 14:03:26.413 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource commandLineArgs [org.springframework.core.env.SimpleCommandLinePropertySource] to EncryptableEnumerablePropertySourceWrapper
2018-04-25 14:03:26.414 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource systemProperties [org.springframework.core.env.MapPropertySource] to EncryptableMapPropertySourceWrapper
2018-04-25 14:03:26.414 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource systemEnvironment [org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor$OriginAwareSystemEnvironmentPropertySource] to EncryptableMapPropertySourceWrapper
2018-04-25 14:03:26.414 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource random [org.springframework.boot.env.RandomValuePropertySource] to EncryptablePropertySourceWrapper
2018-04-25 14:03:26.415 INFO 10028 --- [ main] c.u.j.EncryptablePropertySourceConverter : Converting PropertySource applicationConfig: [classpath:/application.properties] [org.springframework.boot.env.OriginTrackedMapPropertySource] to EncryptableMapPropertySourceWrapper
2018-04-25 14:03:26.468 INFO 10028 --- [ main] c.u.j.r.DefaultLazyPropertyResolver : Property Resolver custom Bean not found with name 'encryptablePropertyResolver'. Initializing Default Property Resolver
2018-04-25 14:03:26.470 INFO 10028 --- [ main] c.u.j.d.DefaultLazyPropertyDetector : Property Detector custom Bean not found with name 'encryptablePropertyDetector'. Initializing Default Property Detector
2018-04-25 14:03:26.472 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : String Encryptor custom Bean not found with name 'jasyptStringEncryptor'. Initializing Default String Encryptor
2018-04-25 14:03:26.478 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.algorithm, using default value: PBEWithMD5AndDES
2018-04-25 14:03:26.479 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.keyObtentionIterations, using default value: 1000
2018-04-25 14:03:26.479 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.poolSize, using default value: 1
2018-04-25 14:03:26.479 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.providerName, using default value: null
2018-04-25 14:03:26.479 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.providerClassName, using default value: null
2018-04-25 14:03:26.479 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.saltGeneratorClassname, using default value: org.jasypt.salt.RandomSaltGenerator
2018-04-25 14:03:26.480 INFO 10028 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.stringOutputType, using default value: base64
2018-04-25 14:03:26.934 INFO 10028 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-04-25 14:03:26.948 INFO 10028 --- [ main] demo.JasyptExampleApplication : Started JasyptExampleApplication in 1.264 seconds (JVM running for 2.06)
My property is MBcoder

Gördüğünüz gibi PBEWithMD5AndDES algoritmasını varsayılan değer olarak seçti ve verdiğim MY_SECRET anahtarı sayesinde myProperty değerini(23ClLWiedLx8v6XT6Wk+Bg==) başarılı bir şekilde deşifre etti.

Umarım yararlı bir yazı olmuştur. Başka bir yazıda görüşmek dileğiyle!

Eğer içeriği beğendiyseniz paylaşabilirsiniz!

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

This site uses Akismet to reduce spam. Learn how your comment data is processed.