보안 감사자가 데이터베이스에 저장된 인코딩된 비밀번호를 확인했을 때, 서로 다른 사용자가 같은 해시 값을 가지고 있다면 이는 심각한 보안 결함으로 이어질 수 있다. 비록 암호화 알고리즘을 사용하더라도 동일한 입력값에 대해 항상 동일한 결과가 나온다면, 공격자는 무지개 테이블(rainbow table)과 같은 기법을 통해 원래의 비밀번호를 유추해낼 수 있기 때문이다. 이러한 문제를 해결하기 위해 도입하는 개념이 바로 솔트이다.
![]()
1. 솔트(Salt)의 개념과 역할
솔트는 암호화된 비밀번호에 보안 레이어를 추가하기 위해 사용하는 임의의 텍스트를 의미한다.
-
동작 원리: 비밀번호가 해시 함수에 전달되기 전에 이 솔트 값을 결합함으로써, 설령 비밀번호가 같더라도 최종적으로 저장되는 해시 값은 사용자마다 다르게 생성된다.
-
방어 효과: 결과적으로 솔트는 알려진 입력값을 통해 결과를 예측하려는 시도를 효과적으로 방어하며 비밀번호 보안을 한층 강화한다.
2. 스프링 시큐리티의 솔트 메커니즘
스프링 시큐리티에서는 SaltSource 인터페이스를 통해 이러한 솔트 메커니즘을 제공한다.
-
시스템 전역 솔트: 모든 사용자에게 동일한 고정 텍스트를 적용하는 방식이지만, 이는 보안상 권장되지 않는다.
-
사용자 고유 솔트: 사용자마다 고유한 정보를 솔트로 사용하는 방식이 더 안전하며, 흔히 사용자의 계정명(username)을 솔트 값으로 활용하는 방식이 널리 사용된다.
3. 솔트 적용 및 설정 방법
실제 애플리케이션에 솔트를 적용하기 위해서는 설정 파일에서 비밀번호 인코더와 솔트 소스를 연결하는 과정이 필요하다.
-
설정 연결: 이를 통해 시스템은 사용자가 입력한 비밀번호와 저장된 솔트 값을 결합하여 인증 과정을 수행하게 된다.
-
로직 수정: 또한, 기존의 사용자 정보를 처리하는 빈(bean)이나 데이터베이스 접근 로직에서도 솔트 값을 적절히 다울 수 있도록 수정이 이루어져야 한다.
4. 고도화된 보안: 무작위 솔트 저장 방식
더욱 강력한 보안을 원한다면 단순히 사용자의 계정명을 솔트로 쓰는 대신, 각 사용자마다 무작위로 생성된 별도의 솔트 값을 데이터베이스에 저장하는 방식을 고려해 볼 수 있다.
-
스키마 확장: 이를 위해 데이터베이스 스키마에 솔트 전용 컬럼을 추가한다.
-
UserDetails 확장: 사용자 상세 정보를 담는 객체인 UserDetails를 확장하여 해당 솔트 값을 포함하도록 구현해야 한다.
-
커스텀 조회 로직: 이 과정에서 사용자 정보 조회 기능을 담당하는 클래스를 커스터마이징하여 데이터베이스로부터 비밀번호와 솔트 값을 함께 불러오도록 설정한다.
이렇게 솔트를 도입하면 공격자가 데이터베이스를 탈취하더라도 각 사용자마다 다른 솔트가 적용되어 있어 비밀번호를 해독하는 데 막대한 비용과 시간이 소요되게 된다. 스프링 시큐리티가 제공하는 다양한 인터페이스와 클래스를 적절히 확장하고 활용함으로써, 우리는 보다 견고하고 안전한 인증 시스템을 구축할 수 있다.