Backend/Spring

[Spring security password Encoding] Spring boot 패스워드 간단 암호화

keepbang 2021. 5. 23. 14:13

spring boot에서 패스워드 암호화를 하기 위해 spring security를 사용해봤다.

먼저 가장 기본인 pom.xml에 dependency를 추가해준다

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>

그냥 패스워드 암호화만 사용하고자 하면 이것만 추가하면된다

bean으로 등록해서 사용하기 위해 따로 클래스를 만들었다.

package com.myProject.test.security.password;

import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.LdapShaPasswordEncoder;
import org.springframework.security.crypto.password.Md4PasswordEncoder;
import org.springframework.security.crypto.password.MessageDigestPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.security.crypto.password.StandardPasswordEncoder;
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class CustomPasswordEncoding {

    @SuppressWarnings("deprecation")
    public String sha256Encoding(String password) {
        String encPassword = "";
        encPassword = passwordEncoder("sha256").encode(password);
        //encPassword = encPassword.replace("{sha256}", "");
        return encPassword;
    }


    @SuppressWarnings("deprecation")
    public PasswordEncoder passwordEncoder(String type) {
        Map<String, PasswordEncoder> encoders = new HashMap<>();
        encoders.put("bcrypt", new BCryptPasswordEncoder());
        encoders.put("ldap", new LdapShaPasswordEncoder());
        encoders.put("MD4", new Md4PasswordEncoder());
        encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
        encoders.put("noop", NoOpPasswordEncoder.getInstance());
        encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
        encoders.put("scrypt", new SCryptPasswordEncoder());
        encoders.put("SHA-1", new MessageDigestPasswordEncoder("SHA-1"));
        encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));
        encoders.put("sha256", new StandardPasswordEncoder());

        return new DelegatingPasswordEncoder(type, encoders);
    }

    public boolean sha256Matching(String password, String encPassword) {
        //encPassword = "{sha256}"+encPassword;
        return passwordEncoder("sha256").matches(password, encPassword);
    }


}

암호화의 종류에는 여러 가지가 있다.

 

여기서는 그중에 sha256이라는 암호화를 사용해봤다.

 

물론 bcryptEncoding이라는 메서드를 만들어서 bcrypt암호화 방식을 사용해도 되고 MD5도 가능하다...(나는 안 해봄)

 

위에 코드에서는 안 나오지만... 실제 사용을 하면 아래와 같이 빨간 선이 생긴다... 거슬리! 게!

빨간 선이 생긴 건 사용을 권하지 않는다는 건데.... 음.... 이건 나중에 좀 더 알아봐야겠다...

 


 

메서드를 설명하자면

passwordEncoder(type) : 해당 메서드를 통해 PasswordEncoder를 가져온다. type에 암호화 방식을 넣어서 사용하면 된다.

PasswordEncoder는 단방향 암호화 방식이라 복호화하는 함수는 없는 거 같다...

메서드 안에 encoders로 map data를 넣어줬는데 저걸 추가 안 하면 아래와 같은 에러를 뱉어낸다.

Exception in thread "main" java.lang.IllegalArgumentException: idForEncode sha256is not found in idToPasswordEncoder {noop=org.springframework.security.crypto.password.NoOpPasswordEncoder@768debd, pbkdf2=org.springframework.security.crypto.password.Pbkdf2PasswordEncoder@490d6c15, SHA-1=org.springframework.security.crypto.password.MessageDigestPasswordEncoder@7d4793a8, ldap=org.springframework.security.crypto.password.LdapShaPasswordEncoder@449b2d27, SHA-256=org.springframework.security.crypto.password.MessageDigestPasswordEncoder@5479e3f, MD4=org.springframework.security.crypto.password.Md4PasswordEncoder@27082746, scrypt=org.springframework.security.crypto.scrypt.SCryptPasswordEncoder@66133adc, bcrypt=org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder@7bfcd12c, MD5=org.springframework.security.crypto.password.MessageDigestPasswordEncoder@42f30e0a}

 

sha256 Encoding : sha256 인코딩이다
sha256 Matching : sha256 인코딩을 입력받은 password와 비교해서 true, false를 반환하는 메서드다.
Component로 등록을 하면 다른 service에서 @Autowired 어노테이션을 사용해서 passwordEncoder를 사용할 수 있다.

 

  ...
  @Autowired
  private CustomPasswordEncoding passwordEncoder;
  ...
  ...
  ...
  password = passwordEncoding.base64EncodedSha256Encoding(password);
  ...

해당 암호화를 실행하면 나오는 포맷은 아래와 같다.

SHA-256 : {SHA-256}{nNpbd2DFGVK674+zvmcamqFylhPCD/CSE3PWHiiQbD0=}41e69d7756d7af9c2720fc4e18f192ee8c88adfc15148cd88d8d3ff9c6ed4472
bcrypt : {bcrypt}$2a$10$Etm1/ZzsGgS/FN7PhsG.dugF/5h78hErl2g19anjmF7Gkdzudti6G
sha256 : {sha256}b0dd6b00935eb00bbd002cdb6b083c9e7abf4761cf476a137b1daf68fe705fb994f9d96052136b24

위와 같이 앞에 {}로 암호화 타입이 적혀서 나온다. 만약 타입 없이 저장을 하고 싶다면 replace를 사용해서 없앤다음 저장을 하면 된다...

 

하지만!!

 

다시 불러와서 암호를 비교할 때는 앞에 암호화 타입이 꼭!! 있어야 한다.

 

만약 더 간단하게 클래스 같은 거 만들지 않고 사용하고 싶다!! 그렇다면 아래와 같이 사용하면 된다.

public static void main(String[] args) throws Exception {
    String password = "test1234";        
    BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();        
    String encPass = encoder.encode(password);        
    System.out.println(encPass);        
    System.out.println(encoder.matches(password, encPass));
}

//실행결과
//$2a$10$vzB./zaOm/2wMj2bLClxl.42b/OPDSdeIK15bhqeAFV5ae9sfOxzS
//true