kok202
Security OAuth2 강의 정리

2019. 7. 13. 04:09[정리] 기능별 개념 정리/Security + OAuth

강의 출처

추가 추천 강의

 

OAuth

실제 유저정보를 가지고 있는 페이스북, 구글에 인증을 위임하는 것

Owner (사용자)

Client (페이스북 인증을 사용하는 웹)

Provider (페이스북, 구글) 

 

OAuth2

Owner (사용자)

Client (페이스북 인증을 사용하는 웹)

Resource Server (보통 클라이언트나 Authorization 둘 중에 하나에 들어감)

Authorization Server (페이스북 인증 서버)

 

Grant type

OAuth 토큰을 받을 때 인증하는 방법이 총 4가지가 있다.

(타입에 따라서 주고받는 프로세스가 다르다.)

1. 서버에서 사용하는 방법 : Authorization code 

2. 모바일에서 사용하는 방법 : Implicit

3. Resource owner password credential

4. Client credential

 

 

 

 

 

샘플 예시 

Security 관련 설정 입력

 

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    @Resource(name="userService")
    private UserDetailService userDetailService
    
    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }
    
    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
    
    @Bean
    public PasswordEncoder encoder(){
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder
            .userDetailService(userDetailService)
            .passwordEncoder(encoder());
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 리소스 이외의 것들에대한 인증 처리 정보를 설정을 하는 곳
        http
            .cors().and()
            .csrf().disable() // 폼 입력할 때, 폼이 내가 제공하는 웹 서버에서 나온 값인지 확인하는 것 
            .anonymous().disable()
            .authorizeRequests()
                .antMatchers("/api-docs/**").permitAll();
    }
    
    @Bean
    public CorsConfiugrationSource corsConfigurationSource(){
        // Cros origin configuration 소스 제공
        CorsConfiguration corsConfiguration. = new CorsConfiguration();
        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return urlBasedCorsConfigurationSource;
    }
}

Resource Server (Rest API 인증을 처리해주는 곳)

// 실제 어플리케이션에 있는 Rest API 인증을 처리해주는 곳
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("resource_id").stateless(false);
    }
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        // 리소스에 대한 인증 처리 정보를 설정을 하는 곳
        http
            .anonymous().disable() // 익명 사용자는 거절한다.
            .authorizeRequests() // 인증이 필요한 요청을 나열하겠다.
                .antMatchers("/users/**").authenticated() // /user/~~ 경로로 들어오는 경우 인증이 필요하다.
                .and()
            .exceptionHandling() // 인증이 되지 않은 경우
            	.accessDeniedHandler(new OAuth2AccessDeniedHandler()); // 이 핸들러를 사용하라
    }
}

Authorization Server (ex. 페이스북 인증 서버)

// 토큰 발급
// 토큰 리프레시
// OAuth 로 거치는 과정을 여기서 처리
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{
    // 발급하는 OAuth 토큰들을 저장하는 저장소
    @Autowired
    private TokenStore tokenStore;
    
    // 실제로 인증하는 부분
    @Autowired
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            .tokenStore(tokenStore)
            .authenticationManager(authenticationManager);
    }
    
    @Override
    public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
        // authenticationManager 가 여기에 적힌 Client 와 secret 을 보고 인증을 처리한다.
        configurer.inMemory()
            .withClient("myClient")
            .secret(passwordEncoder.encode("myClientPassword"))
            .authorizedGrantTypes(
                "password", 
                "authorization_code", 
                "refresh_token")
            .scopes(
                "read",
                "write",
                "trust")
            .accessTokenValiditySeconds(1 * 60 * 60)
            .refreshTokenValiditySeconds(6 * 60 * 60);
    }
}

// 주요 포인트
// TokenStore를 인메모리가 아니라 DB 를 사용하는 TokenStore 로 바꿔야한다.
// TokenStore에 자동으로 client, secret 을 생성해서 여러 앱들을 등록하는 방법을 제공해야한다.

 

userController, userService, userRepository, userEntity 구현은 생략한다.

userService에서 Repository로 save 할 때 password 는 passwordEncoder 를 반드시 거치도록 구현해야한다.

userService는 UserDetailService 의 하위 클래스이여야한다.

 

 

 

 

 

1. Access token 받는 방법

curl -XPOST https://localhost:8080/oauth/token \
     -H "Authorization: Basic 'echo -n myClient:myClientPassword | base64'" \
     -H 'application/x-www-form-urlencoded' \
     --data-urlencode "username=kok202" \ 
     --data-urlencode "password=123456" \ 
     --data-urlencode "grant_type=password"

이 요청을 받으면 AuthorizationServer 가 처리한다.

이 요청의 결과로 access_token 70f1jhfsdf-ds13x-v1sd-1vw5e052v2s1을 받았다고 치자.

 

 

 

 

2. Token 으로 인증이 필요한 API 에 접근하기

curl -XPUT https://localhost:8080/users/1 \
     -H 'Authorization: Bearer 70f1jhfsdf-ds13x-v1sd-1vw5e052v2s1' \
     -H 'Content-Type: application/json' \
     -d '{"age"=100}'

/user/** 의 요청을 받으면 ResourceServer 가 처리한다.

 

 

 

 

CORS : 어떤 도메인이 이 서버의 리소스에 접근할 수 있는가.

브라우저 레벨에서 API 호출시 요청이 두번 나간다고 보면된다.

1. Preflight API call : 서버에게 내가 가진 이 도메인으로 특정 API 의 특정 Method 를 호출 가능한지 물어본다.

2. Real API call : 서버가 호출 가능하다고 말하면 실제로 API call 이 나간다 아니라면 CORS 에러를 내린다.

 

CSRF : 사이트간 요청 위조 공격

나의 서비스는 서비스 안에서 글쓰기를 하면 이를 맞춤법 검사하여 페이스북에 글을 대신 올려주는 서비스라고 가정하자.

나의 서비스는 페이스북 연동이 되어있다.

나의 서비스에 사용자가 페이스북을 통해 가입하려한다.

나의 서비스는 사용자에게 페이스북의 글쓰기 권한을 허가 해달라고 한다.

그렇담 앞으로 받는 Access token 은 페이스북에 글쓰기가 가능한 토큰이 된다.

사용자가 페이스북을 통해 로그인 하여 나의 서비스에 엑세스 토큰을 받았다.

브라우저에서는 이를 쿠키나 세션에 저장하고 있다.

이 때 공격자가 나의 서비스와 완전히 똑같은 페이지를 만들고 히든 태그로 악성 광고글을 쓰도록 하는 코드를 작성해놨다.

사용자가 확인 버튼을 누르면 악성광고가 함께 페이스북에 글쓰기 된다.

 

'[정리] 기능별 개념 정리 > Security + OAuth' 카테고리의 다른 글

OAuth 그림 요약  (0) 2019.08.23
스프링 시큐리티 주요 인터페이스  (0) 2019.08.03
스프링 시큐리티 개요  (0) 2019.08.03
Security 기초 (2)  (0) 2019.07.13
Security 기초 (1)  (0) 2019.07.13