스프링 시큐리티 공식문서를 참고해서 정리해본 시큐리티 관련 내용
인증(비밀번호)
Password Storage :: Spring Security
스프링 시큐리티에 있는 passwordEncoder인터페이스는 비밀번호의 단방향 변환의 기능을 갖고있다.
유저데이터의 비밀번호 보안 역사
제일 처음 유저데이터의 정보는 평문으로 저장했었다. why? : 유저데이터는 DB에 들어가있으니 DB 어드민이 털리지 않는 이상 문제 없을거라 판단.
이후 악의적인 사용자는 SQL Injection같은 공격을 통해 사용자 이름과 비밀번호가 포함된 데이터를 얻을 방법을 찾아냈고, 이러한 방식으로 데이터의 보안이 뚫리기 시작하자 새로운 암호화 방식인 단방향해시 SHA-256을 통해 정보를 해시화하고 해당 해시를 저장하도록 권장되었다.
이러한 방식은 사용자가 인증을 시도하면 해시된 비밀번호가 입력한 비밀번호의 해시와 비교해서 일치한다면 로그인이 되는데, 이러한 암호화를 뚫기 위해 Rainbow Tables라는 조회 테이블이 생겼고 해당 테이블은 비밀번호의 입력값을 미리 해시화해서 테이블에 넣어두고 역인코딩으로 값을 받아온다
때문에 해당 방식으로도 값을 뚫리게 되고 이를 막기위해 개발자는 소금을 치기 시작한다(특정하지 않은 랜덤한 문자열을 해시문에 포함시킴) 이러한 형식으로 Rainbow Tables 조회테이블에 당하지 않는게 현재 상황이다.
이러한 보안상의 이슈를 스프링 시큐리티에서 자체적으로 지원을 해주는데, 추가로 생각해야 하는 것이 비밀번호 검증을 할 때 의도적으로 리소스(CPU, 메모리, 등등)를 많이 사용하는것이다.
비밀번호를 확인하는데 1초의 지연시간을 주는 이유는 공격자가 암호를 무차별확인을 하면서 해독할 수 있는 시간을 주지 않는것이 주요 목표이다.
때문에 스프링 시큐리티 인증 설정을 할 때 해당 부분을 잘 신경써서 같이 구현해야 할 것이다.
또 위와같이 데이터를 찾는데 시간을 주지않기 위해 장기자격증명이 아닌 단기자격증명으로 지속체크를 하는 것이 좋을 것이다.
장기자격증명 → 사용자 이름 및 비밀번호
단기자격증명 → 세션, Oauth토큰
User.UserBuilder users = User.withDefaultPasswordEncoder();
or
UserBuilder users = User.withDefaultPasswordEncoder();
UserDetails user = users
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = users
.username("admin")
.password("password")
.roles("USER","ADMIN")
.build();
기본 Deprecated되어있는데 이유는 메모리와 컴파일된 소스코드에 비밀번호가 노출되어있기 때문에 해당 비밀번호를 외부에서 해시를 해야 안전해짐
때문에 사용x
위의 사진은 스프링 시큐리티 클래스의 User클래스 내부 코드중 일부인데 이런식으로 생성자를 통해서도 가입이 가능한듯?
패스워드 인코더는 자바 자체에서 지원하는데,
- bcrypt
- ldap
- MD4
- MD5
- noop
- pbkdf2
- scrypt
- SHA-1
- SHA-256
- sha256
그냥 이런게 있구나하고 인지하면될듯
주요한 것은 스프링시큐리티에 있는
- BCryptPasswordEncoder
- Argon2PasswordEncoder
- Pbkdf2PasswordEncoder
- SCryptPasswordEncoder
이 네가지 인코더인데 상황이나 여건에 따라서 네가지중 하나를 사용하면서 비밀번호를 확인하는 시간을 약 1초가 걸리도록 지연하게 하는것이 안전하다
이유는 레인보우테이블 공격을 통해 무차별 인코딩확인을 막기 위해.
PasswordEncoder 또한 지원을 하긴 하는데 현재는 안전하지 않다는 것이 검증되었다. 지원하는 이유는 이전 버전에서 만들어진 코드는 해당 인코더를 사용했었기 때문에
만들어진 비밀번호를 변경하는 방법은
http
.passwordManagement(Customizer.withDefaults())
http
.passwordManagement((management) -> management
.changePasswordPage("/update-password")
)
위의 방식으로 사용하면 될 것 같음
추가로
약관에 동의하더라도 개인정보는 평문으로 저장하면 안된다
이 때문에 스프링 시큐리티의 도움을 반드시 받는것이 중요할 것 같다.
혹시나 서비스할 때 항상 잊지않고 생각해야하는 부분
비밀번호 해시 관련 지식참조 사이트
'호기심 천국 > Spring' 카테고리의 다른 글
데이터베이스 정렬 vs 자바 정렬 (0) | 2023.09.12 |
---|---|
스프링부트 final로 클래스 생성자주입 (0) | 2023.07.27 |