저번 주에 프로젝트 시작하면서 만들었던 것들을 풀어내보려고 한다.
우선 PasswordEncoder 쓰는 방법
Gradle로 설명할게요.
dependencies{
implementation 'org.springframework.boot:spring-boot-starter-security'
}
@Configuration
public class CommonConfig {
@Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
설정은 이게 끝.
암호화는
@Autowired
PasswordEncoder passwordEncoder; // DI
@Test
void pwdEnc() {
String pwd = "kedric123";
String encodedPwd = passwordEncoder.encode(pwd); //암호화 하는부분
System.out.println(encodedPwd);
}
결과
{bcrypt}$2a$10$xO99cg0RupsQY4PNvdPJe.neRL7JSplM8t/NQUgBRGnOM19/FbstS
PasswordEncder를 DI 받아서
passwordEncoder.encode(비밀번호)를 해주면 자연스럽게 암호화된다.
테스트 해보니 계속 값은 바뀜.
기존 비밀번호와 맞는지 확인하는 법은
passwordEncoder.matches(클라이언트로부터 받은 비번, 데이터베이스 비번)
별 거 없었네요! 이제 왜 이런 암호화를 쓰는지 알아보도록 할게요.
우선 암호화는 단방향 암호화와 양방향 암호화가 있다.
간단히 말하자면
단방향(MD5, SHA 등)은 암호화(encoding)는 가능해도 복호화(decoding)는 안되는 것을 말하고,
양방향(AES,RSA,DES 등) 은 암호화 및 복호화가 가능한 것이다.
더 자세한 내용은 검색해서 알아보도록 하자.
두 방식을 놓고 보면
단방향으로 암호화된 경우는 복호화가 불가능하기 때문에 암호를 알아내기 어려울 것처럼 보인다.
하지만 여기서 우리가 Spring 이 제공하는 PasswordEncoder를 쓰는 이유가 나온다.
위 암호화 예시에서 언급했지만
PasswordEncoder 를 이용하여 encode하는 경우 암호화된 결과값이 항상 다르게 나온다.
기존 단방향 암호화의 경우,
암호를 알아내려는 공격자가 rainbow table을 이용하여 rainbow attack을 하는경우, 결국 비밀번호를 알아낼 수 있다.
간단히 말하면
kedric1234를 암호화 하는데, 항상 똑같이 암호화된 string이 asdqwe123이라고 한다면
공격자는 암호를 알수 없지만 반대로 asdqwe123가 kedric1234라는 것은 알 수 있다는 것이다.
이런 데이터 목록들을 rainbow table이라고 한다.
레인보우 테이블(Rainbow Table)은 해시 암호화된 비밀번호를 역으로 찾기 위해 사용되는 데이터 구조입니다. 해시 암호화는 비밀번호를 고정 길이의 문자열로 변환하는 방식으로, 암호화를 통해 보안을 강화합니다. 하지만 해시 값을 역으로 비밀번호로 변환하는 것은 어려운 작업이므로, 이를 빠르게 수행할 수 있도록 도와주는 것이 레인보우 테이블입니다.
일반적으로 가능한 모든 비밀번호와 그에 해당하는 해시 값을 계산해두고 이를 저장해 둔 데이터베이스라네요.
레인보우 테이블은 강력하지만 몇 가지 한계가 있습니다:
그래서 BCryptPasswordEncoder를 사용하여 비밀번호를 해싱하고 솔팅을 자동으로 처리해줍니다.