스프링 시큐리티 - 4. 암호 처리

2025. 4. 30. 11:04·스프링/스프링 시큐리티 인 액션 (도서 정리)

PasswordEncoder는 인증 프로세스에서 암호가 유효한지를 확인한다. 인코딩된 암호를 저장하며 아무도 암호를 읽을 수 없게 해시를 저장하는 것이 좋다.

public interface PasswordEncoder {
    String encode(CharSequence rawPassword);

    boolean matches(CharSequence rawPassword, String encodedPassword);

    default boolean upgradeEncoding(String encodedPassword) {
        return false;
    }
}

- encode 메서드는 주어진 문자열을 변환해 반환한다. 주어진 암호의 해시를 제공하거나 암호화를 수행한다.

- matches 메서드에서 인코딩된 문자열이 원시 암호와 일치하는지 확인한다. 지정된 암호를 인증 프로세스에서 알려진 자격 증명의 집합을 대상으로 비교한다.

- upgradeEncoding은 기본값이 false이며, true를 반환하도록 재정의하면 인코딩된 암호를 보안 향상을 위해 다시 인코딩한다.(원래 암호를 알아내기 더 어려울 수 있으나 모호하기 때문에 추천 X)

 

2장에서 나온 NoOpPasswordEncoder는 가장 직관적으로 암호를 일반 텍스트로 간주하였다.

 

public class PlainTextPasswordEncoder implements PasswordEncoder {

	@Override
	public String encode(CharSequence rawPassword) {
        return rawPassword.toString(); // 암호를 변경하지 않고 그대로 반환
    }

	@Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return rawPassword.toString().equals(encodedPassword); // 두 문자열이 같은지 확인
    }
}

 

해싱 알고리즘 SHA-512를 이용하는 PasswordEncoder의 간단한 구현

package com.studiop.ssiach2ex1;

import org.springframework.security.crypto.password.PasswordEncoder;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Sha512PasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence rawPassword) {
        return hashWithSHA512(rawPassword.toString());
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        String hashedPassword = encode(rawPassword);
        return encodedPassword.equals(hashedPassword);
    }

    private String hashWithSHA512(String input) {
        StringBuilder result = new StringBuilder();
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            byte[] digested = md.digest(input.getBytes());
            for (int i = 0; i < digested.length; i++) {
                result.append(Integer.toHexString(0xFF & digested[i]));
            }
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Bad algorithm");
        }
        return result.toString();
    }
}

 

스프링 시큐리티에 구현되어 있는 PasswordEncoder

- NoOpPasswordEncoder : 암호를 인코딩하지 않고 일반 텍스트로 유지. 예제 용도로만 사용해야 하며 실제 시나리오에서는 절대 쓰지 말아야 한다.

- StandardPasswordEncoder : SHA-256을 이용해 암호를 해시한다. 강도가 약한 구식이라서 새 구현에는 쓰지 말아야 한다.

- Pbkdf2PasswordEncoder : PBKDF2를 이용한다.

- BCryptPasswordEncoder : bcrypt 강력 해싱 함수로 암호를 인코딩한다.

- SCryptPasswordEncoder : scrypt 해싱 함수로 암호를 인코딩한다.

 

간단한 예시(타입을 인터페이스로 지정)

PasswordEncoder p = NoOpPasswordEncoder.getInstance();
PasswordEncoder p = new StandardPasswordEncoder();
PasswordEncoder p = new StandardPasswordEncoder("secret");

SecureRandom s = SecureRandom.getInstanceStrong();
PasswordEncoder p = new BCryptPasswordEncoder(4, s);
...

 

* DelegatingPasswordEncoder 전략

- 특정 애플리케이션 버전부터 인코딩 알고리즘이 변경된 경우, 현재 사용되는 알고리즘에서 취약성이 발견되어서 신규 등록 사용자의 자격 증명을 변경하고 싶지만, 기존 자격 증명을 변경하기 쉽지 않은 경우, 여러 종류의 해시를 지원해야 할 때의 대안. 자체 인코딩 알고리즘을 구현하는 대신 다른 구현 인스턴스에 작업을 위임함.

 

@Configuration
public class ProjectConfig {

	@Bean
    public PasswordEncoder passwordEncoder() {
    	Map<String, PasswordEncoder> encoders = new HashMap<>();
        
        encoders.put("noop", NoOpPasswordEncoder.getInstance());
        encoders.put("bcrypt", new BCryptPasswordEncoder());
        encoders.put("scrypt", new SCryptPasswordEncoder());
        
        return new DelegatingPasswordEncoder("bcrypt", encoders);
    }
}

 

- 해시는 해당 해시를 의미하는 알고리즘의 이름을 나타내는 접두사로 시작한다.  암호의 접두사를 기준으로 올바른 PasswordEncoder 구현에 작업을 위임함.

접두사가 없으면 DelegatingPasswordEncoder 인스턴스를 만들 때 첫 번째 매개변수로 지정한다.

 

PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
// 모든 표준 제공 PasswordEncoder의 구현에 대한 맵을 가진 DelegatingPasswordEncoder를 생성하는 방법을 제공함.
// PasswordEncoderFactories 클래스에는 bcrypt가 기본 인코더인 DelegatingPasswordEncoder의 구현을 반환하는
// 정적 메서드 createDelegatingPasswordEncoder() 가 있음

 

인코딩, 암호화, 해싱 개념

인코딩(Encoding) : 주어진 입력에 대한 모든 변환. 문자열을 뒤집는 함수 x가 있을 때 x -> y를 ABCD에 적용하면 DCBA가 나옴.

암호화(Encryption) : 출력을 얻기 위해 입력 값과 키를 모두 지정하는 특정한 유형의 인코딩. 키를 이용하면 나중에 누가 출력에서 입력을 얻는 함수를 호출할 수 있는지 선택할 수 있음(키를 소유하는 자에 따라 할 수 있는지가 선택되니까). (x, k) -> y. 이며, (y, k) -> x 를 역함수 복호화(Reverse Function Decryption)라고 한다. 

암호화에서 쓰는 키와 복호화에 쓰는 키가 같으면 대칭 키라고 하며, (x, k1) -> y, (y, k2) -> x 처럼 암호화와 복호화에 다르키를 쓰면 이를 비대칭 키(Asymmetric Key)라고 하며 (k1, k2)를 키 쌍이라고 하며 k1을 공개 키(Public Key)라고 하고 k2를 개인 키(private key)라고 한다. 이와 같이 개인 키의 소유자는 데이터를 복호화할 수 있다.

해싱(Hashing) : 함수가 한 방향으로만 작동하는 특정한 유형의 인코딩. 출력 y에서 입력 x를 얻을 수 없지만, 출력 y가 입력 x에 해당하는지는 알 수 있음. x -> y, (x, y) -> boolean. 때때로 입력에 임의의 값을 추가할 수도 있는데, (x, k) -> y. 이 값을 솔트(Salt)라고 한다. 솔트는 함수를 더 강하게 만들어 결과에서 입력을 얻는 역함수의 적용 난도를 높인다.

 

UserDetails 스프링 시큐리티가 관리하는 사용자를 나타냄
GrantedAuthority 애플리케이션의 목적 내에서 사용자에게 허용되는 작업을 정의 (읽기, 쓰기, 삭제 등)
UserDetailsSerivce 사용자 이름으로 사용자 세부 정보를 검색하는 객체를 나타냄
UserDetailsManager UserDeatilsService의 더 구체적인 계약. 사용자 이름으로 사용자를 검색하는 것 외에도 사용자 컬렉션이나 특정 사용자를 변경할 수도 있음
PasswordEncoder 암호를 암호화 또는 해시하는 방법과 주어진 인코딩된 문자열을 일반 텍스트 암호와 비교하는 방법을 지정

 

4.2 스프링 시큐리티 암호화 모듈에 관한 추가 정보

- 암호화 및 복호화 함수와 키 생성 기능은 자바 언어에서 기본 제공되지 않아 스프링 시큐리티에서 자체 솔루션을 제공함

 

키 생성기 : 해싱 및 암호화 알고리즘을 위한 키를 생성하는 객체 (StringKeyGenerator 인터페이스)

암호기 : 데이터를 암호화 및 복호화하는 객체 (TextEncryptor 인터페이스)

 

하략... 책 109페이지

 

요약

- PasswordEncoder는 인증 논리에서 암호를 처리하는 가장 중요한 책임을 담당함

- 스프링 시큐리티는 해싱 알고리즘에 여러 대안을 제공하므로 필요한 구현을 선택하기만 하면됨

- 스프링 시큐리티는 암호화 모듈(SSCM)에는 키 생성기와 암호기를 구현하는 여러 대안이 있음

'스프링 > 스프링 시큐리티 인 액션 (도서 정리)' 카테고리의 다른 글

스프링 시큐리티 - 5. 인증 구현  (0) 2025.04.30
스프링 시큐리티 - 3. 사용자 관리  (0) 2025.04.29
스프링 시큐리티 - 2. 기본 프로젝트 만들어보기  (1) 2025.04.29
스프링 시큐리티 - 1. 보안 개념  (0) 2025.04.28
'스프링/스프링 시큐리티 인 액션 (도서 정리)' 카테고리의 다른 글
  • 스프링 시큐리티 - 5. 인증 구현
  • 스프링 시큐리티 - 3. 사용자 관리
  • 스프링 시큐리티 - 2. 기본 프로젝트 만들어보기
  • 스프링 시큐리티 - 1. 보안 개념
효재감자
효재감자
  • 효재감자
    효재감자의 우당탕탕 개발일지
    효재감자
  • 전체
    오늘
    어제
    • 분류 전체보기 (73)
      • 아무거나 (3)
      • 백준 (44)
      • 알고리즘 (4)
      • 자바 (1)
      • 리눅스(우분투) 및 클라우드 (2)
      • 스프링 (14)
        • 스프링 시큐리티 인 액션 (도서 정리) (5)
      • 플러터(Dart) (0)
  • 블로그 메뉴

    • 홈
    • Github
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    백준
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
효재감자
스프링 시큐리티 - 4. 암호 처리
상단으로

티스토리툴바