OAuth 2.0

소밍·2023년 7월 24일
0
post-thumbnail

OAuth란 구글과 같은 플랫폼의 특정한 사용자 데이터에 접근하기 위해 제3자 클라이언트(우리의 서비스)가 사용자의 접근 권한을 위임(Delegated Authorization)받을 수 있는 표준 인가 프로토콜을 말한다. 우리 서비스의 사용자의 구글 플랫폼 데이터에 접근하기 위해 사용자의 구글 id, pw를 받아 가져오는 것은 간단하지만 보안 측면에서 좋지 않다. 물론 구글 역시 우리 서비스가 사용자의 id, pw를 가지고 있는 것을 좋아하지 않을 것. 그렇다면 구글로 로그인하기는 어떤식으로 이루어지는 걸까? 로 시작한 OAuth 공부이다.



1. OAuth 2.0 주체

OAuth에는 다음과 같은 주체가 있다. 내가 쉽게 이해하기 위해 예시를 추가했다.

1-1. Resource Owner

  • 우리의 서비스를 이용하면서 구글과 같은 플랫폼의 리소스(ex. 캘린더 정보)를 소유하고 있는 유저.

1-2. Client

  • Resource Owner의 권한으로 Resource Server의 자원을 이용하고자 하는 서비스.
  • 우리의 서비스

1-3. Authorization Server

  • Resource Owner의 인증 및 권한 부여 후, Client에게 액세스 토큰을 발급하는 서버.
  • 인증과 관련된 처리를 전담하는 서버

1-4. Resource Server

  • Client의 요청에 따라 보호된 리소스에 대한 액세스 권한을 검증하고 응답하는 서버

이후 본문에선 '리소스 소유자', '클라이언트', '인가 서버', '리소스 서버' 라고 칭함.


2. Client 등록

OAuth를 이용하기 전 클라이언트를 리소스 서버에 등록해야한다.

2-1. redirect uri 등록

  • 클라이언트 등록 과정에서 리소스 서버에게 redirect uri를 등록.
  • 후에 리소스 서버가 권한을 부여하는 과정에서 authorization code를 전달해주는데 그 코드를 등록한 redirect uri로 전달.
  • 사용자가 OAuth 2.0 서비스에서 인증을 마치고 (예를 들어 구글 로그인 페이지에서 로그인을 마쳤을 때) 사용자를 리디렉션시킬 위치

2-2. client_id, client_secret 발급

- client_id

- 애플리케이션 식별하는 고유 id
- 외부에 노출되어도 괜찮음.

- client_secret

- id에 대한 비밀번호
- 외부에 노출되어선 안됨.


3. OAuth 2.0의 권한 부여 방식

3-1. authorization code

3-1-1. access token 발급 위한 HTTP 요청 예시

POST /token HTTP/1.1
grant_type=authorization_code
		&code=xxxxxxxxxxxxxxx
        &redirect_uri=https%ajldfwf

3-1-2. 동작 매커니즘

  1. 클라이언트가 리소스 소유자에게 권한을 얻기 위해 인가 서버로 리소스 소유자를 리디렉션함.
  2. 리소스 소유자는 인가 서버를 통해 클라이언트에 대한 권한 부여 여부 결정.
  3. 리소스 소유자가 권한 부여를 승인하면, 인가 서버가 authorization code를 생성하고 이 코드를 클라이언트에게 제공.
  4. 클라이언트는 authorization code를 사용하여 인가 서버에 액세스 토큰발급을 요청함.
    (이 때 클라이언트는 client id, client secret을 함께 전달하여 자신을 인증함)
  5. 인가 서버는 클라이언트의 인증 정보를 확인하고, 유효한 authorization code인 경우 액세스 토큰을 발급.
  6. 이렇게 발급받은 액세스 토큰을 사용하여 클라이언트는 리소스 서버에 요청을 보내고 보호된 리소스에 접근 가능.

3-2. implicit

웹 브라우저를 통해 클라이언트가 리소스 서버에 접근하는 경우에 사용되며, 주로 클라이언트가 웹 애플리케이션인 경우에 사용

GET /authorize HTTP/1.1
		?response_type=token
		&client_id=sdffjq1235alkd
        &redirect_uri=https%ajldfwf

3-2-1. 코드로 확인할 수 있는 implicit 방식 특징

  • POST가 아닌 GET 요청
    일반적으로 OAuth 2.0 인증 프로토콜에서는 액세스 토큰을 요청하는데 POST 요청을 사용하는 경우가 많지만, implicit 플로우는 액세스 토큰을 요청할 때 특별한 인증 코드(authorization code)를 받아올 필요가 없으며, 단지 액세스 토큰만 받으면 되기 때문에 GET 요청 사용

  • grant_type이 없다
    grant_type 매개변수는 클라이언트가 사용하는 권한 부여 방식을 식별하는 역할
    implicit 플로우는 이미 클라이언트가 인가되었다고 간주하고, grant_type 파라미터를 생략하고 액세스 토큰을 바로 요청

3-2-2. 동작 매커니즘

(1) 리소스 서버는 클라이언트가 이미 리소스 소유자에게 인가를 받은 상태라고 가정하고 등록된 클라이언트인지 확인 (client_id, redirect_uri 일치 확인)
(2) 등록된 클라이언트라면 액세스 토큰을 redirect_uri로 보냄

3-2-3. implicit의 특징

  • authorization code 없이 바로 액세스 토큰을 발급
    - 클라이언트가 인가 코드를 요청하지 않는다는 것.

  • 클라이언트 인증 이루어지지 않음.
    - 클라이언트가 누구인지 확인하지 않고 액세스 토큰을 발급한다는 의미.

✦ 등록된 클라이언트인지 확인하는 것과 클라이언트 인증은 다른 것

► 등록된 클라이언트 확인

  • 리소스 서버가 클라이언트로부터 authorization code 또는 액세스 토큰 발급을 요청받았을 때
    해당 클라이언트가 등록된 클라이언트인지를 확인하는 것을 의미.
  • 리소스 서버에 클라이언트를 등록할 때 발급받은
    클라이언트 아이디(client_id)와 클라이언트 비밀번호(client_secret)가 올바른지 확인

► 클라이언트 인증

  • 클라이언트가 가지고 있는 authorization code나 액세스 토큰이 유효한지,
    리소스 서버에 접근 권한이 있는지를 확인하는 것을 의미.

3-3. resource owner password credentials

POST /token HTTP/1.1
grant_type=password
		&username=resource_owner_name
        &password_uri=resource_owner_password
  • 클라이언트가 리소스 오너에게 직접 username과 password를 받아 액세스 토큰을 요청
  • 이 때 인가코드나 리디렉션은 사용하지 않으며 액세스 토큰을 바로 받아옴.

3-3-1. 주의사항

  • username과 password를 직접 받아오기때문에 보안적으로 주의가 필요.
  • 클라이언트는 정보 보호를 위해 HTTPS와 같은 보안 프로토콜을 사용하여 통신해야함.
  • 유저가 가지고 있는 기기의 os와 같은 굉장히 믿을 수 있는 안전한 환경에서만 사용할 수 있는 플로우.

3-4. client credentials

클라이언트가 자체 리소스를 사용하거나, 또는 이미 리소스 서버와 신뢰 관계를 가지고 있을 때 주로 사용.
이 방식에서는 클라이언트 자체가 리소스 서버에 접근하는 경우(예: API 서버에 접근하는 서비스) 자신의 신원을 인증하고 액세스 토큰을 발급받는 방식
사실상 리소스 오너와 oauth 클라이언트가 동일한 개체일때 복잡한 플로우를 가져가기보단 직접적으로 API호출을 통해 토큰을 발급받는 것

POST /token HTTP/1.1
grant_type=client_credentials
        &client_id=your_client_id
        &client_secret=your_client_secret

3-4-1. 동작 매커니즘

(1) 클라이언트는 자신의 자격증명(client_id, client_secret)을 사용하여 인증
(2) 클라이언트는 authorization code나 리디렉션없이 client_id와 client_secret을 리소스 서버로 보내 액세스 토큰을 요청.
(3) 리소스 서버는 클라이언트로부터 받은 client_id와 client_secret을 확인하여 클라이언트에게 액세스 토큰 발급



4. access token은 bearer token

✦ bearer token

  • 다른 암호학적 보호나 클라이언트에 바인딩 되는 장치들을 모두 배제한채
    해당 토큰을 소유하고 있는 것 만으로도 토큰에 대한 사용 권한이 있음을 인정해주는 토큰
  • 토큰이 노출되면 누구나 해당 리소스에 접근할 수 있게 되므로,
    HTTPS와 같은 안전한 통신을 사용하고, 토큰의 유효 기간을 짧게 설정하여 보안을 강화하는 것이 중요
POST /token HTTP/1.1
     Host: server.example.com
     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
     Content-Type: application/x-www-form-urlencoded

     grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
     &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

OAuth 2.0에서 클라이언트가 리소스 서버에 요청을 보낼 때,
HTTP 헤더에 Bearer Token을 포함하여 액세스 토큰을 전달.
리소스 서버는 이 Bearer Token을 검증하여 클라이언트의 요청이 유효한지 확인하고,
해당 액세스 토큰이 리소스에 접근할 권한이 있는지 확인.



5. refresh token

일반적으로 access token은 만료기간이 있으며, 만료되면 더 이상 사용할 수 없다.
refresh token는 access token보다 더 오래 유효하며 이를 이용하여 access token이 만료되었을 때 refresh token으로 새로운 access token과 새로운 refresh token을 받을 수 있다.

  1. access token의 기간이 만료
  2. 클라이언트는 refresh token을 인가 서버 에게 전달
  3. 인가 서버는 클라이언트가 보낸 refresh token를 확인 후
    새로운 access token과 새로운 refresh token을 발급
    클라이언트는 새로 발급받은 access token을 사용하여 리소스 서버의 보호된 리소스에 접근 가능


6. OAuth 1.0과 달라진 점

  • scope를 통해 해당 토큰이 접근할 수 있는 유저 리소스 범위 제한 가능
  • bearer token + TLS 사용으로 client 복잡성 간소화
  • 서버 역할을 authorization, resource 으로 나눔
  • refresh token으로 토큰 탈취 문제 개선
    • 액세스 토큰 탈취되더라도 액세스 토큰이 살아있는 짧은 기간만 *어뷰징할 수 있기 때문.
    • refresh token으로 새로운 액세스 토큰 발급받아 리소스 접근 가능
  • grant 개념 추가로 제한적인 사용환경이 아닌 여러 사용환경에 대한 플로우 나타낼 수 있음
  • 어뷰징(abusing) 이란 부정한 목적을 가지고 시스템을 이용하거나,
    시스템의 취약점을 악용하여 불법적인 행위를 하는 것.


7. OAuth 2.1

더 보안적으로 민감한 사용처들의 프로토콜 채택 (금융권, 의료계, 증권시장 등)
OAuth 1.0 -> 2.0 으로 넘어오면서 클라이언트의 복잡성 해소를 위해 다소 보안을 희생한 trade off 가 있었음
이런 부분이 민감한 사용처들이 사용하기엔 보완이 필요했음
여러 RFC 보안책들을 하나로 모아 스펙화 시키고 현재 구현에 모범 적용 사례들을 스펙화 시킴

7-1. OAuth 2.0 보안과 BCP

7-1-1. OAuth 2.1의 Grant

  • 토큰 탈취에 취약한 implicit 배제

  • 유저에게 직접 아이디, 비밀번호 받는 resource owner password credentials 배제

  • Device Authorization Grant 추가
    - IoT와 관련된 여러 스마트 기기에 적합 사용하는 해당 기기가 아닌 다른 기기를 통해 인증을 받는 플로우

    POST /token HTTP/1.1
    grant_type=urn%3Aietf%3AParams%3Aoauth%3Agrant-type%3Adevice_code
            &device_code=QdlkfwodfkSwldkfRkdmwdf
            &client_id=143205482

7-1-2. 중간에 있는 검증값 탈취 문제 해결 위해 PKCE 스펙 추가

OAuth 2.0의 Authorizaton code grant에 추가된 PKCE
Authorization code flow 시작시 클라이언트가 랜덤값에 대한 hash를 인가 서버에게 보냄,
그리고 액세스 토큰 요청을 보낼 때 해당 해쉬값의 원문을 같이보냄
-> 첫 요청을 탈취하더라도 해쉬 연산을 역연산을 할 수 없기 때문에
첫 요청을 시작한 클라이언트와 마지막으로 토큰을 발급받고자하는 클라이언트가 동일한 서버임을 확인할 수 있음

7-1-3. Refresh Token 개선 - 회전방식

리프레시 토큰은 access token보다 긴 사용기간을 가지고 있었고, 똑같은 리프레시 토큰을 가지고 새로운 access token을 발급받았다면 2.1 부터는 refresh token이 일회성이 되어서 refresh token으로 새로운 access token을 발급받으면 기존에 있던 refresh token은 사용할 수 없게되고 새로운 refresh token을 발급받는 회전방식을 채택

7-1-4. 그 외 OAuth 2.1 BCP에 포함된 보안 사항

  • Redirect URI 패턴 매칭 스펙 아웃, 정확한 매칭 강제
  • URI Query String 에서 Bearer token 사용 불가
  • mTLS 또는 DPoP(암호학적으로 토큰을 Client에 종속) 채택
  • 그 외 자주 발생하는 버그들에 대한 보완 스펙

8. Open ID Connect 인증 계층

OAuth 2.0에서 토큰을 발급받았던 flow에서 추가적으로 JWT기반의 ID 토큰이라는 또다른 토큰을 같이 받을 수 있음

8-1. ID Token

  • 토큰 발급자
  • 토큰 발급 시간
  • 토큰 사용자 (client 식별자)
  • 사용자 식별자
  • 토큰 만료 시간

8-2. ID Token 이점

OAuth 2.0에서 사용자 정보를 알아보기 위해서는 토큰을 가지고 API call을 해야했었던 것과는 다르게
직접적으로 ID 토큰을 파싱하고 안에 있는 서명값을 검증함으로써 API call을 하지 않고도 사용자에 대한 정보를 가져올 수 있음.
이것이 Open ID가 많이 쓰이는 이유고, 트래픽이 늘어나는 인터넷 환경에서 Open ID Connect가 2.1스펙보다 먼저 IDP(IDentity Provider)를 구현하는 이유
통신 부하를 줄이기 위해 Open ID connect가 생겼구나-> api call 하지 않으니 !


요약

  • OAuth 1.0
    - OAuth 인가 프로토콜 개념 제시, 브라우저 환경 동작
  • OAuth 2.0
    - Client 간소화, Refresh 토큰 등장, 여러가지 Grant 추가
  • OAuth 2.1
    - 보안성 개선, IoT 기기 지원 및 모범 사례의 스펙화
  • OpenID Connect
    - 인증 계층 추가, API call 없이 사용자 정보 확인


[참고 자료]

생활코딩 - OAuth 2.0
https://ko.wikipedia.org/wiki/OAuth
https://datatracker.ietf.org/doc/html/rfc6749#section-1.2
https://hudi.blog/oauth-2.0/
https://www.youtube.com/watch?v=DQFv0AxTEgM
https://www.samsungsds.com/kr/insights/oidc.html

profile
생각이 길면 용기는 사라진다.

1개의 댓글

comment-user-thumbnail
2023년 7월 24일

글 잘 봤습니다.

답글 달기

관련 채용 정보