본문 바로가기

웹프로그램

OAuth를 이용해서 인증하기(Ver 1.0)


1. OAuth를 이용한 인증
OAuth 인증은 컨슈머에게 사용자의 자격증명(credentials)를 공유하지 않고 그들의 보호된 자원을 접근하는것을 사용자가 허가하는 과정이다.
OAuth는 보호된 자원을 요청하는데 있어서 사용자의 자격증명 (credentials) 대신에 서비스 프로바이더에 의해 생성된 토큰을 사용한다.
이 과정에서 두개의 토큰을 사용한다.

요청 토큰(Request Token) :
  - 컨슈머가 사용자의 보호된 자원에 접근하기 위하여 사용자로 부터 허가받기 위해서 사용된다. 
  - 사용자에 의해 인증된 요청토큰(Request Token)은 접근토큰(Access Token)으로 교환된다.
  - 한번만 사용되어야 하고, 위 용도가 아닌 다른 용도로 사용되면 안된다.
  - 만료시간을 가지고 있는 것을 권한다.

접근 토큰(Access Token) :
  - 컨슈머가 사용자의 보호된 자원에 접근하기 위해 사용된다.
  - 보호된 자원에 접근권한을 제한할 수 있고 만료시간을 가질 수 있다. 
  - 서비스 프로바이더(Service Provider)는 사용자가 이 Token을 파기할 수 있도록 해 주어야 한다. 
  - 접근 토큰(Access Token)은 보호된 자원에 접근하는 목적으로만 사용되어야 한다.
 
* OAuth 인증은 다음 세 단계에 의해 이루어진다.
  1) 컨슈머가 인증이 안된 요청 토큰을 획득한다. 
  2) 사용자는 요청토큰을 인증한다. 
  3) 컨슈머는 인증된 요청 토큰을 접근 토큰으로 교환한다.


 

A. 인증 안된 요청토큰을 획득
컨슈머는 서비스 프로바이더에게 토큰을 발행해줄 것을 요청해서 인증이 안된 요청토큰을 획득한다. 요청 토큰의 단 한가지 목적은 사용자의
승인을 얻은 후 접근 토큰으로 교환되는 것이다. 요청토큰을 얻는 과정은 다음과 같다.

  1) 요청토큰을 얻기 위하여 컨슈머는 서비스 프로바이더의 요청토큰 URL(Request Token URL)에 HTTP 요청을 한다.
  2) 서비스 프로바이더 문서에 이 요청에 대한 HTTP method가 명시되어 있고 HTTP POST를 권장한다.
  3) 요청은 서명되어(signed) 있어야 하고(서명에 대해서는 아래 2. 서명하기 참조) 다음과 같은 파라미터들을 가지고 있어야 한다.

oauth_cosumer_key : 컨슈머 키
oauth_signature_method : 컨슈머가 요청에 사용한 서명 방법
oauth_signature : 서명 (2. 서명하기 참조)
oauth_timestamp : 1970년 1월 1일 0시 0분 0초 GMT 부터의 초, 양수이어야 하며, 전에 사용된 timestamp 보다 커야한다.
oauth_nonce : 컨슈머에서 생성한 임의적인 문자열. 같은 타임스탬프 내에서는 유일한 값이어야 합니다. reply attack을 막기 위함도 있음.
oauth_version : 1.0 (OPTIONAL, 생략되면 서비스 프로바이더는 1.0으로 간주한다.)
서비스 프로바이더가 정의하는 추가적인 파라미터들    


B. 서비스 프로바이더는 인증이 안된 요청토큰을 발급한다.
  1) 서비스 프로바이더는 서명과 컨슈머 키를 확인한다. 
  2) 서명과 컨슈머 키에 문제가 없으면, 요청토큰과 토큰 비밀번호(Token Secret)을 생성해서 HTTP body를 통해서 컨슈머에게 리턴한다. 
  3) 서비스 프로바이더는 사용자가 성공적으로 사용자 인증을 통하여 접근을 허용하기 전까지 요청토큰이 접근토큰으로 교환되지 않도록
      보장해야 한다.
  4) 응답에 포함되는 내용은 다음과 같다.

oauth_token : 요청 토큰 키
oauth_token_secret : 요청 토큰 비밀번호
oauth_callback_confirmed : true로 설정되있어야 함. 컨슈머는 이것을 서비스 프로바이더가 콜백 값을 받는 것을 승인하는데
                                       사용할 수 있음
서비스 프로바이더가 정의하는 추가적인 파라미터들    


C. 사용자 인증 획득
컨슈머는 사용자가 인증 해줄 때까지 요청토큰을 사용할 수 없다. 사용자 인증은 다음과 같은 과정을 거친다.

C.1. 컨슈머는 사용자를 서비스 제공자쪽으로 보낸다.(redirect)
  1) 컨슈머가 요청 토큰을 접근 토큰으로 교환하기 위해서는 요청 토큰에 사용자의 승인을 얻어야 한다. 컨슈머는 서비스 프로바이더의
    사용자 인증 URL(Authorize URL)을 다음 파라미터를 붙여서 HTTP GET 요청을 구성할 수 있다. 
  2) 컨슈머가 인증 URL로 리다이렉트를 할 수 없는 경우에는 사용자에게 인증을 위해 Authorize URL로 접속할 것을 알려준다. 
  3) Authorize URL의 예

  4) 인증 URL로의 요청은 다음과 같은 파라미터들를 포함한다.(GET 요청 파라미터로)

oauth_token : OPTIONAL. 이전 단계에서 획득한 요청 토큰, 서비스 프로바이더는 필수 파라미터로 정의할 수도 있고, 제외할 수도 있다.
                    제외할 경우 사용자로부터 직접 입력하도록 하여 받아들일 수도 있다.
oauth_callback : OPTIONAL. 인증을 마친 후 되돌아갈 URL
서비스 프로바이더가 정의하는 추가적인 파라미터들

C.2. 서비스 프로바이더는 사용자를 확인하고, 동의를 받는다.
서비스 프로바이더는 사용자의 신원을 확인하고 상세사항에 대하 동의를 구한다. OAuth는 서비스 프로바이더가 어떻게 사용자를 인증해야
되는지에 대해서 세세히 설명하지 않는다. 다만 다음과 같은 과정을 거쳐야 한다.

  1) 서비스 프로바이더는 동의를 구하기 전에 사용자의 신분을 확인한다. 로그인 하지 않았다면 로그인 화면을 보게 된다. 
  2) 서비스 프로바이더는 컨슈머가 접근 요청을 하는 사용자의 정보에 대해 표시한다. 이 정보에는 보호 접근 자원과 접근 기간을 포함한다.
  3) 사용자는 서비스 프로바이더에게 컨슈머가 보호된 자원을 사용할 것을 허가하거나 거부할 수 있다. 만약 사용자가 거부한다면,
     서비스 제공자는 보호된 자원으로의 접근을 허가해서는 안된다. 

D. 서비스 프로바이더는 사용자를 컨슈머에게 돌려 보낸다.
  1) 서비스 프로바이더에서 컨슈머의 접근을 허용하는 사용자 인증 후 컨슈머는 Reqest 토큰은 인증되었고, Access 토큰으로 교환할 준비를
     한다는 내용을 알리고, 사용자가 접근을 거부했으면 컨슈머는 Request 토큰이 파기되었다는 것을 알려야 한다. 
  2) 컨슈머가 oauth_callback 으로 callback URL을 제공한 경우에는 서비스 제공자는 다음의 파라미터와 함께 callback URL로 HTTP GET
     요청을 만들어 리다이렉트 시킨다.

oauth_token : 사용자가 승인 혹은 거부한 요청 토큰
oauth_verifier : 검증 코드

  3) callback URL에는 컨슈머가 제공한 파라미터를 포함하고 있어야 한다. 서비스 프로바이더는 파라미터를 수정해서는 안되며, 
      oauth_token 파라미터만 추가한다.
      callback URL이 없는 경우에는 사용자에게 인증이 끝났으며, consumer로 돌아가 계속 진행할 것을 공지한다. 

E. 접근토큰 획득
컨슈머는 요청 토큰을 보호된 리소스에 접근할 수 있는 접근 토큰으로 교환한다. 접근토큰을 얻는 과정은 다음과 같다.

E.1. 컨슈머가 접근토큰 요청
  1) 요청토큰과 토큰 비밀번호(Token Secret)는 접근 토큰과 토큰 비밀번호(Token Secret)로 교환된다.
  2) 접근 토큰을 요청하기 위해 컨슈머는 서비스 프로바이더의 접근토큰 URL에 HTTP 요청을 한다.
  3) 서비스 프로바이더는 이 요청에 대한 HTTP method를 명시한다. (HTTP POST방식을 권장한다.)
  4) 이 요청은 요청서명으로 서명되어(signed) 있어야 하고(서명에 대해서는 아래 2. 서명하기를 참조) 다음과 같은 파라미터들을 포함한다.

oauth_cosumer_key : 컨슈머 키
oauth_token : 인증된 요청 토큰
oauth_signature_method : 컨슈머가 요청에 사용한 서명 방법
oauth_signature : 서명 (2. 서명하기를 참조)
oauth_timestamp : 1970년 1월 1일 0시 0분 0초 GMT 부터의 초, 양수이어야 하며, 전에 사용된 timestamp 보다 커야한다.
oauth_nonce : 컨슈머에서 생성한 임의적인 문자열. 같은 타임스탬프 내에서는 유일한 값이어야 합니다. reply attack을 막기 위함도 있음.
oauth_version : (OPTIONAL) 1.0, 생략되면 1.0으로 간주
oauth_verifier : 이전 단계에서 서비스 프로바이더로 부터 받은 검증 코드

F. 서비스 프로바이더는 접근토큰을 발급한다.
서비스 제공자는 다음을 꼭 확인해야 한다.
  1) 요청 서명은 정확히 검증되어야 한다.
  2) 요청 토큰은 접근 토큰으로 교환된 적이 없어야 한다.
  3) 요청 토큰은 컨슈머 키와 동일해야한다.

위 조건이 만족되면, 서비스 프로바이더에서 접근 토큰과 토큰 시크릿이 생성되면 서비스 프로바이더 응답 파라미터를 HTTP response
body에 담아 리턴한다. 접근 토큰과 토큰 시크릿은 컨슈머에 저장되고, 보호된 리소스를 요청하는데 사용한다.
응답은 다음의 파라미터를 포함한다.

oauth_token : 접근 토큰
oauth_token_secret : 토큰 비밀번호
서비스 프로바이더가 정의하는 추가적인 파라미터들

검증이 실패하거나 다른 이유로 거절되면 서비스 프로바이더는 HTTP Respond Code를 사용하여 응답해야 한다.
서비스 프로바이더는 요청이 거절된 이유를 HTTP response body에 담아 서비스 프로바이더 응답 파라미터로 나타낼 수 있습니다.

G. 보호된 자원에 접근
접근토큰과 토큰 시크릿을 발급받은 후 컨슈머는 사용자의 보호된 자원에 접근할 수 있다.
요청은 서명되어(signed) 있어야 하며, 다음과 같은 파라미터들을 가지고 있어야 한다. 

oauth_cosumer_key : 컨슈머 키
oauth_token : 접근 토큰
oauth_signature_method : 컨슈머가 요청에 사용한 서명 방법
oauth_signature : 서명 (2. 서명하기를 참조)
oauth_timestamp : 1970년 1월 1일 0시 0분 0초 GMT 부터의 초, 양수이어야 하며, 전에 사용된 timestamp 보다 커야한다.
oauth_nonce : 컨슈머에서 생성한 임의적인 문자열. 같은 타임스탬프 내에서는 유일한 값이어야 합니다. reply attack을 막기 위함도 있음.
oauth_version : (OPTIONAL) 1.0, 생략되면 1.0으로 간주
서비스 프로바이더가 정의하는 추가적인 파라미터들  


2. 서명하기(HMAC-SHA1을 이용)
모든 토큰요청과 보호된 자원에 대한 요청은 컨슈머에 의해 서명되어져야 하고 서비스 프로바이더로 부터 검증되어야 한다.
요청 서명의 목적은 토큰이나 보호된 리소스를 요청할 때 인증되지 않은 서명자의 컨슈머 키와 토큰 사용을 방지하는 것이다.
사인 과정은 컨슈머 시크릿을 인코딩하고, 토큰 시크릿을 요청에 포함된 검증 가능한 값으로 넣는 것이다.

OAuth는 특정 서명 메소드를 지정하지 않는다. 각각 구현의 고유한 요구사항을 가질 수 있다.
프로토콜은 HMAC-SHA1, RSA-SHA1, PLAINTEXT 세 가지의 서명 메소드를 정의하지만 서비스 프로바이더는 새로 구현해서 사용할 수 있고,
특정 메소드를 추천하지는 않는다.
컨슈머는 서명 메소드를 oauth_signature_method 파라미터에 선언하고, 생성한 서명(Signature)을 oauth_signature 파라미터에 저장한다.
서비스 프로바이더는 지정된 메소드로 Signature를 검증한다. 컨슈머의 Signature를 검증할 때 서비스 프로바이더는 요청 nonce가
이전 컨슈머 요청에 사용되지 않았는지 확인해야 한다.
서명 과정은 요청 oauth_signature 파라미터를 제외하고 파라미터의 이름과 값을 절대 바꾸지 않는다.

2.1 서명 기반 문자열(Signature Bse String)
서명 기본 문자열은 일관적으로 재생가능한 단일 문자열 요청요소의 연결이다. 문자열은 해싱이나 서명 알고리즘의 입력으로 사용된다.
HMAC-SHA1 서명 메소드는 표준과 signature를 생성하기 위한 서명 알고리즘과 함께 서명 기본 문자열 예시를 제공한다.
모든 요청 파라미터는 서명 기본 문자열을 생성하기 전에 파라미터 인코딩(OAuth 인증 개념의 7번 참조)에 설명된 데로 인코딩되야 한다.

1. 요청 파라미터 표준화
요청 파라미터는 정렬, 결합되서 표준화된 문자열에 수집된다.
  - realm 파라미터를 제외한 OAuth HTTP 인증 헤더의 파라미터
  - HTTP POST request body의 파라미터(application/x-www-form-urlencoded의 content-type 포함)
  - URL의 쿼리 파라미터 부분에 추가된 HTTP GET 파라미터

oauth_signature 파라미터는 반드시 제외한다.

파라미터를 단일 문자열로 표준화하면 다음과 같다.
  1) 파라미터는 이름의 오름차순으로 정렬한다. 같은 이름이 있으면 값에 의해 정렬한다.

예) a=1, c=hi%20there, f=25, f=50, f=a, z=p, z=t

  2) 정렬된 파라미터를 단일 문자열로 연결시킨다. 각 파라미터는 값과 '='(ASCII 코드 61)로 분리되어 있다, 비어있는 값도 적용한다.
      각 이름-값 쌍을 '&'(ASCII 코드 38)로 분리한다.

예) a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t

2. 요청 파라미터 구성
서명 기본 문자열은 특정 종단 요청의 절대 URL을 포함한다. URL은 서명 기본 문자열에서 스키마, 권한, 경로를 포함시키고, 쿼리와 단편들을
제외시키는데 사용한다.
절대 요청 URL을 서비스 프로바이더에 사용할 수 없다면(컨슈머에는 항상 가능) HTTP Host header와 관련된 HTTP 요청 URL을 사용하고
있는 스키마와 조합해서 생성할 수 있다. Host header를 사용할 수 없다면 서비스 프로바이더는 컨슈머에서 문서나 다른 방법으로 전달된
host 이름을 사용해야 한다.
서비스 프로바이더는 URL 표준화를 하는 동안 모호함을 피하기 위해 서명 기본 문자열에 사용하는 URL 형태를 제공해야 한다.
정리된 것을 제외하고는 URL스키마와 권한은 소문자로 표시하고 포트번호를 포함하는데 http의 기본 포트인 80과 https의 기본 포트인 443은
제외한다.
다음과 같은 요청은

다음과 같이 서명 기본 문자열에 포함된다. 즉 query 부분(?와 그 뒷부분)은 제외한 URL 부분 

3. 요청 요소 연결
다음 아이템들은 단일 문자열로 반드시 연결되야 한다. 각 아이템은 인코딩되야 하고, 값이 비어있더라도  '&'(ASCII 코드 38)로 구분되야
한다. 
  1) HTTP 요청 메소드는 요청을 보내는데 사용된다. 값은 반드시 다음과 같이 대문자여야 한다 : HEAD, GET, POST, 등
  2) 요청 파라미터 구성(앞단계)에서 생성된 요청 URL 
  3) 요청 파라미터의 표준화에서 표준화된 요청 파라미터 문자열

4. HMAC-SHA1, RSA-SHA1, PLAINTEXT
다음 페이지 참고 :
http://oauth.net/core/1.0/ 9.2 HMAC-SHA1, 9.3 RSA-SHA1, 9.4 PLAINTEXT 또는
https://apis.daum.net/oauth/main/welcome 의 중하단 부분


서명 기본 문자열 예제 (HMAC-SHA1 사용)
  1) 서명을 만들기 위해서는 우선적으로 서명 기본 문자열을 생성해야 한다. 요청은 다음 파라미터(oauth_signature 제외)를 포함한다.

oauth_consumer_key: dpf43f3p2l4k3l03
oauth_token: nnch734d00sl2jdk
oauth_signature_method: HMAC-SHA1
oauth_timestamp: 1191242096
oauth_nonce: kllo9940pd9333jh
oauth_version: 1.0
file: vacation.jpg
size: original

  2) 서명 기본 문자열을 생성할 때 다음 입력들이 사용된다.

GET (HTTP 메소드)
http://photos.example.net/photos (파라미터를 제외한 절대 경로)
file=vacation.jpg
&oauth_consumer_key=dpf43f3p2l4k3l03
&oauth_nonce=kllo9940pd9333jh
&oauth_signature_method=HMAC-SHA1
&oauth_timestamp=1191242096
&oauth_token=nnch734d00sl2jdk
&oauth_version=1.0
&size=original


  3) 생성된 서명 기본 문자열 (위의 3가지를 URL 인코딩한 후 &로 연결)

GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal

  4) Signature 값 계산
HMAC-SHA1로 base64 인코딩해서 다음의 Signature를 만들어 낸다. (text로는 서명 기본 문자열을, key로는 kd94hf93k423kf44&pfkkdhi9sl3r4s00(컨슈머 시크릿 & 토큰 시크릿)를 사용)

tR3+Ty81lMeYAr/Fid0kMTYa/WM=

  5) 보호된 자원 요청 (쿼리 파라미터로만 표현)

http://photos.example.net/photos?file=vacation.jpg
&size=original
&oauth_consumer_key=dpf43f3p2l4k3l03
&oauth_token=nnch734d00sl2jdk
&oauth_signature_method=HMAC-SHA1
&oauth_signature=tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D
&oauth_timestamp=1191242096
&oauth_nonce=kllo9940pd9333jh
&oauth_version=1.0


[참고]
http://oauth.net/core/1.0/
https://apis.daum.net/oauth/main/welcome

크리에이티브 커먼즈 라이선스
Creative Commons License