til icon indicating copy to clipboard operation
til copied to clipboard

OAuth

Open raycon opened this issue 4 years ago • 1 comments

https://www.oauth.com/

OAuth

Background

  • 기존에 앱을 사용하기 위해 아이디, 비밀번호를 앱에 제공한다.
  • 비밀번호를 평문으로 저장하기 때문에 보안에 문제가 있다.
  • 앱이 서비스에 접근하는것을 취소하려면 비밀번호를 바꾸는 방법 밖에 없었다.
  • 플리커, 구글, 페이스북, 야후 등 여러 서비스가 각각의 인증 방식을 만들었고, 서로 호환되지 않았다.
  • 2006년 11월 무렵 트위터의 Blaine Cook 수석 아키텍트가 서드파티 앱에 사용자의 패스워드를 제공하지 않는 방법을 찾기 시작했다.
  • 2007년 OpenID를 개발했던 사람들이 참여해서 API 표준을 만들기 위한 메일링 리스트를 만들었다.
  • 2007년 8월 OAuth 1 초안이 발표되었고, 7번의 업데이트를(draft) 통해 연말에 Internet Identity Workshop 에서 확정(final)됐다.
  • 1.1 버전은 IETF working group에서 논의를 시작했으나, 2.0에 집중하기 위해 중단됐다.
  • 1 버전은 모바일 앱에서 안전하게 구현할 수 없다.
  • 2 버전은 최근의 모바일 앱 유즈 케이스를 지원하고, API를 단순화 했다.
  • 2 버전은 IETF 워킹 그룹에서 시작되었고, 웹과 엔터프라이즈 컨트리뷰터 사이의 갈등을 겪었다.
  • 이러한 부분은 별도의 문서로 분리되었고, 프로토콜에서 프레임워크로 이름이 변경됐다.
  • 오늘날 2.0을 구현하려는 사람은 여러 RFC 문서와 초안을 봐야하며, 스펙이 정해주지 않은 사항을 스스로 결정해야 한다.
  • 이를 구현한 서비스들이 대개 비슷한 방식을 사용하고 있다.

Getting Ready

  • OAuth 2.0 서비스를 사용하려면 개발자로 계정을 생성하고 앱을 등록해야한다.
  • 앱을 등록할 때 Redirect URL을 등록해야한다. 그렇지 않을 경우 악의적인 어플리케이션이 사용자 데이터를 탈취할 수 있다.
  • Redirect URL은 여러개를 등록해서 웹, 모바일 앱에서 사용하거나, 개발, 운영 환경에서 사용할 수 있다.
  • Redirect URL은 https를 사용해야 한다.
  • Redirect URL은 정확히일치해야 한다. 쿼리 파라미터(?destionation=account)를 사용하지 않는게 Best Practice
  • 요청마다 Redirect URL을 다르게 지정하는 대신 state를 사용해서 인증 과정이 끝난 뒤 적절한 위치로 이동할 수 있다.

Accessing Data in an OAuth Server

  • 깃헙 개발자 페이지에서 새로운 앱을 등록할 수 있다.
  • 깃헙은 하나의 앱에 하나의 Redirect URL만 지원하기 때문에, 개발, 운영을 분리하고 싶을 경우 두개의 앱을 만들어야 한다.
  • Client ID 는 공개적인 정보다.
  • Client Secret 은 코드에 입력하거나 저장소에 커밋하면 안된다.

Authorization Request

  • state: 클라이언트가 생성하고 세션에 저장하는 랜덤한 문자열이다. 클라이언트는 깃헙으로부터 다시 전달 받은 state 값을 통해 위변조 여부를 확인할 수 있다.
  • 인증이 완료되면 사용자는 redirect_url로 이동하며 code, state 쿼리 파라미터가 함께 전달된다.

Obtaining an Access Token

  • state 값을 세션에 저장된 값과 비교한다.
  • code를 가지고 Access Token 발급 API를 호출한다. 이때 client_secret을 입력한다.
  • 발급된 토큰을 세션에 저장하고 적절한 페이지로 이동한다.
  • 사용자가 다음에 페이지에 다시 방문할 경우, 세션에 토큰이 있으므로 로그인한 사용자를 위한 뷰를 보여줄 수 있다.
  • 깃헙이 반환하는 에러에 맞는 적절한 대처를 해야한다.

Making API Requests

  • Authorization 헤더에 Bearer ACCESS_TOKEN 을 지정해서 깃헙 API를 호출할 수 있다.

Signing in with Google

  • Authentication: 자신이 누구라고 주장하는 사람을 확인하는 절차 (인증)
  • Authorization: 가고 싶은 곳으로 가도록 혹은 원하는 정보를 얻도록 허용하는 과정 (허가)
  • OAuth은 Authorization을 위해 설계 되었기때문에, OAuth 플로우의 결과물은 사용자 계정의 어떠한 것을 접근하거나 수정하는 Access token 이다.
  • Access Token 자체는 사용자가 누구인지에 대한 정보를 포함하고 있지 않다.
  • 사용자가 누구인지 확인하는 방법으로 user info API를 만들어서 사용자의 프로필을 전달하는 방식이 널리 쓰이지만, 이 방식은 OAuth 표준이 아니다.
  • 좀 더 진보적이고 표준화된 접근 방식은 OAuth 2.0 익스텐션인 OpenID Connect를 사용하는 것이다.

Create an Application

  • 깃헙과 마찬가지로 구글 개발자 콘솔에서 앱을 생성하고 Client ID, Secret을 발급 받는다. Redirect URL도 등록 한다.

Authorization Request

  • 사용자의 데이터에 접근하지 않고, 누구인지만 확인하기 위해 Authorization 요청에 scope 값을 openid email로 지정한다.
  • 사용자는 권한과 관계 없이 계정을 선택하는 화면을 보게 된다.
  • 사용자가 계정을 선택하면 redirect_url로 이동하며 code, state 쿼리 파라미터가 함께 전달된다.

Getting an ID Token

  • code를 사용해서 구글 토큰 API를 호출한다.
  • 구글은 요청을 검증하고, access_tokenid_token값을 응답한다.
  • access_token은 API 요청을 만들 때 사용할 수 있다는 점을 제외하고 우리의 앱에 큰 의미가 없다.
  • id_token은 JWT다.

Verifying the User Info

  • 일반적으로 ID Token은 내부의 정보를 신뢰하기 전에 토큰을 먼저 검증을 해야 한다.
  • 요청을 인증하기 위해 Client Secret을 사용하여 Google에 대한 HTTPS 연결에서 ID Token을 얻었으므로, 획득한 ID Token이 공격자가 아닌 서비스에서 온 것이라고 확신 할 수 있다.
  • ID Token을 서비스 내부의 다른 컴포넌트에서 사용할 경우에는 유효성을 검증해야 한다.
  • JWT 토큰은 Header.Payload.Signature로 구성된다. Payload 부분은 BASE64로 인코딩된 JSON 문자열이다.
  • ID Token의 Payload에서 sub (subject) 항목은 사용자를 식별하는데 사용되며, 이를 세션에 저장한다.
  • access_tokenid_token도 나중에 사용하기 위해 세션에 저장한다.

Using the ID Token to Retrieve User Info

  • 구글은 ID Token의 값을 조회하기 위한 tokeninfo API 를 제공한다.
  • https://www.googleapis.com/oauth2/v3/tokeninfo
  • 추가적인 네트워크 호출이 발생하므로, 개발용으로만 사용하는 것이 좋다.
  • 응답은 ID Token의 Payload 와 유사하다.

Using the Access Token to Retrieve User Info

  • Access Token을 사용해서 사용자 정보를 조회하는 userinfo API 를 제공한다.
  • https://www.googleapis.com/oauth2/v3/userinfo
  • 이 사항은 OpenID Connect 표준의 일부다.
  • sub를 포함한 사용자 이름, 프로필 사진, 이메일, 지역 정보와 같은 추가적인 정보를 확인할 수 있다.

Server-Side Apps

  • 서버사이드 앱은 소스 코드가 공개되지 않기 때문에 Client Secret 을 안전하게 보관할 수 있다.
  • 사용자가 앱을 허가하면 authorizaton_code를 전달 받는다.

Authorization Code Grant

  • Authorization Code 는 Access Token 을 발급 받기 위한 임시 코드다.
  • Authorization Code + Client Secret => Access Token

OAuth Security

  • 새로운 서버를 구현한다면, PKCE 를 지원하도록 구현해야한다.

Authorization Request Parameters

Authorization 요청은 다음과 같은 쿼리 파라미터가 필요하다.

  • response_type=code
  • client_id
  • redirect_url (optional)
  • scope (optional)
  • state
  • PKCE

Exchange the authorization code for an access token

Access Token 발급은 POST 요청으로 이루어지며, 다음과 같은 파라미터가 필요하다

  • grant_type (required): authorization_code
  • code (required): Authorization Code
  • redirect_uri: Authorization 요청에서 전달 되었을 경우, Access Token 요청에서도 전달해야한다.
  • Client Authentication (required): client_id, client_secret를 사용해서 자격을 증명한다.

Possible Errors

Authorization 과정에서 오류가 발생하면 error_description, error_uri 파라미터와 함께 리다이렉트 된다.

  • redirect_url 오류
  • client_id 오류
  • error=access_denied: 사용자가 접근을 거부함
  • 파라미터 오류

Security Considerations

  • Client Secret 값을 보호하지 못하는 경우(모바일 앱, SPA 앱) PKCE를 사용해야 한다.

Single-Page Apps

  • SPA는 Authorization Code 발급까지 동일하고, Access Token 발급에 Client Secret을 쓰지 않는다.
  • 사용자는 브라우저를 통해서 API 서버(OAuth 서버)와 직접 통신한다.
  • Client Secret을 사용하지 않기 때문에, 보안은 state 파라미터와 redirect_url을 사용해서 이루어진다.
  • OAuth 2.0 서비스에서 redirect_url을 등록해야 하는 이유다.

Mobile And Native Apps

  • SPA와 비슷하게 Client Secret 을 사용할 수 없다.
  • 외부 브라우저를 실행해서 Authorization Flow 를 사용하는 것이 최선이다.
  • redirect_uricom.example.app://auth 와 같은 방식으로 지정해서 앱이 실행되도록 한다.
  • WebView를 사용하는 것은 보안에 좋지 않다. 모바일 기본 브라우저(사파리)를 사용하면 기존의 쿠키를 사용할 수 있다.

Making Authenticated Requests

  • Access Token 을 사용하는 방법으로는 HTTP 요청의 Authorization 헤더를 사용하는 방법과, Post 파라미터를 사용하는 방법이 있다.
  • Access Token 은 API 호출하는 용도로만 사용해야 한다. 토큰이 항상 같은 구조를 가진다는 보장이 없으므로 복호화해서 사용하는 것은 위험하다.
  • 토큰이 만료되는 시점을 발급 받을 때 저장하거나, 일단 토큰을 사용해서 요청을 하고 오류가 발생할 경우 갱신하는 방법이 있다.

Refreshing an Access Token

  • refresh_tokenexpires 값을 사용하면 access_token을 사용한 요청이 실패하기 까지 기다리지 않아도 된다.
  • grant_type=refresh_token 으로 지정해서 새로운 access_tokenrefresh_token을 발급 받을 수 있다.
  • 갱신이 실패할 경우 사용자에게 다시 로그인하도록 처리해야한다.

raycon avatar Feb 24 '21 03:02 raycon

https://www.youtube.com/watch?v=996OiexHze0 https://curity.io/resources/architect/oauth/spa-best-practices/#storing-tokens-for-spas

raycon avatar Mar 02 '21 12:03 raycon