웹 서비스를 이용하다보면 위와 같은 로그인 창을 본적이 있을 것이다.
위의 기능은 별도의 회원가입 없이 로그인을 제공하는 플랫폼의 아이디만 있으면 서비스를 이용할 수 있도록 로그인 기능을 제공하는 것이다.
즉, 외부 서비스에서도 인증을 가능하게 하고 그 서비스의 API를 이용하게 해주는 것을 OAuth(Open Authorization)이라고 한다.
OAuth("Open Authorization")는 인터넷 사용자들이 비밀번호를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는, 접근 위임을 위한 개방형 표준이다.
좀 더 간단하게는 인증(Authentication)과 권한(Authorization)을 획득하는 것이라고도 볼 수 있다.
OAuth는 인증을 위한 오픈 스탠더드 프로토콜로, 사용자가 Facebook이나 트위터 같은 인터넷 서비스의 기능을 다른 애플리케이션(데스크톱, 웹, 모바일 등)에서도 사용할 수 있게 한 것이다.
이전에도 다른 애플리케이션에 아이디와 비밀번호를 제공하고 싶지 않은 요구가 있었는데, 비밀정보 인증 방식을 통해 개인정보를 여러 곳에 입력하면서 피싱에 둔감해지고 애플리케이션이 안전하다는 보장이 없기 때문에 보안에 취약했기 때문이다.
비밀번호 인증 방식의 문제점
- 신뢰
- 사용자가 애플리케이션에 ID/PW를 제공하기 꺼려함- 피싱에 대한 인식 저하
- 각 종 애플리케이션들에 ID/PW 를 계속 제공하는 경우- 접근범위가 늘어남에 따른 위험 부담
- ID/PW를 모두 알고 있는 애플리케이션은 모든 권한을 가짐- 신뢰성의 제한
- PW 를 변경한다면 애플리케이션은 동작을 하지 못하게 됨- 폐기 문제
- 권한을 폐기할 수 있는 유일한 방법이 PW를 변경하는 것
OAuth의 탄생 이전에도 다른 애플리케이션에 사용자의 아이디와 암호가 노출되지 않도록 하면서 API 접근 위임(API Access Delegation)이 가능한 여러 인증 방법이 있었다. Google과 Yahoo!, AOL, Amazon 등에서는 각각의 인증 방식을 제작하여 사용했다.
하지만 API 접근 위임에 대한 표준안이 없었고, 이를 위한 표준안으로써 트위터의 주도로 OAuth 1.0이 나온 때는 2007년이며, 이후 보안 문제를 해결한 수정 버전인 OAuth 1.0 revision A 가 2008년에 나왔다.
이 후 이 활동을 지지하는 사람이 생기게 되었고, 2008년 IETF 모임(73회, 미네소타에서 개최)에서 OAuth가 IETF 표준안으로 관리되야 하는 가에 대한 논의가 있었다. 그리고 2010년에 OAuth 1.0 프로토콜 표준안이 RFC5849로 발표되었다.
즉, 2007년에 나온 OAuth 1.0은 비공식 논의체에 의해 최초로 만들어진 것이고, 2010년 IETF OAuth 워킹그룹에 의해 이 프로토콜이 IETF 표준 프로토콜로 발표된 것이다.
이 후 OAuth 1.0과 호환되지 않지만, 인증 절차가 간략한 장점이 있는 OAuth 2.0가 나왔고, 여러 서비스들에서 OAuth 1.0과 OAuth 2.0을 사용하게 되었다.
위에서 OAuth의 사용 예시로 로그인을 소개하였다. 하지만 OAuth와 로그인은 반드시 분리해서 이해해야 한다.
만약 사원증을 이용해 출입할 수 있는 회사가 있다고 할때, 회사 사원이 건물에 출입하는 것이 로그인이라면 OAuth는 외부인이 방문증을 수령한 후 회사에 출입하는 것에 비유할 수 있다.
방문증은 사전에 정해진 곳만 다닐 수 있도록 하는 것이기 때문에, '방문증'을 가진 사람이 출입할 수 있는 곳과 '사원증'을 가진 사람이 출입할 수 있는 곳은 다르다. 이 처럼 직접 서비스에 로그인한 사용자와 OAuth를 이용해 권한을 인증받은 사용자는 할 수 있는 일이 다르다.
OAuth에서 'Auth'는 'Authentication'(인증)뿐만 아니라 'Authorization'(허가) 또한 포함하고 있는 것이다. 따라서 OAuth 인증을 진행할 때 해당 서비스 제공자는 '제 3자가 어떤 정보나 서비스에 사용자의 권한으로 접근하려 하는데 허용하겠느냐'라는 안내 메시지를 보여 주는 것이다.
아래 사진은 네이버에서 접근 권한 요청이 있음을 알려 주는 화면이다.
OpenID도 인증을 위한 표준 프로토콜이고 HTTP를 사용한다는 점에서는 OAuth와 같다. 그러나 OpenID와 OAuth의 목적은 다르다.
OpenID의 주요 목적은 인증(Authentication)이지만, OAuth의 주요 목적은 허가(Authorization)이다.
즉, OpenID를 사용한다는 것은 본질적으로 로그인하는 행동과 같다. OpenID는 OpenID Provider에서 사용자의 인증 과정을 처리한다. Open ID를 사용하는 여러 서비스(Relying Party)는 OpenID Provider에게 인증을 위임하는 것이다.
물론 OAuth에서도 인증 과정이 있다. 하지만 OAuth의 근본 목적은 API를 호출할 수 있는 권한이 있는 사용자인지 확인하는 것이다.
따라서 OAuth를 사용자 인증을 위한 방법으로 쓸 수 있지만, OpenID와 OAuth의 근본 목적은 다르다.
OAuth를 이용하여 사용자를 인증을 하는 과정을 OAuth Dance라고 한다. 두 명이 춤을 추듯 정확하게 정보를 주고받는 과정이라는 것이다.
OAuth 1.0를 구성하고 이해하기 위한 요소들은 다음과 같다.
구분 | 설명 |
---|---|
User | Service Provider에 계정을 가지고 있으면서, Consumer를 이용하려는 사용자 |
Service Provider | OAuth를 사용하는 Open API를 제공하는 서비스 |
Consumer | OAuth 인증을 사용해 Service Provider의 기능을 사용하려는 애플리케이션이나 웹 서비스 |
Request Token | Consumer가 Service Provider에게 접근 권한을 인증받기 위해 사용하는 값. 인증이 완료된 후에는 Access Token으로 교환한다. |
Access Token | 인증 후 Consumer가 Service Provider의 자원에 접근하기 위한 키를 포함한 값 |
OAuth를 이용해 깃허브에 로그인하는 과정을 나타내면 다음과 같다. 해당 과정은 트위터를 Service Provider로 사용한다.
위의 인증 과정을 좀 더 풀어 설명하면 다음과 같다.
Access Token은 방문증이라고 이해할 수 있다.
방문증으로 사전에 허락된 공간에 출입할 수 있는 것처럼 Access Token을 가지고 있는 Consumer는 사전에 호출이 허락된 Service Provider의 오픈 API를 호출할 수 있다.
OAuth Dance(OAuth 인증 과정)를 2012년 기준 네이버 OAuth API를 통해 알아보자.
해당 예시는 OAuth 1.0을 사용한다.
OAuth에서 Consumer가 Request Token 발급을 요청하고 Service Provider가 Request Token을 발급하는 과정이다.
아래는 네이버의 OAuth API로 Request Token을 요청하는 예이다.
GET /naver.oauth?mode=req_req_token&
oauth_callback=http://example.com/OAuthRequestToken.do&
oauth_consumer_key=WEhGuJZWUasHg&
oauth_nonce=zSs4RFI7lakpADpSsv&
oauth_signature=wz9+ZO5OLUnTors7HlyaKat1Mo0=&
oauth_signature_method=HMAC-SHA1&
oauth_timestamp=1330442419&
oauth_version=1.0 HTTP/1.1
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: nid.naver.com
Request Token 발급 요청 시 사용하는 매개변수는 다음과 같다.
매개변수 | 설명 |
---|---|
oauth_callback | Service Provider가 인증을 완료한 후 리다이렉트할 Consumer의 웹 주소. 만약 Consumer가 웹 애플리케이션이 아니라 리다이렉트할 주소가 없다면 소문자로 'oob'(Out Of Band라는 뜻)를 값으로 사용한다. |
oauth_consumer_key | Consumer를 구별하는 키 값. Service Provider는 이 키 값으로 Consumer를 구분한다. |
oauth_nonce | Consumer에서 임시로 생성한 임의의 문자열. oauth_timestamp의 값이 같은 요청에서는 유일한 값이어야 한다. 이는 악의적인 목적으로 계속 요청을 보내는 것을 막기 위해서이다. |
oauth_signature | OAuth 인증 정보를 암호화하고 인코딩하여 서명 값. OAuth 인증 정보는 매개변수 중에서 oauth_signature를 제외한 나머지 매개변수와 HTTP 요청 방식을 문자열로 조합한 값이다. 암화 방식은 oauth_signature_method에 정의된다. |
oauth_signature_method | oauth_signature를 암호화하는 방법. HMAC-SHA1, HMAC-MD5 등을 사용할 수 있다. |
oauth_timestamp | 요청을 생성한 시점의 타임스탬프. 1970년1월 1일 00시 00분 00초 이후의 시간을 초로 환산한 초 단위의 누적 시간이다. |
oauth_version | OAuth 사용 버전. 1.0a는 1.0이라고 명시하면 된다. |
Request Token을 요청하면, Service Provider는 Consumer에 Request Token으로 사용할 oauth_token
과 oauth_token_secret
을 전달한다.
Access Token을 요청할 때는 Request Token의 요청에 대한 응답 값으로 받은 oauth_token_secret
을 사용한다.
Consumer가 웹 애플리케이션이라면 HTTP 세션이나 쿠키 또는 DBMS 등에 oauth_token_secret
를 저장해 놓아야 한다.
OAuth 1.0에서 매개변수 중 oauth_signature
를 생성하는 것이 가장 까다로운 단계이다.
Consumer와 Service Provider가 같은 암호화(signing) 알고리즘을 이용하여 oauth_signature
를 만들어야 한다.
oauth_signature
는 다음과 같은 4단계를 거쳐 만든다.
요청 매개변수를 모두 모은다.
oauth_signature
를 제외하고 'oauth_'로 시작하는 OAuth 관련 매개변수를 모은다. 매개변수를 정규화(Normalize)한다.
=
형태로 나열하고 각 쌍 사이에는 &
을 넣어 또 URL 인코딩을 적용한다.Signature Base String을 만든다.
&
를 사용해 결합한다. 즉 [GET|POST] + & + [URL 문자열로 매개변수는 제외] + & + [정규화한 매개변수]
형태가 된다.http://nid.naver.com/naver.oauth
을 URL로 사용하고, 이 URL에 URL 인코딩을 적용한 값을 사용한 것이다.키 생성
OAuth에서 사용자 인증 페이지를 호출하는 단계에서는 Request Token으로 받은 oauth_token
을 이용해 Service Provider가 정해 놓은 사용자 인증 페이지를 User에게 보여 주도록 한다.
위 예제에서 OAuth용 사용자 인증 페이지의 주소는 다음과 같다.
https://nid.naver.com/naver.oauth?mode=auth_req_token
여기에 Request Token을 요청해서 반환받은 oauth_token
을 매개 변수로 전달하면 된다.
예를 들면 아래와 같은 URL이 만들어 지고 해당 URL은 사용자 인증 화면을 가리킨다.
https://nid.naver.com/naver.oauth?mode=auth_req_token&oauth_token=wpsCb0Mcpf9dDDC2
사용자 인증 화면을 통해 OAuth는 Service Provider에서 User를 인증한다.
인증을 마치면 Consumer가 oauth_callback
에 지정한 URL로 리다이렉트한다. 이때 Service Provider는 새로운 oauth_token
과 oauth_verifier
를 Consumer에 전달한다.
이 값들은 Access Token을 요청할 때 사용한다.
Access Token을 요청하는 방법은 Request Token을 요청하는 방법과 거의 같다. 다만, 사용하는 매개변수의 종류가 약간 다르고 oauth_signature
를 생성할 때 사용하는 키가 다르다.
Access Token 을 요청할 때에는 매개변수 oauth_callback
는 없고, 대신 oauth_token
와 oauth_verifer
가 있다.
Request Token 발급을 요청할 때에는 Consumer Secret Key를 사용해 oauth_token_secret
를 생성했다.
하지만 Access Token 발급을 요청할 때에는 Consumer Secret Key에 oauth_token_secret
을 결합한 값 즉, (Consumer Secret Key + & + oauth_token_secret)
을 사용해 oauth_token_secret
를 생성한다. 암호화 키를 변경하여 보안을 더 강화하는 것이다.
Access Token 발급을 요청할 때 사용하는 매개변수는 아래와 같다.
매개변수 | 설명 |
---|---|
oauth_consumer_key | Consumer를 구별하는 키 값. Service Provider는 이 키 값으로 Consumer를 구분한다. |
oauth_nonce | Consumer에서 임시로 생성한 임의의 문자열. oauth_timestamp의 값이 같은 요청에서는 유일한 값이어야 한다. 이는 악의적인 목적으로 계속 요청을 보내는 것을 막기 위해서이다. |
oauth_signature | OAuth 인증 정보를 암호화하고 인코딩하여 서명 값. OAuth 인증 정보는 매개변수 중에서 oauth_signature를 제외한 나머지 매개변수와 HTTP 요청 방식을 문자열로 조합한 값이다. 암화 방식은 oauth_signature_method에 정의된다. |
oauth_signature_method | oauth_signature를 암호화하는 방법. HMAC-SHA1, HMAC-MD5 등을 사용할 수 있다. |
oauth_timestamp | 요청을 생성한 시점의 타임스탬프. 1970년1월 1일 00시 00분 00초 이후의 시간을 초로 환산한 초 단위의 누적 시간이다. |
oauth_version | OAuth 사용 버전 |
oauth_verifier | Request Token 요청 시 oauth_callback으로 전달받은 oauth_verifier 값 |
oauth_token | Request Token 요청 시 oauth_callback으로 전달받은 oauth_token 값 |
위의 표에 나타낸 매개변수들를 상황에 맞게 정의한 다음 Access Token을 요청하면 oauth_token
과 oauth_token_secret
을 전달받게 된다.
Service Provider에 따라 사용자의 아이디나 프로필 정보 같은 것들이 반환되기도 한다.
Access Token을 발급 받으면 Consumer는 User의 권한으로 Service Provider의 기능을 사용할 수 있게 된다. 다시말해, 권한이 필요한 오픈 API를 호출할 수 있게 되는 것이다.
예를 들어 네이버 카페에서 게시판 목록을 가져온기 위해 호출해야 하는 URL은 다음과 같다.
http://openapi.naver.com/cafe/getMenuList.xml
이때, 특정 User의 권한을 가지고 카페 게시판 목록 반환 URL을 요청해야 해당 User가 가입한 카페의 게시판 목록을 반환받을 수 있다.
이를 위해 해당 URL을 호출할 때는 OAuth 매개변수를 함께 전달해야 한다.
아래는 Access Token을 사용해 오픈 API를 요청하는 예이다.
HTTP 헤더에 Authorization 필드를 두었고, Authorization 필드의 값 부분에 OAuth 매개변수 적는다.
Access Token을 사용할 때는 GET이나 POST가 아닌 HEAD 방식을 사용한다.
POST /cafe/getMenuList.xml HTTP/1.1
Authorization: OAuth oauth_consumer_key="dpf43f3p2l4k3l03",
oauth_token="nSDFh734d00sl2jdk",
oauth_signature_method="HMACSHA1",
oauth_timestamp="1379123202",
oauth_nonce="chapoH",
oauth_signature="MdpQcU8iPSUjWoN%2FUDMsK2sui9I%3D"
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: http://openapi.naver.com
Access Token을 사용해 오픈 API를 호출할 때 사용하는 매개변수는 아래와 같다.
매개변수 | 설명 |
---|---|
oauth_consumer_key | Consumer를 구별하는 키 값. Service Provider는 이 키 값으로 Consumer를 구분한다. |
oauth_nonce | Consumer에서 임시로 생성한 임의의 문자열. oauth_timestamp의 값이 같은 요청에서는 유일한 값이어야 한다. 이는 악의적인 목적으로 계속 요청을 보내는 것을 막기 위해서이다. |
oauth_signature | OAuth 인증 정보를 암호화하고 인코딩하여 서명 값. OAuth 인증 정보는 매개변수 중에서 oauth_signature를 제외한 나머지 매개변수와 HTTP 요청 방식을 문자열로 조합한 값이다. 암화 방식은 oauth_signature_method에 정의된다. |
oauth_signature_method | oauth_signature를 암호화하는 방법. HMAC-SHA1, HMAC-MD5 등을 사용할 수 있다. |
oauth_timestamp | 요청을 생성한 시점의 타임스탬프. 1970년1월 1일 00시 00분 00초 이후의 시간을 초로 환산한 초 단위의 누적 시간이다. |
oauth_version | OAuth 버전 |
oauth_token | oauth_callback으로 전달받은 oauth_token |
주의
Access Token을 이용해 요청할 때, Service Provider에 따라realm
이라는 매개변수를 사용해야 하는 경우도 있다.realm
은 optional 매개변수인데,WWW-Authenticate HTTP
헤더 필드에서 사용하는 값이다.
OAuth 1.0은 웹 애플리케이션이 아닌 애플리케이션에서는 사용하기 곤란하다는 단점이 있다. 또한 절차가 복잡하여 OAuth 구현 라이브러리를 제작하기 어렵고, 이런저런 복잡한 절차 때문에 Service Provider에게도 연산 부담이 발생한다.
OAuth 2.0은 이러한 단점을 개선한 것으로 OAuth 2.0의 특징은 다음과 같다.
이외에도 OAuth 2.0에서 사용하는 용어 체계는 OAuth 1.0과 완전히 다르다.
같은 목적의 다른 프로토콜이라고 이해하는 것이 좋다.
OAuth 2.0를 구성하고 이해하기 위한 요소들은 다음과 같다.
구분 | 설명 |
---|---|
Resource Owner | 서드파티 애플리케이션 (Google, Facebook, Kakao 등)에 이미 개인정보를 저장(회원가입)하고 있으며 Client가 제공하는 서비스를 이용하려는 사용자이다. 'Resource' 는 개인정보라고 생각하면 된다. |
Client | OAuth 2.0을 사용해 서드파티 로그인 기능을 구현할 자사 또는 개인 애플리케이션 서버 |
Authorization Server | 권한을 부여(인증에 사용할 아이템을 제공주는)해주는 서버로 사용자는 이 서버로 ID, PW를 넘겨 Authorization Code를 발급 받을 수 있다. Client는 이 서버로 Authorization Code을 넘겨 Access Token을 발급 받을 수 있다. |
Resource Server | 사용자의 개인정보를 가지고있는 애플리케이션 (Google, Facebook, Kakao 등) 서버로 Client는 Access Token을 이 서버로 넘겨 개인정보를 응답 받을 수 있다. |
Access Token | 인증 후 Client가 Resource Server의 자원에 접근하기 위한 키를 포함한 값 |
Refresh Token | Access Token이 만료되었을 때, 새로운 Access Token을 발급 받기 위한 Token Authorization Server에서 Access Token을 발급할 때 Refresh Token도 함께 발급하여 전달한다. |
OAuth 2.0의 일반적인 인증 과정은 다음과 같다.
OAuth 2.0의 경우 4가지 프로토콜이 존재한다.
Client와 Authorization Server와의 상호작용 횟수 및 Client 종류에 따라 다음과 같이 분류할 수 있다.
Confidential Client | Public Client | |
---|---|---|
3-legged | Authorization Code Grant Type | Implicit Grant Type |
2-legged | Resource Owner Password Credentials Grant Type | Client Credentials Grant Type |
Confidential Client
인증 서버로 안전하게 인증할 수 있는 응용 프로그램을 말한다.
(등록된 클라이언트 비밀을 안전하게 유지할 수 있음)
Public Client
브라우저나 모바일 장치에서 실행되는 응용 프로그램과 같이 등록된 클라이언트 암호를 사용할 수 없는 Client를 말한다.
response_type=code
라고 넘긴다.response_type=token
이라고 넘긴다.grant_type=password
이라고 넘긴다.grant_type=client_credentials
이라고 넘긴다.OAuth 1.0 | OAuth 2.0 | |
---|---|---|
참여자 구분 | - 이용자(User) - 소비자(Consumer) - 서비스 제공자(Service Provider) | - 자원 소유자(Resource Owner) - 클라이언트(Client) - 권한 서버(Authorization Server) - 자원 서버(Resource Server) |
토큰 | - 요청 토큰(Request Token) - 접근 토큰(Access Token) | - 접근 토큰(Access Token) - 재발급 토큰(Refresh Token) |
유효 기간 | - 접근 토큰의 유효 기간 없음 | - 접근 토큰 유효 기간 부여 - 만료 시 재발급 토큰 이용 |
클라이언트 | - 웹 서비스 | - 웹, 앱 등 |
- https://ko.wikipedia.org/wiki/OAuth
- https://d2.naver.com/helloworld/24942
- https://cheese10yun.github.io/oauth2/#null
- https://showerbugs.github.io/2017-11-16/OAuth-%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C
- https://itwiki.kr/w/OAuth#%EC%9D%B8%EC%A6%9D_%EC%A0%88%EC%B0%A8
- https://hwannny.tistory.com/92