💻 Computer Science/Network

[보안] SSO(Single Sign-On) 구현 2 - OAuth 2.0(Open Authorization 2.0)

Sugar0810 2023. 2. 14. 16:50

참고 : OAuth 2.0 Simplified

 

OAuth 2.0(Open Authorization 2.0, 이하 OAuth)는 “Authorization“을 위한 개방형 표준 프로토콜입니다.
Third-Party App에게 리소스 소유자를 대신하여 리소스 서버에서 제공하는 자원에 대한 접근 권한을 위임하는 방식을 제공합니다.
즉, 사용자의 동의를 받고 Third-Party App과 중요한 정보(계정)를 공유하지 않고도 자원에 접근할 수 있게 해줍니다.

예를 들어 다음과 같은 경우를 예시로 들 수 있습니다.

1.사용자는 3rd party app에 있는 “facebook 친구 리스트 import” 단자를 클릭함
2.사용자가 Facebook에 성공적으로 로그인하면, Facebook 친구 목록에 접근하는 것을 허가할 것인지에 대한 메시지가 표시됨

3.사용자가 Yes를 클릭하면 3rd party app에 Facebook 친구 목록을 가져올 수 있는 권한, 그리고 승인을 부여하는 토큰과 함께 사용자는 app으로 리다이렉트됨

 

OAuth는 사용자가 자격 증명을 공유하지 않고도 app에서 리소스에 액세스 할 수 있습니다.
즉, 3rd앱이 facebook아이디를 몰라도 facebook에 있는 정보를 서비스에서 안전하게 사용할 수 있다는 의미입니다.

 

OAuth는 모바일 플랫폼에서의 SAML의 단점을 보완하기 위해 개발되었으며, SAML과 다르게 XML이 아닌 JSON을 기반으로 합니다.

 

또한 SAML은 Authentication/Authorization(인증/인가)를 둘 다 다루는데 반해 OAuth는 Authorization를 목적으로 설계되었습니다.

 

 

※ Authentication vs Authorization

  • Authentication : 인증. 내가 누군지!
  • Authorization : 인가. 내가 어떤 권한을 갖고 있는지!

 

※ Access Token

OAuth의 핵심은 Access Token입니다.

 

Access Token은 임의의 문자열 값이고, 토큰을 발급해 준 서비스만이 해당 토큰의 정보를 알고 있습니다.

 

이 토큰은 Resource Owner가 자신의 정보(Resource)를 넘겨주는 것에 대해서 동의한다는 증표입니다.

 

SAML에서 SAMLAssertion이 안에 User의 인증정보를 갖고 있어서, 해당 Assertion을 가지면 User의 인증/권한을 사용할 수 있듯이
OAuth에서는 Access Token이 이와 비슷한 역할을 수행하게 됩니다.
(Access Token는 인증에 대한 정보는 없고, 권한에 대한 허가만 가능)


토큰을 요청할 때에는 redirect_uri값을 같이 요청하여 발급받을 위치를 지정하게 됩니다.
하지만 어떤 악의적인 사용자가 redirect_uri값을 변경한다면? 그럼 그 해커는 AccessToken을 탈취하고 resource에 마음대로 접근할 수 있는 권한을 갖게 됩니다.

 

이러한 위험성때문에 OAuth를 사용하려는 ServiceProvider에 AccessToken을 발급받을 위치인 redirect_uri을 등록해야합니다.


만약 위의 예시처럼 페이스북의 친구를 끌고오는 3rd party app이 있다면, OAuth방식으로 자원에 대한 권한을 얻으려면 페이스북에 3rd party app로 돌아오는 redirect_uri를 등록해주어야 합니다.


만약 기 등록된 redirect_uri가 아니라 다른 uri로 리다이렉트로 AccessToken을 보내려고 한다면 페이스북에서는 수상한 행동으로 여기고 정보를 보내주지 않을 것입니다.

 

 Refresh Token

Access Token은 탈취당하면 안되는 OAuth에서 가장 중요한 토큰입니다.
만약 탈취당하면 악의적인 사용자가 나의 정보에 접근할 수도 있습니다.

 

때문에 OAuth에서는 일정 시간이 지나면 AccessToken을 사용하지 못하도록 유효기간을 설정해둡니다.

 

보통 짧게는 몇분에서 길어야 반나절 정도로 유효기간을 설정해두는데요, 이 방식은 짧으면 짧을 수록 안전하지만 만료될때마다 다시 Resource Owner에게 허락받아야 한다는 단점이 있습니다.(다시 로그인해야한다는 의미)

 

그래서 Access Token을 간편하게 발급받을 수 있는 Refresh Token을 Access Token과 함께 받게 됩니다.
Refresh Token은 Access Token보다 유효기간이 길어서 Access Token이 만료되더라도 Refresh Token이 만료되지 않는 이상 로그인 없이 계속 발급받을 수 있습니다.

 

※ 인증 플로우 : Authorization Code Grant

지금부터는 OAuth의 플로우에 대해서 알아보도록 하겠습니다.

 

총 4가지 방법이 있는데, 해당 포스팅에서는 그 중 가장 많이 사용하고 권장하는 방법인 Authorization Code Grant(권한 코드 인증)에 대해서 설명하도록 하겠습니다.

 

역할은 4가지입니다.

  • Resource Owner : 자원소유자, User
  • Client : 클라이언트 (Ex. 3rd party app)
  • Service Provider : 서비스 제공자
    • Resource Server : 자원 서버
    • Authorization Server : 권한 서버

0. Client 서비스 등록

  • 신뢰할 수 있는 Redirect Uri를 위해 미리 Service Provider(SP)에 Access Token을 받을 Client의 uri를 등록합니다.

1. 서비스 요청

  • Resource Owner(User)가 Client에 서비스를 요청합니다.
  • Client에서는 Session내 Access정보가 있는지 확인합니다.ex. 같이 “게임(client)”할 친구를 구하고 싶은 “호롤리(User)”는 게임내 “페이스북(SP) 친구 연동하기” 버튼을 클릭합니다.

2. Authorization Code 요청

  • Session 내 Access정보가 없는 것을 확인한 Client는 SP의 Authorization Server에 Authorization Code를 요청합니다.
  • 이 때 Request에 포함되는 파라미터 : client_id, redirect_url, scope response_type=code
  • scope는 어떤 권한을 요청할건지 범위
  • 서버 내 Access정보가 남아있는지 확인합니다.

3. 로그인 팝업 출력 & 로그인 정보 입력

  • 서버 내 Access 정보가 없다면 로그인 팝업을 사용자에게 띄웁니다.
  • 로그인하면 어떤 권한을 허가할것인지에 대한 메세지 창을 띄웁니다.
  • 이때의 인증과정은 OAuth의 범위가 아닙니다. Token을 받기 위한 인증일 뿐!ex. 호롤리는 페이스북 로그인창에 자신의 계정을 입력하여 로그인하고, 게임에서 나의 페이스북 친구리스트에 접근할 수 있는 권한을 허가해줍니다.

4. Authorization Code 응답

  • 로그인 정보와 redirect_url이 valid하다면 Authorization Code를 redirect_url로 응답해줍니다.
  • Authorization Code는 해당 Client는 Resource Owner에게 사용허락을 인가받았음의 증서와 같습니다.

5. Access Token 요청

  • Access Token을 요청합니다.
  • 이 때 Request에 포함되는 파라미터 : client_id, client_secret, redirect_url, authorization_code

6. Access Token, Refresh Token 응답

  • Access Token : (user가 허락한 scope만큼의)Resource를 사용할 수 있게 해주는 토큰
  • Refresh Token : 보안을 위해 유효시간이 짧은 Access Token을 위해 간단히 Access Token을 발급받을 수 있게 해주는 토큰
  • 아래와 같은 형식으로 응답이 오게됩니다.
    HTTP/1.1 200 OK
    Content-Type: application/json
    Cache-Control: no-store
    Pragma: no-cache
      
    {
      "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
      "token_type":"bearer",
      "expires_in":3600,
      "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
      "scope":"create"
    }
    

7. Resource 요청

  • Client는 발급 받은 Access Token을 통해 Resource Server에서 사용자의 정보에 접근합니다.
  • Resource를 요청할 때에는 다음과 같이 Request헤더에 AccessToken을 세팅합니다.
    Authorization: Bearer <ACCESS TOKEN>
    

8. Resource 응답

  • Resource Server는 받은 Access Token의 유효성과 지정된 scope에 접근하는것이 맞는지 확인한 후, 정보를 내어줍니다.

9. 서비스 응답

  • 요청했던 Resource를 토대로 Client는 Resource Owner가 요청했던 서비스를 제공합니다.ex) 페이스북 로그인을 마친 호롤리는 게임 화면에서 자신의 페이스북 친구들을 확인할 수 있게 되었습니다!

 

※ Access Token이 만료되었을 경우

Access Token이 만료되면 Client는 더이상 Resource Server로부터 Resource를 가져올 수 없습니다.(권한 없음!)

 

1. Access Token 재요청

  • Refresh Token과 만료된 Access Token을 Authorization Server로 보냅니다.
    POST /oauth/token HTTP/1.1
    Host: authorization-server.com
      
    grant_type=refresh_token
    &refresh_token=xxxxxxxxxxx
    &client_id=xxxxxxxxxx
    &client_secret=xxxxxxxxxx
    

2. 새로운 Access Token 발급

  • 서버는 받은 Refresh Token이 조작되지 않았는지 DB의 토큰과 비교 합니다.
  • 토큰이 동일하고 Refresh Token의 유효기간도 지나지 않았다면 새로운 Access Token을 발급해 줍니다.

만약 Refresh Token도 만료되었다면 다시 로그인을 해야합니다!

 

※ SSO 개념 보러가기

 


 

🎓 Reference