OAuth 정리
발생일: 2013.10.18
키워드: OAuth
문제:
보안은 늘 어려운 것 같다.
잘 정리된 문서를 찾기도 어렵고, 있다 하더라도 난 좀 이해하기 어렵더라. @_@
이번에 OAuth 인증 처리가 필요하던 차에, 한빛 소프트에서 나온 EBook을 보게 됐다.
오잉~~ 쉽게 설명되어 있어서 참 좋더라. :D
http://www.hanb.co.kr/ebook/look.html?isbn=9788979149944
책 읽으면서 정리해둔 게 있어 옮겨둔다.
해결책:
서버사이드 웹 애플리케이션
1. 권한 서버로 권한 코드 요청하기
요청 URL 예: https://accounts.google.com/o/oauth2/auth
client_id: 등록한 애플리케이션의 아이디
redirect_uri: 권한 코드 획득 후 리다이렉트할 URI
scope: 요청 데이터의 접근 범위 (API 서버에 따라 컴마나 공백으로 구분)
response_type=code
state: CSRF를 막기위한 1회성 랜덤값
approval_prompt:
사용자가 방문할 때마다 승인받을 것인가? 매번 받으려면 force, 처음만 받으려면 auto
access_type:
사용자가 컴퓨터를 사용하지 않는 동안에도 접근하도록 할 것인가?
그렇다면 offline이고, 이 땐 애플리케이션에서 재발급 토큰을 가져올 수 있다.
online을 사용하면 재발급 토큰은 발급되지 않는다.
---> 이 요청을 보내면 API 서비스의 권한 허용 페이지로 이동한다.
"어떤 앱이 이런이런 권한을 사용하려 합니다. 허용하겠습니까?"의 메시지다.
허용하면, 위에 정의했던 redirect_uri 의 경로로 리다이렉트되며,
이 때 접근 요청을 승인했을 때를 나타내는 권한 코드(code)와 요청에 포함했던 (state)가 함께 전달된다.
2. 권한 코드로 액세스 토큰 발급받기
이제, 전달받은 code와 state로 API 요청을 만들기 위해 권한 코드를 OAuth 액세스 토큰으로 교환해야 한다.
액세스 토큰의 엔드포인트로 HTTP POST 요청을 보내면 된다.
요청에는 아래 파라미터가 필요하다.
code: 애플리케이션에 전달되는 권한 코드
redirect_uri: 권한 엔드포인트에 첫 요청을 보낼 때의 등록된 위치
grant_type=authorization_code: 권한 코드의 액세스 토큰으로의 교환을 의미
헤더에는 client_id와 client_secret을 포함해 보낸다.
- HTTP Basic Authorization 헤더로 (client_id 와 client_secret을 포함하는 방식)
- POST의 파라미터로 client_id와 client_secret을 포함하는 방식
--> 이 요청이 인증되고 다른 파라미터가 유효하면, 권한 서버는 JSON 인코딩 응답에 OAuth 액세스 토큰을 리턴한다.
access_token: API 요청을 허가하는데 사용하는 토큰
token_type: 발급된 액세스 토큰의 타입. 주로 'bearer'가 사용되지만, 확장 가능하다.
expires_in: 토큰은 시간 제약이 있을 수 있다. 이 값은 추가 정보이고 만료되기까지 남은 시간(초)를 의미한다.
refresh_token: 액세스 토큰이 만료된 후 새로운 액세스 토큰을 얻기 위해 사용하는 토큰이다.
재발급 토큰이 있으면 offline 모드에서도 계속 API에 접근할 수 있다.
액세스 토큰과 재발급 토큰은 항상 기밀이 유지되어야 하고,
자원 소유자를 포함한 임의의 사용자에게 노출되지 말아야 한다.
재발급 토큰은 사용자 계정과 연관된 서버사이드 데이터베이스에 저장되어야 한다.
액세스 토큰도 데이터베이스에 저장할 수 있지만, 주로 성능 때문에 세션에 캐시한다.
3. API 호출하기
발급받은 액세스 토큰으로 API에 요청할 수 있다.
이를 전달 토큰(bearer token)이라 하고, 주로 헤더에 넣어 보낸다.
"Authorization: Bearer 액세스 토큰"
4. 액세스 토큰 재발급 받기
액세스 토큰을 발급받을 때 토큰의 만료시간을 계산해 함께 저장해둔다.
다음 요청 시 토큰이 만료되었다면, 재발급 토큰으로 다시 액세스 토큰을 발급받아온다.
* 액세스 토큰과 재발급 토큰
- 액세스 토큰의 유효함을 확인할 때 매번 권한 서버나 데이터베이스에 요청하면 API 응답이 늦어질 수 있다.
이 때문에 주로 서명이나 암호화한 토큰을 사용해 검증 범위를 줄인다.
사용자가 이전에 허가했던 애플리케이션의 접근을 취소할 수 있기 때문에,
API 서비스가 암호화를 사용해 검증하더라도 안전할 수 있게 토큰의 유효 범위를 짧게하는 것이 필요하다.
client_id
client_secret
grant_type=refresh_token
refresh_token: 재발급 토큰
--> 이 응답으로는 access_token, refresh_token, expires_in 을 받음
클라이언트 사이드 웹 애플리케이션
암묵적 허가 플로우를 사용하며 아래 경우에 사용한다.
- 데이터에 접근이 일시적으로 필요할 때
- 사용자가 규칙적으로 API 제공 업체에 로긍니할 때
- OAuth 클라이언트가 자바스크립트, 플래시 등을 사용해 웹 브라우저에서 실행될 때
- 웹 브라우저의 신뢰도가 높고, 신뢰할 수 없는 사용자나 애프리케이션에 노출될 염려가 적을 때
1. 권한 서버로의 요청 파라미터
client_id
redirect_uri
scope
response_type=token (액세스토큰)
--> 권한을 얻으면 redirect_uri 에 정의한 페이지로 이동하면서,
URL에 해시(#) 형태로 access_token과 관련 정보가 추가된다.
http://example.com/callback#access_token=xxx&token_type=Bearer&expires_in=3600
2. API 요청하기
전달받은 access_token 으로 요청을 보내면 된다.
도메인이 다른 경우엔 jsonp로 보낸다.
3. 액세스 토큰 재발급 받기
암묵적 허가 플로우에서는 권한 코드 플로우와 달리 토큰을 재발급하기 위한 특정 프로토콜을 사용하지 않는다.
처음 토큰을 가져올 때와 동일한 방식으로 가져와야 한다.
아직 표준화되지 않았지만, 일부 OAuth 2.0 제공자들은 즉시 모드(immediate mode)를 지원한다.
즉시 모드는 사용자에게 알리지 않고 새로운 액세스 토큰을 투명하게 애플리케이션으로 보낼 수 있도록,
숨겨진 iframe 내에서 토큰 재발급 과정을 허용한다.
주로 `immediate=true`라는 파라미터를 추가로 제공해 해결한다.
자원 소유자 비밀번호 플로우
사용자 이름과 비밀번호를 액세스 토큰으로 교환하고, 재발급 토큰은 선택적으로 사용한다.
다른 OAuth 플로우에 비해 의미있는 보안성을 가지며,
주로 사용자의 강한 신뢰가 바탕이 되어야 한다.
자원 소유자의 비밀번호가 애플리케이션에 노출되기 때문에, 보통 API 제공 업체가 배포한 공식 애플리케이션에만 추천한다.
1. 사용자에게 인증 요청
사용자에게 아이디와 비밀번호를 받아 권한 서버로 요청을 보낸다.
아래 파라미터가 필요하다.
grant_type=password: 이 플로우에서는 'password'라고 기술한다.
scope: 접근 요청할 수 있는 데이터
client_id: (선택) 애플리케이션의 등록 값
client_secret: (선택) 파라미터 이름만 보면 비밀성을 내포하는 듯 하지만, 네이티브 모바일 애플리케이션 같은
공개 클라이언트를 위해서도 API 제공 업체에서 가끔 사용한다.
이런 경우, 파라미터 값은 비밀이 아니어서 애플리케이션 사용자가 발견할 수도 있다.
username: 자원 소유자가 제공하는 사용자 이름(utf-8)
password: 자원 소유자가 제공하는 비밀번호(utf-8)
--> 요청에 성공하면 아래 값을 application/json 형태로 응답한다.
access_token: API 접근에 사용하는 액세스 토큰
id: 사용자의 유일한 식별값.
(예제에서는 URL 형태인데, 사용자에 대한 더 많은 정보를 얻기 위해 OAuth에서 보호되는 자원처럼 접근될 수 있다고 한다. 잘은 모르겠다)
signature: (선택) 서버에 식별 URL을 보낸 후, 이 URL이 변경되지 않았음을 검증하기 위해 사용하는 서명이다.
2. API 호출
마찬가지로 헤더에 "Authorization: Bearer 액세스토큰" 값을 넣어 API를 요청하면 된다.