Spring_Security_03

Jaewoo Back·2024년 7월 11일
0

Spring Security공부

목록 보기
3/13
post-thumbnail

스프링 보안

Spring Security는 일반적인 공격에 대한 인증, 권한 부여 및 보호를 제공하는 프레임워크입니다.

명령형 및 반응형 애플리케이션 모두 보호하기 위한 최고 수준의 지원을 제공하는
Spring기반 애플리케이션을 보호하기위한 표준이다.

필수 구성 요소

  • java 8 이상의 런타임 환경

Spring Security는 자체 포함 방식으로 작동하는 것이 목표이다.
특히 특수 JAAS(Java Authentication and Authorization Service) 정책 파일을 구성하거나 Spring Security를 공통 클래스 경로 위치에 배치할 필요가 없다.

Spring Security 6.3의 새로운기능

공식홈페이지 새로운 기능 확인하기

기능

Spring Security는 인증, 권한 부여 및 일반적인 악용에 대한 보호에 대한 포괄적인 지원을 제공합니다.

인증

인증 : 특정 리소스에 액세스하려는 사용자의 ID를 확인하는 방법이다.

비밀번호 저장

비밀번호 저장
처음에는 암호가 일반 텍스트로 저장되었습니다. 암호가 안전하다고 가정했으나, 악의적인 사용자는 SQL 인젝션과 같은 공격을 사용하여 "데이터 덤프"를 얻을 수 있는 방법을 찾을 수 있었습니다. 보안 전문가들은 암호를 보호하기 위해 조치를 취해야했습니다.

개발자는 SHA-256rhk 같은 단방향 해시를 통해 암호를 저장하도록 권장했습니다. 사용자가 인증을 시도하면 해시된 암호가 입력한 암호의 해시와 비교됩니다. 이 시스템을 무력화하기 위해 악의적인 사용자는 레인보우 테이블이라는 조회 테이블을 만듭니다.

개발자는 레인보우 테이블의 효과를 완화하기 위해 솔트 암호를 사용하도록 권장되었습니다. 모든 사용자의 암호에 대해 임의의 바이트(솔트)가 생성됩니다. 이를 통해 고유한 해시를 생성합니다. 솔트는 사용자의 암호와 함께 일반 텍스트로 저장됩니다. 그런 다음 인증이 시도되면 해시된 암호가 저장된 솔트의 해시 및 입력한 암호와 비교됩니다.

현대에는 암호화 해시(예: SHA-256)가 더 이상 안전하지 않다는 것을 알고 있습니다. 그 이유는 최신 하드웨어를 사용하면 초당 수십억 개의 해시 계산을 수행 할 수 있기 때문입니다. 즉, 각 암호를 개별적으로 쉽게 해독할 수 있습니다.

결론
개발자는 이제 적응형 단방향 함수를 활용하여 암호를 저장하는 것이 좋습니다. 적응형 단방향 함수는 사용한 암호 유효성 검사는 의도적으로 리소스를 많이 사용합니다.
시스템에서 암호를 확인하는 데 약 1초가 걸리도록 "작업요소"를 지정합니다. 이 절충안은 공격자가 암호를 해독하기 어렵게 만드는 것이지만 자체 시스템에 과도한 부담을 주거나 사용자를 짜증나게 할 정도로 비용이 많이 들지 않습니다.

사용해야하는 적응형 단방향 함수의 예로는 bcrypt, PBKDF2, scrypt 및 argon2가 있습니다.

리소스를 많이 사용하기 때문에 모든 요청에 대해 유효성 검사하면 애플리케이션의 성능이 크게 저하될 수 있습니다. 장기 자격증명을 단기 자격 증명(세션, OAuth 토큰 등)으로 교환하는 것이 좋습니다.


BCryptPassword 인코더

암호 트래킹에 대한 저항력을 높이기 위해 bcrypt는 의도적으로 느립니다.
기본 구현은 javadoc에 언급된대로 강도 10을 사용합니다.

// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));

아르곤2패스워드인코더

// Create an encoder with all the defaults
Argon2PasswordEncoder encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));

Pbkdf2암호 인코더

이 알고리즘은 FIPS 인증이 필요한 경우에 적합합니다.

// Create an encoder with all the defaults
Pbkdf2PasswordEncoder encoder = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));

SCryptPassword인코더


// Create an encoder with all the defaults
SCryptPasswordEncoder encoder = SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));

다른 sPasswordEncoder

이전 버전과의 호환성을 위해 전적으로 존재하는 다른 구현이 많이 있습니다. 더 이상 안전하지 않은 것으로 간주됨을 나타내기 위해 모두 더 이상 사용되지 않습니다. 그러나 기존 레거시 시스템을 마이그레이션하기 어렵기 때문에 제거할 계획은 없습니다.PasswordEncoder

비밀번호 구성 변경

사용자가 암호를 지정할 수 있는 대부분의 응용 프로그램에는 해당 암호를 업데이트하는 기능도 필요합니다. 비밀번호 변경을 위한 엔드포인트를 제공할 수 있도록 Spring Securiy를 구성할 수 있습니다.
예를 들어 애플리케이션의 암호 변경 엔드 포인트가 /change-password인 경우 다음과 같이 구성합니다.

http
   .passwordManagement(Customizer.withDefaults())

passwordManager가 Spring Security로 이동하면 엔드포인트를 리디렉션합니다.

또는 끝점이 아닌 경우 다음과 같이 지정할 수도 있습니다.

http
   .passwordManagement((management) -> management
       .changePasswordPage("/update-password")
   )

손상된 비밀번호 확인

Spring Security는 CompromisedPasswordChecker 인터페이스의 HaveIBeenPwnedRestApiPasswordChecker 구현을 통해 Have I Been Pwned API와의 통합을 제공합니다.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
   http
       .authorizeHttpRequests(authorize -> authorize
           .anyRequest().authenticated()
       )
       .formLogin(withDefaults())
       .httpBasic(withDefaults());
   return http.build();
}

@Bean
public CompromisedPasswordChecker compromisedPasswordChecker() {
   return new HaveIBeenPwnedRestApiPasswordChecker();
}

이렇게 하면 취약한 암호를 사용하여 HTTP Basic 또는 Form Login을 통해 인증을 시도할 때 401 응답 상태 코드를 받게 됩니다.
그러나 이 경우 사용자가 올바른 암호를 제공했지만 여전히 로그인할 수 없기에 약간의 혼란을 일으킬 수 있습니다.

이러한 경우 사용자 에이전트를 /reset-password로 리디렉션하는 처리할 수 있습니다.


@ControllerAdvice
public class MyControllerAdvice {

   @ExceptionHandler(CompromisedPasswordException.class)
   public String handleCompromisedPasswordException(CompromisedPasswordException ex, RedirectAttributes attributes) {
       attributes.addFlashAttribute("error", ex.message);
       return "redirect:/reset-password";
   }

}
profile
https://blog.naver.com/jaewoo2_25

0개의 댓글