비밀번호는 평문이나 복호화 가능한 형태로 저장하면 안 되고, bcrypt, scrypt, Argon2처럼 비밀번호 저장에 적합한 단방향 해시 알고리즘을 사용해야 합니다.
단순히 SHA-256 같은 고속 해시를 사용하는 것도 적절하지 않습니다. 비밀번호 해시는 무차별 대입 공격의 비용을 높이기 위해 의도적으로 계산 속도가 느려야 하기 때문입니다.
또한 사용자마다 고유한 salt를 적용하여 동일한 비밀번호도 서로 다른 해시값이 생성되도록 해야 합니다. Spring Security에서는 PasswordEncoder를 통해 이를 구현할 수 있으며, 일반적으로 BCryptPasswordEncoder 등을 사용합니다. 로그인할 때는 비밀번호를 복호화하지 않고, 입력받은 비밀번호와 저장된 해시를 matches()로 비교합니다.
레인보우 테이블
- 원본-다이제스트 쌍을 미리 계산하여 여러개 저장해둔 테이블
솔트
- 비밀번호에 랜덤한 값을 더한 후 해싱
키 스트레칭
- 해싱의 연산속도를 의도적으로 느리게 만들기
Spring 표준은 BCrypt이다. (확인필요)
해싱 + 솔트 + 키 스트레칭을 지원하는 BCrypt를 주로 사용한다.
Salt는 비밀로 보관해야 하나요?
Salt는 비밀번호마다 다르게 생성하는 임의의 값으로, 같은 비밀번호가 같은 해시를 만들지 않도록 하는 것이 목적입니다. 비밀일 필요는 없으므로 일반적으로 해시 결과와 함께 저장하지만, 충분히 무작위이고 사용자마다 고유해야 합니다.
Pepper는 Salt와 무엇이 다른가요?
Pepper는 여러 비밀번호에 공통으로 추가하는 서버 측 비밀값입니다. 데이터베이스와 분리된 Secret Manager나 환경에 보관하여 DB만 유출되었을 때 공격 비용을 높일 수 있지만, 유출이나 교체에 대비한 키 관리 전략이 필요합니다.
비밀번호 해시 알고리즘의 비용 설정은 어떻게 관리하나요?
서버가 감당할 수 있는 범위에서 로그인 응답 시간이 지나치게 느려지지 않도록 비용 값을 측정하여 정합니다. 하드웨어 성능과 공격 능력이 변하므로 주기적으로 비용을 높이고, 로그인 성공 시 기존 해시가 낮은 비용이나 오래된 알고리즘을 사용한다면 새 설정으로 다시 해시할 수 있습니다.