본문 바로가기
  • 실행력이 모든걸 결정한다
Spring Series/Document

[SpringBoot] 공식 문서 요약(6) - Security, OAuth2

by 김코더 김주역 2021. 11. 27.
반응형

SpringBoot Document Review 6

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/

 

 

 

Security

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/boot-features-security.html

 

OAuth2

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/boot-features-security.html#boot-features-security-oauth2

 

 

1. Spring Security

- Spring Security가 classpath에 있다면 웹 애플리케이션은 보안 처리가 된다. 그래서 웹 애플리케이션에 URI 요청을 하면 로그인 화면이 나오는 것이고, 로그인을 완료하면 요청 처리가 이루어진다.

- 기본적인 AuthenticationManager은 하나의 유저를 가지며, 유저명은 user이다. 패스워드는 랜덤이고 애플리케이션 시작시 INFO 레벨에서 org.springframework.boot.autoconfigure.security에 의해 log로 출력된다.

Using generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35

- 유저의 이름과 패스워드는 각각 spring.security.user.name, spring.security.user.password로 지정 가능하다.

※ user의 속성 정보 : https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/api/org/springframework/boot/autoconfigure/security/SecurityProperties.User.html

- Spring Boot는 httpBasic, formLogin 중에서 무엇을 사용할 것인지를 결정하기 위해 Spring Security의 Content Negotiation 전략에 의존한다.

- 메소드 레벨의 security를 웹 애플리케이션에 추가하기 위해, 원하는 설정과 함께 @EnableGlobalMethodSecurity를 추가할 수 있다. 

※ 추가적인 메소드 정보 : https://docs.spring.io/spring-security/site/docs/5.1.8.RELEASE/reference/htmlsingle/#jc-method

 

Spring Security가 활성화 됐을 때 제공받는 기본적인 기능들

- userDetailService 혹은 ReactiveUserDetailService(Webflux) : in-memory store를 사용하고, 자동 생성된 패스워드를 가지는 단일 유저를 포함함

※ in-memory : 데이터를 하드 디스크가 아닌 메인 메모리에 모두 올리는 것

- 전체 애플리케이션에 대한 Form 기반 로그인과 HTTP 기반 Security

- DefaultAuthenticationEventPublisher : AuthenticationEventPublisher 인터페이스의 기본 구현체로, 인증 관련 Event들을 싣는 역할을 함. 정확하게 말하면 인증 관련 예외들을 Event에 매핑하여 application context를 통해 싣는 것임

※ AuthenticationEventPublisher에 대한 Bean을 추가하여 또 다른 인증 관련 Event Publisher를 제공할 수 있다.

※ 인증 관련 이벤트 모음 : https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/authentication/event/package-summary.html

예시

@Component
public class AuthenticationEventHandlers{
    @EventListener
    public void handleBadCredential(AuthenticationFailureBadCredentialsEvent event){
    	System.out.println(event.getAuthentication().getPrincipal() : "비밀번호가 틀렸습니다."); //getPrincipal() : UserDetails를 구현한 사용자 객체
    }
}

 

 

2. MVC Security

- 기본 보안 설정은 SecurityAutoConfiguration과 UserDetailsServiceAutoConfiguration에 구현되어 있다. SecurityAutoConfiguration는 웹 보안 설정을 위한 SpringBootWebSecurityConfiguration를 import하고, UserDetailsServiceAutoConfiguration는 인증 관련 설정을 해준다.

- 웹 애플리케이션의 기본 보안 설정을 완전히 바꾸고 싶다면 WebSecurityConfigurerAdapter 타입의 Bean을 추가하면 되는데, 이 작업이 UserDetailsService 설정이나 Actuator의 보안을 비활성화 시키지는 않는다.

- UserDetailsService 설정을 완전히 바꾸고 싶다면 UserDetailsService, AuthenticationProvider, AuthenticationManager 중 하나의 타입의 Bean을 추가하면 된다.

- Access 규칙들은 WebSecurityConfigurerAdapter을 추가함으로써 오버라이딩할 수 있는데, Spring Boot는 actuator endpoint와 staitc resources에 대한 Access 규칙들을 오버라이딩해서 사용할 수 있는 편리한 메소드들을 제공한다.

- EndpointRequest는 management.endpoints.web.base-path 속성에 기반한 RequestMatcher을 생성하기 위해 사용될 수 있고, PathRequest는 공통적으로 사용되는 위치에 있는 resources를 위한 RequestMatcher을 생성하기 위해 사용될 수 있다.

예시

static resources("/css/**", "/js/**", "/images/**", /webjars/**", "/**/favicon.ico")에 대한 모든 접근 허용, 로그인 및 로그인 오류 페이지에 대한 모든 접근 허용, 로그아웃 페이지에 대한 모든 접근 허용

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
    @Override
    protected void configure(HttpSecurity http) throws Exception{
    	http.authorizeRequests()
            .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
            .anyRequest().fullyAuthenticated()
            .and()
            .formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
            .and()
            .logout().permitAll();
    }
}

※ Authenticated는 로그인을 요구하는 처리이고, permitAll은 로그인을 요구하지 않는 처리이다.

 

 

3. WebFlux Security

- Spring MVC와 유사하게 spring-boot-starter-security를 추가함으로써 보안 처리를 할 수 있다.

- 기본 보안 설정은 ReactiveSecurityAutoConfiguration과 UserDetailsServiceAutoConfiguration에 구현되어 있다. ReactiveSecurityAutoConfiguration은 웹 보안 설정을 위한 WebFluxSecurityConfiguration를 import하고, UserDetailsServiceAutoConfiguration는 인증 관련 설정을 해준다.

- 웹 애플리케이션의 기본 보안 설정을 완전히 바꾸고 싶다면 WebFilterChainProxy 타입의 Bean을 추가하면 되는데, 이 작업이 UserDetailsService 설정이나 Actuator의 보안을 비활성화 시키지는 않는다.

- UserDetailsService 설정을 완전히 바꾸고 싶다면 ReactiveUserDetailsService, ReactiveAuthenticationManager들 중 하나의 타입의 Bean을 추가하면 된다.

- Access 규칙들은 SecurityWebFilterChain클래스를 직접 추가함으로써 추가할 수 있는데, Spring Boot는 actuator endpoint와 staitc resources에 대한 Access 규칙들을 오버라이딩해서 사용할 수 있는 편리한 메소드들을 제공한다.

- EndpointRequest는 management.endpoints.web.base-path 속성에 기반한 ServerWebExchangeMatcher를 생성하기 위해 사용될 수 있고, PathRequest는 공통적으로 사용되는 위치에 있는 resources를 위한 ServerWebExchangeMatcher을 생성하기 위해 사용될 수 있다.

예제

@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
	return http
		.authorizeExchange()
			.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
			.pathMatchers("/foo", "/bar").authenticated().and()
			.formLogin().and()
		.build();
}

 

 

4. OAuth2

- spring-security-oauth2-client가 classpath에 있다면, OAuth2 Client에 대한 자동설정이 이루어진다. 이 설정은 OAuth2ClientProperties클래스에 들어있는 속성들을 사용할 수 있도록 하며, 이 속성들은 Servlet과 Reactive 애플리케이션에 둘다 적용된다.

- spring.security.oauth2.client가 prefix인 여러 속성들을 이용하여, 다수의 OAuth2 client들과 provider들을 등록할 수 있다. 다음 예제는 2개의 Client와 하나의 Provider를 등록하는 예이다.

spring.security.oauth2.client.registration.my-client-1.client-id=abcd
spring.security.oauth2.client.registration.my-client-1.client-secret=password
spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope
spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-1.scope=user
spring.security.oauth2.client.registration.my-client-1.redirect-uri=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-1.client-authentication-method=basic
spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization_code

spring.security.oauth2.client.registration.my-client-2.client-id=abcd
spring.security.oauth2.client.registration.my-client-2.client-secret=password
spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope
spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-2.scope=email
spring.security.oauth2.client.registration.my-client-2.redirect-uri=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-2.client-authentication-method=basic
spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code

spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=http://my-auth-server/oauth/authorize
spring.security.oauth2.client.provider.my-oauth-provider.token-uri=http://my-auth-server/oauth/token
spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=http://my-auth-server/userinfo
spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header
spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=http://my-auth-server/token_keys
spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name

- 기본적으로 Spring Security의 OAuth2LoginAuthenticationFilter은 오직 "/login/oauth2/code/*"와 매칭되는 URL만을 처리하는데, 만약 다른 패턴을 사용하고 싶다면 redirect-uri-template을 커스터마이징할 수도 있다. 대표적으로, WebSecurityConfigurerAdapter을 사용하여 커스터마이징하는 방법이 있다.

public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			.authorizeRequests()
				.anyRequest().authenticated()
				.and()
			.oauth2Login()
				.redirectionEndpoint()
					.baseUri("/custom-callback");
	}
}

- 최근에는 OpenID Connect에 대한 설정도 제공해준다.

 

OAuth2 Client를 일반적인 Provider들에 등록하기

- Google, Github, Facebook, Okta와 같은 일반적인 OAuth2와 OpenID provider들에게 각각 기본값 집합들이 제공된다. 이 provider들을 커스터마이징할 필요가 없다면, 아래 예시와 같이 기본값들을 추론하는 부분에 provider속성을 설정할 수 있다. 만약 client ID가 기본적으로 제공된 provider의 client ID와 매칭된다면, Spring Boot는 잘 추론할 수 있을 것이다. 아래 예시는 Google provider을 사용하는 경우이다.

spring.security.oauth2.client.registration.my-client.client-id=abcd
spring.security.oauth2.client.registration.my-client.client-secret=password
spring.security.oauth2.client.registration.my-client.provider=google

spring.security.oauth2.client.registration.google.client-id=abcd
spring.security.oauth2.client.registration.google.client-secret=password

 

 

5. Actuator Security

- 보안상의 목적으로 /health, /info를 제외한 모든 actuator들은 기본적으로 비활성화된다.

- management.endpoints.web.exposure.include 속성은 actuator들을 활성화하기 위해 사용될 수 있으며, 이 속성을 설정하기 전에는 노출된 actuator들이 민감한 정보를 포함하지 않도록 해야 한다.

- Spring Security가 classpath에 있고, 별도의 WebSecurityConfigurerAdapter가 없다면 actuator들은 Spring Boot 자동 설정에 의해 보안이 적용된다. 만약 커스텀 WebSecurityConfigurerAdapter을 정의했다면, Spring Boot 자동 설정은 적용되지 않기 때문에 개발자가 따로 actuator 접근 규칙의 모든 제어를 담당해야 한다. 

 

CSRF(Cross Site Request Forgery) 보호

CSRF 공격이란, 사용자의 의지와 무관하게 공격자가 서버에 변조된 요청을 보내는 공격 방식이다.

CSRF Token이란, 서버에 들어온 요청이 실제 서버에서 허용한 요청이 맞는지 확인하기 위한 토큰이다.

서버에서는 View 페이지를 발행할 때 랜덤으로 생성된 Token을 같이 준 뒤 사용자 세션에 저장해둔다. 그리고 사용자가 서버에 작업을 요청할 때 페이지에 Hidden으로 숨어있는 Token 값이 같이 서버로 전송되는데, 서버에서는 이 Token 값이 세션에 저장된 값과 일치하는지 확인하여 해당 요청이 위조된게 아니라는 것을 확인한다. 일치 여부를 확인한 Token은 바로 폐기하고 새로운 뷰 페이지를 발행할 때마다 새로 생성한다.

※ 정보 출처 : https://codevang.tistory.com/282

 

- Spring Boot는 Spring Security의 기본값에 의존하기 때문에, 기본적으로 CSRF 보호 기능이 켜져있다. 이 말은 기본 security 설정이 사용중이라면, POST, PUT 혹은 DELETE 요청을 요구하는 actuator endpoints들은 403 forbidden 에러가 발생할 것이라는 뜻이다.

- non-browser 클라이언트들에 의해 사용되는 서비스의 경우에는, CSRF 보호를 비활성화하는 것을 권장한다.

 

 

반응형

댓글