[Spring Security] OAuth 2.0 개념과 동작

HJ·2023년 9월 15일
0

Spring Security

목록 보기
7/9
post-thumbnail

참고 : https://aaronparecki.com/oauth-2-simplified/
참고 : https://hudi.blog/oauth-2.0/
참고 : https://blog.naver.com/mds_datasecurity/222182943542


OAuth


OAuth 란 인터넷 사용자들이 비밀번호를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는, 접근 위임을 위한 개방형 표준입니다. ( 위키백과 )

쉽게 말하면 사용자들이 애플리케이션에 비밀번호를 제공하지 않고, 카카오나 구글 같은 곳에 저장된 자신들의 정보에 접근할 수 있는 권한을 부여할 수 있는 방법입니다.

이로 인해 외부 소셜 계정을 이용하여 회원가입이나 로그인을 간편하게 할 수 있으며, 애플리케이션이 사용자의 접근 권한을 위임받음으로써 Google 로 로그인하면 API를 통해 연동된 계정의 Google Calendar 정보를 보여주거나 수정하는 등의 작업을 할 수 있습니다.

OAuth 에는 1.0 과 2.0 이 있는데 OAuth 2.0 에 대해 알아보도록 하겠습니다.




구성 요소


[ Resource Owner ]

리소스 소유자를 의미하는데 일반적인 사용자라고 이해하면 됩니다. 리소스 소유자는 카카오나 구글에 있는 자신의 계정 일부에 대한 액세스 권한을 애플리케이션 ( 우리의 서비스 )에 부여합니다.



[ Client ]

클라이언트는 사용자가 아니라 카카오나 구글의 자원을 사용하기 위해 접근을 요청하는 서비스 혹은 애플리케이션을 의미하며, 보통 우리가 개발하려는 서비스가 이에 해당합니다.

쉽게 말해서 클라이언트는 사용자 계정에 액세스하려고 시도하는 애플리케이션이고, 그렇게 하려면 먼저 리소스 소유자( 사용자 )로부터 허가를 받아야 합니다.

여기서 주의할 점은 사용자가 client 라고 생각할 수 있는데 Authorization Server 입장에서는 우리의 서비스가 Client 이기 때문에 이러한 이름을 갖는 것입니다.



[ Authorization Server ]

리소스 소유자를 인증하고, Client 에게 권한을 부여하는 서버입니다. 리소스 소유자는 Authorization Server 에 ID, PW 를 넘겨 Authorization Code 를 발급받고, 이를 Client 에게 넘겨 Client 가 Token 을 발급받을 수 있도록 합니다.



[ Resource Server ]

카카오나 구글 처럼 리소스를 가진 서버이며, 사용자의 정보에 접근하는 데 사용되는 api 서비스를 제공합니다. Access Token 을 발급받은 Client 의 요청을 수락하고 요청에 대한 응답을 해줍니다.




권한 요청 시 필요한 파라미터


OAuth 를 사용하려면 Client 를 Resource Server 에 등록해야합니다. 이 때 Client 는 Redirect URI 를 등록해야하며, Client ID 를 발급받게 되며, 선택적으로 Client Secret 를 발급받게 됩니다.

그 후 Client 가 Authorization Server 에 인증을 요청을 할 때 Redirect URI, Cient ID, Response Type, Scope 등을 넘겨주며, Access Token 을 요청할 때는 Grant Type 을 넘겨줍니다.



[ Redirect URI ]

Redirect URL 은 사용자가 애플리케이션을 인증한 후 OAuth 2.0 서비스가 사용자에게 반환되는 위치입니다.

공격자가 인증 코드나 액세스 토큰을 가로챌 수 있는 리디렉션 공격을 방지하기 위해 이전에 서비스에 등록된 URL 로만 사용자를 리디렉션합니다.



[ Client ID, Client Secret ]

Client ID 는 애플리케이션( 서비스 )을 식별하는 식별자ID 를 의미하며, Client 가 Authorization Server 에 등록하면 발급받을 수 있습니다.

Resource Server 입장에서는 다양한 서비스가 존재하기 때문에 요청하는 Client 가 어떤 Client 인지 구별하기 위해 사용됩니다.

Client Secret 는 Client ID 에 대한 비밀번호로 절대 외부에 노출되면 안됩니다.



[ Response Type ]

Client 가 Authorization Server 로 권한 부여 동의 요청 시 포함되는 값이며, 권한 부여 방식에 따라 전달하는 값이 다릅니다.

  • Authorization Code Grant 방식 : response_type = code

  • Implicit Grant 방식 : response_type = token



[ Scope ]

Scope 는 Client 의 권한을 설정하기 위한 기능인데 Scope 를 통해서 유저 리소스에 대한 Client 의 접근 범위를 제한할 수 있습니다.

예를 들어, 우리의 서비스( Client ) 가 사용자의 구글 연락처를 받아오고 싶다면, OAuth Scope 에 연락처 스코프 문자열을 포함하여 OAuth 제공자에게 전달하면 됩니다. 만약 여러 개의 권한을 요청한다면 콤마를 통해 로그인 시, scope 를 넘겨주게 됩니다.

그 후 사용자는 Scope 에 명시된 권한을 요청하는 화면을 만나게 될 것이며, 이러한 과정을 거쳐 발급된 Access Token 은 부여된 Scope 에 해당하는 권한을 획득하게 됩니다.



[ State ]

CSRF 공격에 대비하기 위해 클라이언트가 권한서버에 요청 시 포함하는 임의의 문자열. 필수 사항은 아니지만 클라이언트가 요청 시 state를 포함 시켰다면 권한 서버는 동일한 값을 클라이언트에게 보내야 합니다.

이에 대한 예시는 아래에서 확인할 수 있습니다.



[ Grant Type ]

Client 가 Authorization Server 로 Access Token 요청 시 포함되는 값이며, 권한 부여 방식에 따라 전달하는 값이 다릅니다.

  • Authorization Code Grant 방식 : grant_type = authorization_code

  • Resource Owner Password Credentials Grant 방식 : grant_type = password

  • CLient Credentials Grant 방식 : grant_type = client_credentials




인증 종류 및 동작 과정


OAuth 2.0 에서는 Authorization Server 가 Client 에게 토큰을 부여하는 방식( 권한을 부여하는 방식 )에 따른 프로토콜을 4가지 종류로 구분하여 제공하고 있습니다.

Authorization Code Grant 와 Implicit Grant 는 인증 과정에 사용자가 개입하며, 나머지 두 방식은 사용자가 개입하지 않습니다.



[ Authorization Code Grant ]

권한 부여 승인 코드 방식이라고 하며, 토큰을 발급받기 위해 Authorization Server 가 생성해서 resource owner 에게 전달한 Authorization Code 를 전달하는 방법입니다.

간편 로그인 기능에서 사용되는 방식으로 클라이언트가 사용자를 대신하여 특정 자원에 접근을 요청할 때 사용되는 방식입니다.


  1. 리소스 소유자가 Client 에 로그인 요청을 하면, Client 는 Authorization 에 로그인 요청을 합니다. 이 때, Client ID, Redirect URI, Response Type 을 전달하는데 Response Type 에는 code 를 지정합니다.
  1. Authorization Server 는 리소스 소유자에게 로그인 페이지를 제공하고, 리소스 소유자는 이를 통해 ID, PW 를 입력합니다.

  2. 전달받은 ID, PW 가 정확하다면 Authorization Server 는 권한 부여 코드 요청 시 전달받은 Redirect URI 로 Authorization Code 를 전달합니다. 이때, Authorization Code란 Client가 Access Token을 획득하기 위해 사용하는 임시 코드이기 때문에 만료 시간이 1분에서 10분 정도로 매우 짧습니다.

  1. Client 는 전달 받은 Authorization Code 과 Client ID 를 전달하며 Authorization Server 에 Access Token 을 요청합니다.


[ Implicit Grant ]

암묵적 승인 방식이라고 하며, OAuth 2.0에서 가장 많이 사용되는 방식입니다.

위에서 알아본 권한 부여 코드의 발급 없이 바로 Acces Token 을 발급합니다. 그렇기 때문에 보안 상의 문제로 인해 만료 기간을 짧게 설정해야 한다는 특징을 가지고 있습니다.


  1. 리소스 소유자가 Client 에 로그인 요청을 하면, Client 는 Authorization 에 로그인 요청을 합니다. 이 때, Client ID, Redirect URI, Response Type 을 전달하는데 Response Type 에는 code 를 지정합니다.
  1. Authorization Server 는 리소스 소유자에게 로그인 페이지를 제공하고, 리소스 소유자는 이를 통해 ID, PW 를 입력합니다,
  1. 전달받은 ID, PW 가 정확하다면 Authorization Server 는 권한 부여 코드 요청 시 전달받은 Redirect URI 로 Access Token 을 전달합니다.


[ Resource Owner Password Credentials Grant ]

자원 소유자 자격 증명 승인 방식으로 username 과 password 로 Access Token 을 발급받는 방식입니다.

해당 방식은 권한 서버, 리소스 서버, 클라이언트가 모두 같은 시스템에 속해 있을 때만 사용할 수 있고, Client 가 타사의 외부 프로그램일 경우에는 이 방식을 적용하면 안됩니다.


  1. 리소스 소유자가 Client 에게 username, password 를 넘겨주면 Client 는 전달받은 username, password 와 함께, grant_type = password 로 지정해서 Authorization Server 에게 전달합니다

  2. Authorization Server 는 이를 확인하고 Client 에게 Access Token 을 발급합니다.



[ Client Credentials Grant ]

클라이언트 자격증명 승인 방식으로 리소스 소유자가 아닌 Client 에 대한 인가가 필요할 때 사용되는 방식입니다.

자신이 관리하는 리소스 혹은 권한 서버에 해당 클라이언트를 위한 제한된 리소스 접근 권한이 설정되어 있는 경우에 사용됩니다.





Request, Response 예시


[ Authorization Code Grant ]

1. Authorization Code 발급

< Request >

GET https://authorization-server.com/
    auth?response_type=code
    &client_id=CLIENT_ID
    &redirect_uri=REDIRECT_URI
    &scope=photos
    &state=1234zyx
  • reponse_type : Authorization Code 를 발급받기 위해서는 code 로 지정해야합니다.

  • client_id : 애플리케이션을 인증 서버에 등록했을 때 발급받은 Client ID

  • redirect_uri : 애플리케이션을 등록할 때 지정한 Redirect URI

  • scope : 클라이언트가 부여받은 리소스 접근 권한

  • state : CSRF 공격에 대비하기 위해 클라이언트가 보내는 임의의 문자열


< Response >

https://example-app.com/cb?code=AUTH_CODE_HERE&state=1234zyx
  • code : 서버는 Authorization Code 를 쿼리 스트링으로 반환합니다.

  • state : 서버는 client 로부터 전달받은 state 를 그대로 다시 전달합니다.


2. Access Token 발급

< Request >

POST https://api.authorization-server.com/token
    Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
    Content-Type: application/x-www-form-urlencoded

    grant_type=authorization_code
    &code=AUTH_CODE_HERE
    &redirect_uri=REDIRECT_URI
    &client_id=CLIENT_ID
< Response >

{
  "access_token":"RsT5OjbzRn430zqMLgV3Ia",
  "expires_in":3600
}

OR

{
  "error":"invalid_request"
}
  • Authorization Code 를 발급받을 때는 GET 방식으로 요청하는 반면, Access Token 을 발급받을 때는 POST 방식으로 요청하며, application/x-www-form-urlencoded 형식으로 요청합니다.

  • 서버는 Access Token 과 만료 시간으로 응답하거나 오류가 있다면 error 를 전달합니다.

  • grant_type : Access Token 을 전달하기 위해 지정하는데 현재는 Authorization Code 를 이용해서 발급 받는 것이기 때문에 authorization_code 로 지정합니다.

  • code : 쿼리 스트링 형태로 전달받은 Authorization Code 의 코드값을 적습니다.



[ Implicit Grant ]

< Request >

GET https://authorization-server.com/
    auth?response_type=token
    &client_id=CLIENT_ID
    &redirect_uri=REDIRECT_URI
    &scope=photos
    &state=1234zyx
< Response >

http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=1234xyz&token_type=example&expires_in=36000

GET 방식으로 요청하며, response_type = token 으로 지정하고 그 외 나머지는 이전과 동일합니다.

응답은 URL 로 Access Token 이 바로 전달되며, 클라이언트가 전달한 state 및 만료 시간도 포함되어 있습니다.



[ Resource Owner Password Credentials Grant ]

< Request >

POST https://api.authorization-server.com/token
    Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
    Content-Type: application/x-www-form-urlencoded

    grant_type=password
    &username=USERNAME
    &password=PASSWORD
< Response >

{
  "access_token":"RsT5OjbzRn430zqMLgV3Ia",
  "expires_in":3600
}


[ Client Credentials Grant ]

< Request >

POST https://api.authorization-server.com/token
    Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
    Content-Type: application/x-www-form-urlencoded

    grant_type=client_credentials
< Response >

{
  "access_token":"RsT5OjbzRn430zqMLgV3Ia",
  "expires_in":3600
}

0개의 댓글