IT 개발 관련/[Spring]

[Spring] Spring Security, PasswordEncoder 구현하기

Baileyton 2024. 5. 27. 15:33
728x90

PasswordEncoder를 이용한 Spring Security 비밀번호 암호화

비밀번호는 사용자 인증 시스템에서 가장 중요한 요소 중 하나로, 이를 안전하게 저장하는 것은 매우 중요합니다. 비밀번호가 평문으로 저장될 경우, 데이터베이스가 해킹 당했을 때 사용자 계정이 쉽게 노출될 위험이 있습니다. 이를 방지하기 위해 비밀번호를 단방향 암호화하여 저장하는 것이 필수적입니다.

 

Spring Security

비밀번호를 안전하게 저장할 수 있도록 비밀번호의 단방향 암호화를 지원하는 PasswordEncoder 인터페이스와 구현체들을 제공

 

Spring Security를 이용한 구현과정

Spring Security 의존성 주입

build.gradle

dependencies {
		implementation 'org.springframework.boot:spring-boot-starter-security'
}

Config 설정

WebSecurityConfig.java

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors().disable()
                .csrf().disable()
                .formLogin().disable()
                .headers().frameOptions().disable();
    }
}

PasswordEncoder 인터페이스 내부

public interface PasswordEncoder {

	// 비밀번호 단방향 암호화
	String encode(CharSequence rawPassword);
    
        // 암호화되지 않은 비밀번호(raw)와 암호화된 비밀번호(encode)가 일치하는지 비교
	boolean matches(CharSequence rawPassword, String encodedPassword);

	// 기본적으로 false를 return, Custom하게 구현할 경우 이를 기반으로 더 강력한 암호화 구현
	default boolean upgradeEncoding(String encodedPassword) {
		return false;
	}
}

 

 

SHA-256 기반 비밀번호 암호화 구현하기

PasswordEncoder

@Component
public class PasswordEncoder {
    
    // 비밀번호 단방향 암호화 메서드
    public String encode(String password) {
        try {
            // SHA-256 알고리즘 인스턴스 생성
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(password.getBytes()); // 비밀번호의 바이트 표현을 해시 함수에 업데이트

            byte[] byteData = md.digest(); // 해시 함수의 최종 해시 값 얻기

            // 바이트 배열을 16진수 문자열로 변환
            StringBuilder sb = new StringBuilder();
            for (byte b : byteData) {
                sb.append(String.format("%02x", b));
            }

            return sb.toString(); // 16진수 문자열 반환
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e); // 알고리즘이 없는 경우 예외 처리
        }
    }

    // 암호화되지 않은 비밀번호와 암호화된 비밀번호 비교 메서드
    public boolean matches(String rawPassword, String encodedPassword) {
        return encode(rawPassword).equals(encodedPassword); // 비밀번호 일치 여부 확인
    }
}
  • MessageDigest.getInstance("SHA-256")을 통해 SHA-256 해시 함수의 인스턴스를 얻어옵니다.
  • md.update(password.getBytes())를 통해 비밀번호의 바이트 표현을 해시 함수에 업데이트합니다.
  • md.digest()를 호출하여 해시 함수의 최종 해시 값을 얻어옵니다.
  • 얻어온 해시 값을 16진수 문자열로 변환하여 반환합니다.

평문 암호화 문제

동일한 비밀번호를 암호화하면 항상 동일한 해시 값이 생성됩니다. 이를 해결하기 위해 솔트(Salt)를 도입하는 방법이 있으며, 솔트는 해시할 때 추가되는 무작위 데이터로 매번 다른 해시 값을 생성하게 만든다.

728x90