-
[Spring Boot] OAuth2 (1/2) : 개념 이해서버개발/spring-boot 2020. 1. 21. 11:15
OAuth 란?
OAuth(Open Authorization, Open Authentication)는 사용자 리소스를 관리하는 서비스(구글, 페이스북 등)에서 제3의 애플리케이션에게 사용자의 패스워드 제공 없이 인증, 인가할 수 있는 인증 관련 표준 프로토콜이다. OAuth 이전에 사용자의 권한을 위임받는 방식은 사용자가 이용하는 서비스의 계정/패스워드를 제공받는 방식이었다. 이는 패스워드 유출 뿐 아니라 권한을 위임받는 애플리케이션이 필요 이상으로 계정에 대한 모든 권한을 획득하게 되는 등 다양한 문제점이 존재한다. OAuth 인증은 API를 제공하는 서버에서 사용자 인증 및 권한 부여를 진행하고 이에 대한 'Access Token'을 발급하는 방식을 제공하며 이러한 문제들을 해결할 수 있다.
OAuth2는 OAuth1 프로토콜의 복잡한 인증방식을 단순화 한 것이 가장 큰 특징이다.
OAuth2 기본 지식
용어 정리
Role
OAuth2 워크플로우상의 역할은 4가지로 구분된다
- Resource-Owner : 리소스 소유권을 가진 사람
- Resource-Server : 리소스가 위치한 서버 (ex. google)
- Client : 리소스를 요청하는 애플리케이션
- Authorization-Server : 클라이언트 인증, 토큰 발행 등의 역할을 담당하는 서버
Token
Authorization-Server에 의해 생성되고, 클라이언트의 요청 시점에 발행되는 랜덤 문자열을 의미하며 2가지 타입이 있다.
- Access-Token
: 리소스에 대한 접근을 허용하는 토큰이며, 헤더나 파라미터 등에 담겨 리소스 서버로의 요청에 포함되어야 한다. 만료일이 있으며, Authorization-Server에 의해 정의된다 - Refresh-Token(optional)
: Access-Token 이 만료되기 전에 Authorization-Server에 전송해 토근 기간을 연장하는 데 사용된다.
OAuth2 Type 중에는 Refresh-Token을 허용하지 않는 경우도 있다.
Access token scope(optional)
Access-Token의 접근 범위를 지정한다. 스코프 리스트를 Authorization-Server에서 정의하면, Client에서 리소스 요청 시 이 파라미터를 추가해서 보내야 한다.
권고 사항
HTTPS 사용
OAuth2는 Token, 사용자 자격증명 등 민감 데이터가 요청에 담기게 되기 때문에 HTTPS를 사용하기를 권고한다.
클라이언트 등록 절차 필요
OAuth2를 사용해 리소스를 요청하려면 Authentication-Server에 클라이언트로 등록이 되어야 한다. 이 절차에 대한 승인방법은 OAuth2 제공자(provider)가 정의한다. 클라이언트 등록 절차에 사용되는 가장 기본적인 파라미터는 다음과 같이 정의한다.
*아래 내용은 실제 구현 시 조금씩 차이가 있을 수 있습니다.
클라이언트 등록 요청
- Application Name : 클라이언트 애플리케이션 이름
- Redirect URLs : 인증 코드와 Access-Token을 받을 URL
- Grant Types : 클라이언트에서 사용하는 인증 방식
- Javascript Origin(optional) : XMLHttpRequest를 통해 리소스를 요청할 수 있는 hostnames(javascript level에서 http 호출에 사용되는 객체)
인증서버 응답
- Client Id : 클라이언트 아이디
- Client Secret : 클라이언트 시크릿
OAuth2 인증 방식 4 Type
토큰을 획득하는 데 있어 클라이언트의 위치, 특성에 따라 4개의 승인 타입을 제공한다.
1. 권한 코드 (Authorization grant types)
사용
클라이언트가 웹서버인 경우 주로 사용된다. Refresh-Token(을 Authorization-Server에서 구현한 경우)에 의해 갱신되기 전까지 사용 가능한 기간이 긴(longlived) Access-Token을 허용한다.
예시
- Resource-Owner : Alice
- Resource-Server : 구글
- Client : 웹 사이트
- Authorization-Server : 구글 인증서버
시나리오
- 웹사이트가 Alice의 구글 프로필 정보를 획득하려 한다.
- 웹사이트에서 Alice를 구글 인증 페이지로 redirecting 시킨다.
- Alice가 승인하면, 구글 서버에서 웹사이트로 인증 코드를 보낸다.
- 클라이언트는 이 코드를 구글 인증서버에 보내 Access-Token을 받는다.
- 이후 웹 사이트는 Access-Token을 통해 Alice의 구글 프로필 을 가져온다.
특징
- Alice는 Access-Token 을 볼 수 없다. 이 값은 웹사이트(Client)에 저장된다. -> ex. 세션
- 구글 인증서버는 Access-Token과 더불어 Refresh-Token 도 제공할 수 있다.
- 토큰은 웹사이트의 브라우 저단으로 넘기지 않는 것이 안전하다.
2. 암묵적 허가 (Implicit grant)
사용
클라이언트가 웹 브라우저에서 실행되는 경우 사용된다. 이 타입은 Refresh-Token을 허용하지 않는다.
예시
- Resource-Owner : AliceResource-Server : 페이스북
- Client : 웹 사이트 (AngularJS로 개발된)
- Authorization-Server : 페이스북 인증 서버
시나리오
- 웹사이트가 Alice의 페이스북 프로필 정보를 획득하려 한다
- 웹사이트에서 Alice를 페이스북 인증 페이지로 redirecting 시킨다.
- Alice가 승인하면, 페이스북 인증서버가 Alice를 웹 사이트로 redirecting 시키는데, 이때 URL에 Access-Token을 담아 보낸다.
- 이후 웹 사이트는 Access-Token 을 통해 Alice의 페이스북 프로필을 가져온다.
특징
- Token 은 웹서버로 보내지는 것이 아니기에 URL로 노출된다.
- CORS(Cross Origin Resource Sharing) 이슈가 발생하지 않는 이유는 페이스북에서 헤더에 Access-Control-Allow-Origin을 담아 보내기 때문이다.
- refresh-Token을 허용하지 않는다.
3. 자원 소유자의 비밀번호 기반 허가 (Resource Owner Password Credentials Grant)
Resource-Owner의 ID/PW를 OAuth Access-Token으로 교환할 수 있게 한다.
사용
클라이언트가 인증서버와 동일한 권한을 가지도록 개발된 경우 주로 사용된다. 예를 들어, 특정 웹사이트 (example.com)에서 API 서버를 오픈하는 경우(api.example.com) 클라이언트와 인증서버는 동일한 권한을 가지고 있다고 볼 수 있다.
예시
- Resource-Owner : Alice (academy.com에 계정을 가지고 있는 사용자)
- Resource-Server : api.academy.com (오픈한 APIs)
- Client : academy.com
- Authorization-Server : academy 인증 서버
시나리오
- 아카데미에서 관계사에 제공할 API 서버를 오픈했다. 이 API는 Access-Token을 사용한다.
- api.academy.com에 접근하면 academy.com의 로그인 페이지로 redirecting 한다.
- Alice가 로그인하면 아카데미 서버는 로그인 정보와 Access-Token을 교환한다.
- 이후 api.academy.com에서는 이 토큰을 통해 리소스를 요청해 사용한다.
특징
- 사용자의 패스워드가 클라이언트로 전송된 후, 인증서버로 다시 전송된다.
4. 클라이언트 인증서(Client Credentials Grant)
클라이언트가 자원을 소유하고 있거나 권한이 권한 서버에서 미리 준비되어 있을 때 주로 사용된다. 이 방식은 특정 사용자의 권한을 대행하는 방식보다는 저장 서비스나 데이터베이스를 대신하여 API를 사용하려는 애플리케이션에 적합하다.
사용
클라이언트가 Resource-Owner 인 경우에 사용한다. 따라서 엔드유저로부터의 인증이 생략된다.
예시
- Resource-Owner : 웹 사이트
- Resource-Server : 구글 클라우드 스토리지
- Client : 웹 사이트(Resource-Owner와 동일)
- Authorization-Server : 구글 인증서버
시나리오
- 웹 사이트가 파일을 구글 스토리지에 저장하는 방식으로 개발되어 있다.
- 웹 사이트는 구글 인증서버를 통해 인증하고 토큰을 발급받는다.
- 발급받은 토큰을 이용해서 웹 사이트가 구글 API를 통해 파일을 읽고 쓸 수 있게 된다.
특징
- redirect 시킬 URL 이 필요 없다.
- Refresh-Token은 권장되지 않는다. 의미가 없기에 구현할 필요가 없다.
(ex. 키 클락의 경우 refresh-token을 사용하려 하면 에러 발생)
잘못된 구현으로 인한 인증코드 부여 방식의 취약성
OAuth2 프로토콜을 제대로 구현하지 않는 경우 마주하게 될 문제들을 몇 가지 살펴보자.
1. 권한 코드 방식의 취약성
시나리오
- 피해자가 취약한 웹 사이트 A에 계정을 가지고 있는 상황으로 가정한다.
- A에서는 사용자가 가입할 때 페이스북 계정으로 가입할 수 있는 기능이 있다.(즉, A는 페이스북 인증서버의 클라이언트로 등록되어 있다.
- 공격자는 A에서 제공하는 페이스북 연결 기능을 클릭하지만, 별도의 장치를 통해 리다이렉션을 막는다.
(ex. 파이어폭스의 NoRedirect 플러그인 등) - 공격자는 클라이언트 인증코드를 담고 있는 리다이렉션 URL을 획득한다.
- 이후 공격자는 (어떤 수단을 써서라도) 피해자가 해당 URL 을 통해 로그인을 하도록 한다.
- 피해자가 탈취된 URL로 로그인을 하게 되면, 이후 공격자의 페이스북 계정과 피해자의 A사이트 계정이 연동되게 되며, 이후 공격자는 자신의 페이스북 계정을 통해 A의 피해자 계정을 제어할 수 있게 된다.
예방
state 매개변수를 추가하는 것으로 해결할 수 있다. 일반적으로 사용자의 세션의 임의의 수를 해싱한 값이 함께 들어가도록 한다. 이러한 장치를 통해 만약 로그인 시도 환경이 달라지게 되는 것을 인증서버에서 확인할 수 있게 된다.
2. 암묵적 허가 방식의 취약성
시나리오
- 공격자가 취약한 A 사이트의 사용자 정보를 해킹하려는 상황이다.
- A에서는 페이스북 로그인 기능이 존재한다.
- 공격자는 B를 만들어 똑같이 페이스북 로그인 기능을 추가한다.
- 피해자는 B에서 페이스북 로그인을 시도하고 이로 인해 Access-Token이 발급된다.
- 공격자는 이 토큰을 A사이트에서 이용한다.
예방
토큰 정보에 ClientID를 포함하고 이를 체크하는 장치를 추가한다.
3. Clickjacking
시나리오
- 공격자가 투명한 Iframe을 이용해서 인증 페이지를 숨긴다. 따라서 해당 페이지에는 눈에 보이지 않는 인증 허가 버튼이 숨겨지게 된다.
- 공격자는 피해자가 눈에 보이지 않는(하지만 버튼이 존재하는) 위치를 피해자가 클릭하도록 유도한다.
예방
인증서버는 인증 페이지에 X-Frame-Options : DENY, SAMEORIGIN 등을 설정해서 이를 예방한다.
참고자료
- RFC 6749(OAuth2) : https://tools.ietf.org/html/rfc6749#section-4.1
'서버개발 > spring-boot' 카테고리의 다른 글
[Spring Boot] JPA (2/4) : JPA 기본 개념 (0) 2020.01.30 [Spring Boot] JPA (1/4) : SQL/NoSQL 차이점 (0) 2020.01.29 [Spring Boot] HTTP/HTTPS (1/2) : 개념 이해 (1) 2020.01.21