OAuth는 인터넷 사용자들이 비밀번호를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는, 접근 위임을 위한 개방형 표준이다.
OAuth 1.0 버전에서 발전하여 현재는 OAuth 2.0이 업계 표준 프로토콜이다.
OAuth 2.0은 어떤 점이 좋아서 널리 사용되는걸까?
- 인증과 권한 부여를 동시에 할 수 있음
- 일반 사용자의 정보유출을 막으면서 서드 파티에게 필요한 정보를 제공 가능
- 세밀하게 scope 제어 가능
위와 같은 장점과 더불어 보안이 적당히 좋으면서도 사용자가 편리하게 사용할 수 있다는 점에서 많이 사용되는 것 같다.
이제 OAuth에 대해 기본적인 사항을 알고 과정을 보자!
다양한 인증 방법이 있으며 계속 추가되고 있다. 공식문서에서는 다음과 같은 인증 방법을 볼 수 있다.
그리고 더이상 사용하지 않는 인증 방법으로는 Password Grant가 있고, Implicit Flow는 사용되고는 있으나 보안상의 문제로 권장되지 않는다.
Implicit Flow는 authorization code 교환을 거치지 않고 바로 엑세스 토큰을 발급받게 된다. 이렇게 할 경우 Resource Server에 등록된 Client인지 확인하지 않고 엑세스 토큰을 발급하게 되므로 위험성을 가지게 되고 OAuth 2.0부터는 Implicit Flow를 사용하지 않는 것을 권장한다.
가장 대표적으로 사용되는 것은 Authorization Code Grant 방식이다.
+----------+
| Resource |
| Owner |
| |
+----------+
^
|
(B)
+----|-----+ Client Identifier +---------------+
| -+----(A)-- & Redirection URI ---->| |
| User- | | Authorization |
| Agent -+----(B)-- User authenticates --->| Server |
| | | |
| -+----(C)-- Authorization Code ---<| |
+-|----|---+ +---------------+
| | ^ v
(A) (C) | |
| | | |
^ v | |
+---------+ | |
| |>---(D)-- Authorization Code ---------' |
| Client | & Redirection URI |
| | |
| |<---(E)----- Access Token -------------------'
+---------+ (w/ Optional Refresh Token)
Authorization Server와 Resource Server가 있으나 설명의 편의 상 Authorization Server로 합쳐서 흐름을 알아보자!
OAuth를 이용하여 Authorization Server에 접속하려면 먼저 Client를 Authorization Server에 등록해야 한다.
등록하는 방법은 서비스마다 다르지만 공통적으로 필요한 요소는 아래와 같다.
🚨redirect URI
OAuth 2.0 서비스는 인증이 성공한 사용자를 사전에 등록된 Redirect URI로만 리디렉션 시킨다. 승인되지 않은 URI로 리디렉션 될 경우, 추후 설명할 Authorization Code를 중간에 탈취당할 위험성이 있기 때문이다. 일부 OAuth 2.0 서비스는 여러 Redirect URI를 등록할 수 있다.
Client가 Authorization Server에 접근하는 것을 Resource Owner가 승인하는 과정이다.
Resource Owner가 'Login with GitHub'과 같은 소셜 로그인 버튼을 누른다. 버튼에는 예를 들어 다음과 같은 url이 걸려있을 것이다. scope은 Resource Server에서 사용하고자 하는 기능이며 이 기능에 대해서만 인증을 받으면 된다.
https://Authorization.server
?client_id=1
&scope=B C
&redirect_uri=https://client/callback
→ User-Agent가 Authorization Server에 로그인이 안되어 있다면 먼저 로그인을 하도록 한다.
→ 로그인이 되었다면 Authorization Server는 자신이 가지고 있는 client id와 redirect url을 User-Agent가 요청한 것과 같은지 확인한다. 다르다면 작업을 끝내버린다.
→ client id와 redirect url이 일치한다면 scope에 해당하는 권한을 Client에게 부여할 것인가에 대한 메세지를 User-Agent에게 보낸다.
→ Resource Owner가 승인을 하면 Resource Server에 해당 사용자의 user id와 scope에 대한 정보를 저장한다.
이제 Authorization Server가 승인을 해주어야 한다. 이 때 임시 비밀번호와 같은 'authorization code'를 사용하는데 과정은 아래와 같다.
Authorization Server가 authorization code를 User-Agent에 전송한다. 전송할 때 HTTP header Location에 redirect url의 query string으로 붙여서 보내는데
Location: https://client/callback?code=3
이러한 형식이다.
→ User-Agent는 해당 Location으로 Client에 요청을 보낸다.
→ Client는 User-Agent에게 받은 authorization code로 Authorization Server에 다음과 같은 요청을 보낸다.
https://resource.srver/token?
grant_type=authorization_code // 다른 방법도 있음
&code=3 // authorization code
&redirect_uri=https://client/callback
&client_id=1
&client_secret=2 // client secret!!
→ Authorization Server는 받은 정보가 맞는지 확인하여 다음 단계에서 access token을 발급하게 된다.
이제 드디어 Authorization Server가 access token을 발급한다!
Client가 보낸 요청의 정보가 맞으면 Authorization Server는 access token을 발급하여 Client에게 응답으로 보내준다.
→ Client는 응답으로 받은 access token을 저장한다.
+--------+ +---------------+
| |--(A)------- Authorization Grant --------->| |
| | | |
| |<-(B)----------- Access Token -------------| |
| | & Refresh Token | |
| | | |
| | +----------+ | |
| |--(C)---- Access Token ---->| | | |
| | | | | |
| |<-(D)- Protected Resource --| Resource | | Authorization |
| Client | | Server | | Server |
| |--(E)---- Access Token ---->| | | |
| | | | | |
| |<-(F)- Invalid Token Error -| | | |
| | +----------+ | |
| | | |
| |--(G)----------- Refresh Token ----------->| |
| | | |
| |<-(H)----------- Access Token -------------| |
+--------+ & Optional Refresh Token +---------------+
access token은 브라우저에서 관리를 하기 때문에 탈취당할 위험이 있다. access token을 탈취당했을 경우 서비스 서버는 탈취자가 access token을 사용하여 접근하는것을 막을 방법이 딱히 없다. 그래서 나온 개념이 refresh token이다.
access token의 수명을 짧게 하고, 수명이 다 할 경우 refresh token을 이용하여 access token을 새로 발급 받아 사용자에게 준다. 이렇게 할 경우 access token 탈취 시에 피해를 줄일 수 있고, 사용자는 로그인을 자주 할 필요 없이 내부적으로 로그인을 유지시켜주어 사용자의 편의성을 높여준다.
더 나아가 Refresh Token Rotation(RTR) 기법도 있다. refresh token을 한 번만 사용할 수 있고, 사용 시에는 refresh token도 새로 발급하는 기법이다. refresh token의 탈취까지도 고려한 것으로 볼 수 있는데, refresh token 탈취 시 피해를 줄일 수 있는 방법이다.
Authorization Server는 Access token을 발급할 때 Refresh token을 함께 발급하는 곳도 있고, 보안 상 더 철저하게 관리하는 곳은 refresh token의 탈취를 우려하여 발급하지 않는 곳도 있다.
Access token이 만료되면 Refresh token을 Authorization Server에 보내서 새로운 token을 발급받는다.
이 때, Access token만 갱신하는 경우도 있고, Refresh token도 같이 갱신하여 새로 받는 경우도 있다.
많이 들어본 OAuth였는데 그 과정이 생각보다 복잡했고, 하지만 그만큼 여러 번 확인함으로써 안전하다고 생각했다. 특히 access token과 refresh token을 관리할 때 보안적인 부분까지 고려해서 사용해야 한다는 것을 알았는데 이 두 가지 토큰을 나의 서비스에서 어떻게 사용하면 좋을지에 대해 생각해보게 되었다.
https://opentutorials.org/course/3405
https://oauth.net/2/grant-types/implicit/