SecurityFilterChain:
import org.springframework.security.web.SecurityFilterChain;
。Spring Security에서 제공하는 보안 filter 모음 역할의Interface.
(Authentication Filter,Authorization Filter,CORS Filter,CSRF Filter,ExceptionTranslation Filter등)
▶@Configuration을 통해Spring Bean으로 등록하여필터를 설정
。Web Security Configuration를 정의하는@Configuration Class를 통해Spring Bean으로 등록 시Delegating Filter Proxy를 통해Servlet Filter Chain사이에서Filter로서의존성 주입되어 기능
。Spring Security의 핵심이 되는 기능을 제공하여 사용자에게 적절한Authentication과Authorization이 부여
。SecurityFilterChain의구현체로서HttpSecurity가 존재
▶FilterChain을 통해 설정 후HttpSecurity객체.build()로 생성된HttpSecurity instance를 반환하여SecurityFilterChain으로서Spring Bean으로 등록
▶ 이후@EnableWebSecurity에 의해 해당Spring Bean이 활성화
。Filter Chain의 경우Filter에 따른검증이 순차적으로 적용.
1.CORS,CSRF등의 Filter :
。기본필터
2.Authentication Filter:
。적절한자격증명보유 여부 Filtering
3.Authorization Filter:
。접근하려는자원에 적절한접근권한이 있는지 Filtering
Security Filter Chain핵심적인 기능
。기본적으로Controller에Mapping된 모든URL을 대상으로보호를 수행
▶ 해당URL에 대해요청시 사용자에게인증정보를 요구
。 승인되지 않은요청에 대해서는비허용
▶URL로Http Request가 전송되었을때,SecurityFilterChain의필터를 통해 사용자가인증( Authenticate )되지 않은 경우, 만약form-based login이 활성화 되었을때Login Form을 표시
HttpSecurity
。특정HTTP Request에 대한웹보안의Configuration을 설정하는 역할의SecurityFilterChain 인터페이스 구현체
▶Default로서 모든Http Request에 대해 적용
。@Bean 메서드의매개변수로의존성주입되며, 해당메서드에서필터 설정을 수행한 이후SpringFilterChain으로 반환함으로써Spring Bean으로 등록
▶ 이후 해당설정을 기반으로요청 / 응답시인증 / 인가를 수행
。Resource(URL)의접근 권한을 설정
▶ 특정Resource의접근 권한또는특정 권한을 가진사용자의접근 권한을 설정
。Spring Security의 각종Configuration을 수행.
▶@Configuration Class의@Bean Method에서HttpSecurity객체에서Filter Chain을 구현 후HttpSecurity객체.build()로HttpSecurity객체를 생성 및SecurityFilterChain객체로서 return하여Spring Bean으로 등록함으로써Spring Security의 설정을 반영.
。Spring Security 6.x부터는메서드 체이닝이 아닌,람다식기반 설정방식 권장
httpsecurity객체.authorizeHttpRequest(람다식):
。Spring Framework에 전달되는HttpRequest에 대한접근권한을 설정하는 Method.
▶HttpRequest을 특정 패턴에 따라서filtering하고접근권한을 부여
。HttpSecurity객체에 대하여 input된 인증이 된 모든HttpRequest에 대하여 승인처리 설정.
▶ 구현하지 않는 경우, 모든HTTP Request에 대해서 거절
。콜백함수의매개변수로auth를 전달하며, 해당 변수를 통해어플리케이션의API 호출에 따른 모든HttpRequest에 대한접근권한설정이 가능.
접근권한설정 시 먼저 설정한엔드포인트에 대한접근권한이 우선적으로 적용된다..requestMatchers(HttpMethod.POST, "/api/v1/npcs/read").permitAll() .requestMatchers(HttpMethod.POST, "/api/v1/npcs/**").authenticated()▶ 다음처럼 설정 시
/api/v1/npcs/read 엔드포인트에 대해모든 사용자가 접근 가능하고, 이하 나머지엔드포인트는인증된 사용자만 접근가능하도록 설정됨
HTTP Request의접근권한설정 Method (Global Security)
。HttpSecurity.authorizeHttpRequests(람다식)에서람다식이 전달하는인자( =auth)를 통해 설정.
▶ 구현하지 않는 경우, 모든HTTP Request에 대해서 거절
인가를검증할 대상URL 패턴지정
。requestMatchers(),anyRequest()
auth.requestMatchers( HTTPMethod.메소드명 , "/URL Pattern1" , "/URL Pattern2", ...)
。HTTP Request의 특정URL pattern과HTTP Method에 대해서접근 권한을 설정 시 사용하는메서드
▶ 나머지HTTP Request에 대해서는auth.anyRequest()에서 정의
。URL Pattern을 정의한String[] 인자도 받을 수 있다.
。기존antMatchers()처럼URL 전체를 모두일치해야 허용하는 방식에서URL Pattern만일치해야 허용하는 방식으로 개선
ex)auth.requestMatchers(HttpMethod.OPTIONS, "/login/**").permitAll():
▶/login이후의URL Pattern의OPTIONS HTTP Method방식의HTTP Request는 모두 허용.
auth.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
。CORS 관련 설정으로서,Preflight Request이 전달되어인가 검증을 수행하는 경우 모두 허용하도록 설정
auth.anyRequest():
。따로 접근권한을 설정한 특정HTTP Request이외의 모든HTTP Request에 대한 접근권한을 정의하는메서드
▶.anyRequest()는.requestMatchers("/**")처럼 동작http.authorizeHttpRequests( auth->auth.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() .anyRequest().authenticated() )▶
auth.requestMatchers에서 정의한HTTP Request이외의 모든HTTP Request에 대해 인증된 사용자만 접근가능하도록 설정.
인가 검증 메서드
。requestMatchers(), anyRequest()를 통해 설정된 대상을검증수행
auth.anonymous()
。인증이 되지 않은익명 사용자만 접속할 수 있도록 설정하는인가 검사 메서드
▶인증된 사람은 차단
。보통로그인 페이지에서 작성 ( 로그인 한 사람이 또 로그인 하면 안되므로 )http.authorizeHttpRequests(auth -> auth .requestMatchers("/login/**").anonymous() )▶
/login/**의URL Pattern을 가진요청중인증되지 않은 사용자만 접근 가능.
auth.hasRole("역할명")
。해당URL 패턴에 특정Role을 가진 사용자만 접근할 수 있도록 제한하는인가 검사 메서드
▶역할명만 입력 시GrantedAuthority내부의ROLE_역할명과 자동으로매칭http.authorizeHttpRequests(auth -> auth .requestMatchers("/admin/**").hasRole("ADMIN") )▶
/admin/**의URL Pattern을 가진요청중"ROLE_ADMIN"을 가진사용자만 접근 가능.
auth.hasAnyRole("역할명1", "역할명2", ... )
。해당URL 패턴에 정의된 여러 개의Role중 해당하는역할을 가진사용자만 접근 할 수 있도록 제한하는인가 검사 메서드
auth.hasAuthority("ROLE_역할명")
。해당URL 패턴에 특정Role을 가진 사용자만 접근할 수 있도록 제한하는hasRole()과 동일 역할의인가 검사 메서드
▶hasRole()과 달리"ROLE_역할명"을 모두 입력하여GrantedAuthority내부의ROLE_역할명과매칭
auth.hasAnyAuthority("ROLE_역할명1", "ROLE_역할명2", ...)
。해당URL 패턴에 정의된 여러 개의Role중 해당하는역할을 가진사용자만 접근 할 수 있도록 제한하는hasAnyRole()과 동일한 역할의인가 검사 메서드
▶"ROLE_역할명"을 모두 입력
auth.authenticated()
。해당URL 패턴에 대해Authenticated된Client만 접근가능하도록 설정하는인가 검사 메서드
▶auth.anonymous()와 반대
auth.permitAll()
。해당URL 패턴에 대해인증되거나, 되지 않거나 상관없이 모든HTTP Request에 대해 허용.
▶ 따로접근권한을 설정한 특정HTTP Request가 없는 경우보안없이 개방하는것과 같음.
auth.denyAll()
。해당URL 패턴에 대해 모든HTTP Request에 대해 차단하는인가검사 메서드
。주로인가검증 메서드 설정에서마지막에 설정하여, 위에서 정의한접근 가능한 URL외 모든URL에 접근 시차단하여 내부자원을 보호auth .requestMatchers("/sign-up") .permitAll() .requestMatchers("/login-page") .anonymous() .requestMatchers("/user/**") .hasAuthority("USER") .anyRequest() .denyAll();▶
/sign-up,/login-page,/user/**외URL로 접근하는 모든요청을 차단
HttpSecurity객체.httpBasic(Customizer.withDefaults())
。Spring Security에서HTTP Basic Authentication을 활성화하는 Method.
▶ Clent의 ID와 PW를HTTP Request의Authorization Header에 포함하여 인증하는 방식.
。Authorization Header요구 시Basic Authentication도출.
Basic Authentication: 웹브라우저의 인증 팝업으로Authorization Header의ID/PW입력 기능 제공.
。HTTP Basic:Header에 ID와 PW를 포함 및Base64로 인코딩하여HTTP Authorization Header에 포함하여 Server로 전송.
HttpSecurity객체.headers(콜백함수)
。HttpRequest에 대한Http Response Header를 설정하는 method.
▶Spring Security는 보안 관련HTTP Header를 자동으로 추가하지만,
필요에 따라 추가하거나 비활성화 설정 가능.
。람다식의 매개변수로서Http header객체가 전달http.headers(header -> header.frameOptions(frameOptions->frameOptions.disable()));
header객체.frameOptions(람다식):
。HTTP Header을 통해Web Application의iframe보안정책을 설정하는 기능.
▶ 주로Clickjacking공격을 방지하는 역할을 수행.
。frameOption객체가람다식 인자로 전달됨
<iframe>:inline frame
。HTML에서 다른 웹페이지나 문서를 현재 페이지 내에 삽입할 때 사용하는 태그.
▶ 외부 웹사이트, 동영상, 지도, 문서등을 포함 가능
frameoption객체.disable():
。Http Header의FrameOption을 비활성화.
▶ 모든iframe을 허용하여iframe기반 UI ( ex.h2-console)을 사용 시 필요하지만 보안위험이 존재하므로, 신뢰할 수 있는 경우에만 사용.
frameoption객체.sameOrigin():
。iframe을 같은 도메인에서 오는 `HTTP Request에 대해서만 허용.
▶ 동일한 도메인에서만iframe을 사용가능하고, 다른 도메인에서는 차단.
HttpSecurity객체.build():
。Configuration이 수행된HttpSecurity객체를 생성.
▶ 주로SecurityFilterChain Interface로UpCasting하여Spring Bean으로 등록
HttpSecurity객체.sessionManagement(콜백함수):
。Spring Security에서세션 관리 전략을 설정하는 Method.
。Session을 사용하지 않는Stateless방식의JWT 기반 인증과REST API 규약을 위해Session Policy에서STATELESS설정 시 활용
▶Spring Security는 기본적으로Session을 사용하므로Session이 생성되지 않도록 설정
。Session이 없는 경우 추가로CSRF Protection을 비활성화 가능
。Form Based Login등Session을 사용하는인증방식의 경우 사용하도록 설정해야한다.
。매개변수로session이 전달되며, 람다식으로session.sessionCreationPolicy(Session Policy 설정 옵션)를 통해Spring Security가 설정한Session Policy에 따라Session의 처분을 결정.httpsecurity객체.sessionManagement( session->session.sessionCreationPolicy(SessionCreationPolicy.STATELESS) )▶
Spring Security가Session을 사용하지 않도록Session Policy설정.
Session Policy설정 옵션
import org.springframework.security.config.http.SessionCreationPolicy;
SessionCreationPolicy.ALWAYS:
。항상 새로운Session을 생성하도록Session Policy설정.
SessionCreationPolicy.NEVER:
。Spring Security가Session을 생성하지 않지만, 기존Session을 사용가능하도록Session Policy설정.
SessionCreationPolicy.IF_REQUIRED:
。기본값으로서, 필요한 경우에만Session을 생성하도록Session Policy설정.
SessionCreationPolicy.STATELESS:
。Session을 사용하지 않도록Session Policy설정.
▶JSESSIONID 쿠키는 생성되지만,세션자체가 생성 되지 않고인메모리 DB에 저장되지도 않음.
。주로JWT Token을 활용하는REST APIAuthentication 구현 시 사용.
HTTPSecurity객체.oauth2Login(Customizer.withDefaults())
。Spring Security에서Oauth 2.0 로그인 기능을 활성화하는메서드
▶ 다음 설정을 끝낸 후localhost:8080/login접속 시 해당API를보호하기위해application.yml에 등록된OAuth2 Provider( ex.
。localhost:8080/logout접속 시 로그아웃을 수행.
oauth2.successHandler(AuthenticationSuccessHandler)
。Spring Security에서OAuth2 로그인성공 이후실행 동작을 직접 정의하여 등록하는Handler
▶ 주로로그인 성공이후OAuth를 통한 JWT 발급을 수행하는이벤트 핸들러를 정의 후 등록..oauth2Login(oauth2->{ oauth2.successHandler(oauth2SuccessHandler); })
Security Filter Chain구성
▶Filter를 넣어야하는 위치는 다음도식을 통해 결정
。JWT 기반 로그인 검증을 수행하는 경우Security Filter Chain의UsernamePasswordAuthenticationFilter직전에JWT 토큰검사 필터를 삽입
▶로그인이후SecurityContextHolder의Authentication 구현체에 등록 시UsernamePasswordAuthenticationFilter와DefaultLoginPageFeneratingFilter는Skip하도록 설정
▶Authentication 구현체가 등록되지 않은 경우UsernamePasswordAuthenticationFilter와DefaultLoginPageFeneratingFilter가 동작하여로그인 페이지도출
UsernamePasswordAuthenticationFilter
。사용자가ID / PW 로그인 요청을 전송 시인증을 수행하는필터
DefaultLoginPageFeneratingFilter
。기본 로그인 페이지를 자동생성하는필터
▶form Based Login시Spring Login 페이지를 자동 생성
Filter Chain내사용자 정의 필터 구현체등록하기
。 OncePerRequestFilter 상속 클래스를Security Filter Chain의Filter로서 등록하기
。주로로그인시 JWT 검증 필터, OAuth에서 JWT 검증 필터 등을 추가할 때 활용
httpSecurity객체.addFilter(필터객체)
。Security Filter Chain내 마지막에필터등록
httpSecurity객체.addFilterAt(필터객체)
。Security Filter Chain내 마지막에필터등록
httpSecurity객체.addFilterBefore(필터객체, 필터체인 내 특정필터.class)
。Security Filter Chain내특정 필터기준 직전에필터를 등록
ex ).addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
。주로UsernamePasswordAuthenticationFilter직전에JWT 검증 필터등록하여로그인 성공시 해당필터를Skip하도록 설정.
▶로그인 실패시UsernamePasswordAuthenticationFilter가 작동
httpSecurity객체.addFilterAfter(필터객체, 필터체인 내 특정필터.class)
。Security Filter Chain내특정 필터기준 직후에필터를 등록
ex ).addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)