: OAuth 2.0(Open Authorization 2.0) 인증은 페이스북, 구글, 네이버 등에서 사용할 수 있는 사용자 인증 방식이다. 대표적인 OAuth 2.0의 예가 특정 서비스를 로그인할 때 회원 가입을 하지 않고 페이스북이나 네이버 아이디로 로그인을 하는 것이다.

 

※ OAuth 2.0 주체

- Client : 개발자가 만들고 서비스하고 있는 웹/앱

- Resource Owner : Client를 사용하는 서비스 사용자

- Resource Server : Owner의 리소스(데이터)를 가지는 페이스북, 구글, 트위터, 네이버 등의 서버

=> Owner가 Resource Server에 저장한 데이터를 Client에서 사용하고자 할 때 OAuth 2.0 방식을 이용한다.

 

※ OAuth 2.0 구현 절차

: 사용자의 구글 캘린더 정보를 앱에 불러오는 절차를 볼 것이다.

 

1. 클라이언트를 구글(Resource Server) API 콘솔에서 OAuth 인증에 등록한다. 등록하면 구글에서 Client ID와 Client secret 값을 발급해준다. 클라이언트는 2개의 값을 저장하고 특히, Client secret 값은 외부에 절대 노출되서는 안 된다.

 

2. 사용자(Resource Owner)가 Client의 구글 캘린더 정보가 필요한 페이지에 접속한다.

 

3. Client는 사용자에게 구글 캘린더 정보가 필요하다는 문구를 담는 인증 요청 페이지를 보여준다.

 

4. 사용자가 인증 요청에 대해 승인하면 Client는 Resource Server(구글)에 접속하고 구글은 사용자에게 로그인 화면을 보여준다. 구글 로그인 화면은 Client가 별도로 개발하지 않아도 된다.

 

5. 사용자가 로그인에 성공했다면 Client가 요구하는 Scope를 보여준다. Scope는 Client가 필요로 하는 정보를 일컫는다. 여기서는 Scope는 구글 캘린더 정보이다. 따라서 사용자는 "현재 이 Client가 Resource Server 구글의 캘린더 정보를 사용하려고 합니다. 동의합니까?"와 같은 문구를 보게 된다.

 

6. 사용자가 허락하면 Resource Server는 Client에게 Code값을 전송한다. Code값은 사용자(Resouce Owner)가 Client에게 Resource Server 구글의 캘린더 정보의 제공을 승인했다는 정보를 가진다.

 

7. Client는 Code값, Client ID, Client secret 값을 Resource Server 구글에 보낸다. Resource Server 구글은 받은 정보를 토대로 사용자 Resource Owner가 정보를 제공하기로 승인한 Client가 맞는지 검증한다.

 

8. 검증 결과가 유효하다면 Resource Server는 Client에게 Access Token을 발급한다. Client는 Access Token을 DB 등에 보관하고 Access Token을 이용해서 Resource Server 구글 캘린더 정보를 요청한다.

 

9. Resource Server 구글은 Client가 보낸 Access Token을 보고 자기가 발급한 적이 있는 Token 값이면 Resource Owner의 캘린더 정보를 Client에게 보낸다.

 

OAuth 2.0의 절차에 대해서 알아보았다. 몇 몇 절차에 대한 세부적인 내용을 알아보겠다.

먼저 4번 절차에서 사용자가 인증 요청에 대해 승인을 하면 다음 형식의 URL을 전송하면 된다. 그러면 구글 로그인 화면이 자동으로 나온다.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 state=state_parameter_passthrough_value&
 redirect_uri=http%3A%2F%2Foauth2.example.com%2Fcallback&
 response_type=code&
 client_id=client_id

scope는 5번 절차에서 설명했다. scope에 들어가는 값은 구글 API 콘솔 사이트에 나와있다. access_type은 online과 offline이 있다. Access Token은 Client가 계속 가지고 있으면 유출도 될 수 있고 Resource Owner 사용자가 Client에게 정보 제공을 거절하고 싶을 때 문제가 발생한다. 따라서 Access Token은 수명을 가진다 보통 1시간이다. 그래서 수명이 끝나면 Access Token은 사라지기 때문에 다시 Resource Owner 사용자에게 승인 허가를 받고 Resource Server에 다시 Access Token을 받아야 한다. 이러한 절차를 반복하는 것은 비효율적이기에 만약 access_type을 offline으로 하면 Resource Server는 Access Token을 줄 때 Refresh Token도 같이 준다. Refresh Token은 Access Token이 수명을 다해 사라지면 Client가 Resource Server에게 Refresh Token을 보내 Access Token을 다시 받을 수 있다. 단, Refresh Token은 Access Token을 처음 받을 때만 받을 수 있다. redirect_url은 code 값을 Resource Server에서 보낼 때 보낼 주소값이다. client_id는 1번 절차에서 발급 받은 Client_ID를 넣으면 된다. 나머지 파라미터는 알 필요는 없다.

6번 절차의 경우 Code 값은 4번 절차에서 redirect_url 값으로 줬던 url로 파라미터 형식으로 전송된다. 예로 http://redirect_url/?code=4/코드값 형식으로 Client는 받게 된다. Client는 받은 코드값을 URL String에서 추출한 후 DB에 저장한다. 그리고 Access Token을 받아야 되기 때문에 7번 절차에서와 같이 Code값, Client ID, Client secret 값을 서버에 전송해야 한다. 형식은 다음과 같다.

POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https://oauth2.example.com/code&
grant_type=authorization_code

Post 방식으로 위와 같이 보내야 한다. grant_type을 제외하고 나머지는 알 것이라고 생각한다. grant_type은 일반적으로 authorization_code를 입력하되 Refresh Token을 이용해 Access Token을 받아야 할 시 refresh_token이라고 입력해야 한다. 추가로 code와 redirect_uri 항목을 제거하고 refresh_token=Refresh Token 값 파라미터를 넣어주면 Refresh Token으로 Access Token을 얻을 수 있다. 위 방식으로 AccessToken을 요청했을 시 Resource Server는 JSON 방식으로 다음과 같이 Access Token을 받는다.

{
  "access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in":3920,
  "token_type":"Bearer",
  "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

마지막 9번 절차에서 Client에서 구글 정보를 요청할 때는 파라미터에 access_token값을 넣거나 Authorization헤더의 Bearer 값에 Access Token 값을 넣는 방식이 있다.

GET https://www.googleapis.com/drive/v2/files?access_token=<access_token>

GET /drive/v2/files HTTP/1.1 Authorization: Bearer

<access_token> Host: www.googleapis.com/

: HTTP 프로토콜을 사용하는 데이터 통신은 제 3자가 감청, 조작 등이 가능해 보안에 취약하다. HTTPS는 보안에 취약한 HTTP의 약점을 해결해준다. HTTPS의 S가 OverSecureSocket Layer의 약자인 걸 보면 보안에 강력한 걸 알 수 있다. 이러한 보안성을 갖추기 위해 사용하는 게 SSL(Secure Sockets Layer)이다. 즉 HTTP 프로토콜에 대해서 SSL을 사용하면 HTTPS 프로토콜이 된다. SSL에 대해 알기 전에 알아야할 기본적인 지식이 있다. 이에 대해서 먼저 설명하고 마지막에 SSL에 대해 설명할 예정이다.

 

※ 디지털 인증서

: 클라이언트와 서버는 인증서라는 것을 통해 서로를 신뢰하게 된다. 절차는 이렇다. 클라이언트가 서버에 접속하면 서버는 클라이언트에게 인증서를 전달한다. 클라이언트는 이 인증서를 보고 자신이 접속하고자 하는 웹 서버에서 해당 인증서가 왔는 지 확인하는 과정 등을 거쳐서 클라이언트가 접속한 서버를 신뢰할 수 있는 지 검증하게 된다. 이러한 검증 과정을 마치면 서로 실제 데이터 통신을 하게 된다. 인증서를 이용했을 때의 장점은 다음과 같고 이에 대해서 자세하게 알아볼 것이다.

- 대칭키 또는 공개키를 통한 암호화/복호화 과정을 통해 통신 내용이 공격자에게 노출되는 것을 막을 수 있다.

- 클라이언트가 접속하려는 서버가 신뢰할 수 있는 서버인지 판단할 수 있다.

- 통신 내용의 악의적인 변경을 방지할 수 있다.

 

※ 대칭 키와 공개 키

- 대칭 키 : 암호화와 복호화하는 클라이언트와 서버가 똑같은 키를 가진다. 똑같은 키를 가지려면 서로 키 값을 공유해야 한다. 따라서 키 값을 원격지에 전송을 해야 하는데 키 값 자체는 암호화가 안 되있다. 따라서 키 값이 노출될 가능성이 있어 보안에 취약할 수 있다.

 

- 공개 키: 공개 키와 비밀 키 각각 한 개씩 한 쌍으로 존재한다. 공개 키로 암호화한 데이터는 비밀 키로 복호화가 가능하다. 반대로 비밀 키로 암호화한 데이터는 공개 키로 복호화가 가능하다. 공개 키는 누구에게도 노출이 되도 상관없다. 공개 키로 암호화하면 비밀 키로 복호화할 수 있기 때문이다. 따라서 공개 키로 암호화한 데이터를 공개 키와 함께 원격지로 전송하더라도 공개 키에 맞는 비밀 키로 복호화를 할 수 있기 때문에 대칭 키와 달리 공개 키를 외부로 노출해도 괜찮다. 즉, 대칭키의 단점을 해결해준다. 단, 대칭 키에 비해서 연산이 더 복잡하다.

 

※ 인증

: 자신이 받은 데이터가 올바른 상대방(자신이 예상하는 서버)에서 전송한 게 맞는 지 확인하는 과정을 말한다. 인증을 하는 방법은 이렇다. 먼저 비밀 키로 자신의 데이터를 암호화하고 공개 키와 함께 상대방에게 전송한다. 상대방은 받은 공개 키로 데이터를 복호화 한다. 복호화가 가능하다면 인증이 성공한 것이다. 왜냐하면 비밀 키는 데이터를 전송한 자신만 알고 공개 키로 데이터가 복호화된다면 해당 데이터는 비밀 키로 암호화됐다는 뜻이기 때문이다. 이러한 인증 방식은 실제 SSL 통신 방식에서 사용된다.

 

※ SSL 인증서

: SSL 인증서는 클라이언트가 접속한 서버가 신뢰할 수 있는 서버임을 확인해주고 SSL 통신에서 사용할 공개 키를 클라이언트에게 전달하는 역할을 한다. SSL 인증서에 대해 알기 전에 CA(Certificate Authority 혹은 Root Certificate)에 대해서 알아야 한다. CA는 클라이언트가 접속한 서버가 클라이언트가 요청한 서버가 맞는 지 보장해주는 기관들을 말하고 SSL 인증서 내부에 명시되 있다. 각 브라우저들은 CA(기관)들의 리스트를 가지고 있다. SSL 인증서에 있는 CA와 브라우저에 탑재된 CA List 사이에 일련의 절차를 거친 후에 클라이언트가 요청한 서버가 맞는 지 보장해준다. 자세한 과정은 차차 나온다. 따라서 SSL을 사용하려면 CA들에게 인증서를 구입해야 한다. 이렇게 인증서에는 서비스의 정보(인증서 발급한 CA, 서비스의 도메인 등), 서버 측 공개 키(공개 키의 내용, 암호화 방법)이 들어 있다.   

 

※ SSL 인증서 서비스 보증(인증) 과정

: 웹 브라우저가 서버에 접속할 때 서버는 제일 먼저 인증서를 브라우저에게 전송한다. 브라우저는 서버에게 받은 인증서에서 CA를 확인하고 자신의 CA List에 있는 지 확인한다. 있다면 해당 CA를 브라우저 자신이 가지고 있는 해당 CA에 대한 공개 키로 복호화 한다. 참고로 웹 브라우저는 자신의 CA List의 각 CA에 대해서 공개 키를 가지고 있다. 만약 복호화가 된다면 이 인증서는 CA의 비밀 키에 의해서 암호화 된 것을 의미하게 된다. CA의 비밀 키를 가지고 있는 것은 CA 밖에 없기 때문에 해당 인증서가 CA에서 발급 되었다는 것을 인증하게 된다. 이 과정을 통해 클라이언트가 요청한 서비스를 신뢰할 수 있게 된다. 

※ SSL 동작 과정

 

: 간략하게 SSL은 공개 키와 대칭 키를 혼합해서 사용한다. 실제 데이터는 대칭 키 방식으로 암호화하고 대칭 키를 공개 키 방식으로 암호화한다. SSL에서 클라이언트와 서버사이에 통신할 때 악수(handshake)->세션(전송)->종료 3 단계가 있다. 이에 대해서 자세히 알아보자.

 

1. 악수(handshake) : 해당 과정에서는 실제 데이터를 주고 받기 전 서로 상대방이 존재하는 지, 신뢰할 수 있는지, 어떤 방법으로 데이터를 주고 받을 지 결정한다. SSL에서는 서버가 인증서를 클라이언트에게 전송하고 클라이언트와 서버 사이에 암호화 기법을 결정한다. 자세한 단계는 다음과 같다.

a. 클라이언트가 서버에 접속한다. 이 단계를 "Client Hello" 라고 한다. 이 단계에서 주고 받는 정보는 다음과 같다.

- 클라이언트에서 생성한 랜덤 데이터(사용 목적은 마지막에 알아볼 예정이다.)

- 클라이언트가 지원하는 암호화 방식들 : 클라이언트와 서버가 지원하는 암호화 방식이 다르기 때문에 클라이언트는 자신이 어떤 암호화 기법을 지원하는 지 서버에게 알려줘야 한다.

- 세션 아이디

 

b. 서버는 "Client Hello" 응답으로 "Server Hello"를 한다. 이 단계에서 주고 받는 정보는 다음과 같다.

- 서버 측에서 생성한 랜덤 데이터

- 클라이언트가 지원하는 암호화 방식 중에서 서버가 선택한 암호화 방식 => SSL 통신 중에 사용할 암호화 최종 결정

- 인증서

 

c. 클라이언트는 서버에게 받은 인증서를 토대로 위에서 살펴본 SSL 인증서 서비스 보증 과정에 따라 인증서를 복호화해 인증한다. 복호화한 인증서 안에 있는 서버가 생성한 공개 키를 획득한다.(서버는 비밀 키를 가지고 있다.)

 

* a와 b 과정에서 랜덤 데이터를 서로에게 전송했다. 클라이언트는 서버에게 받은 랜덤 데이터와 자신이 생성한 랜덤 데이터를 조합해 pre master secret 키를 생성한다. 이 키는 세션(전송) 단계에서 데이터를 주고 받을 때 실제 데이터를 암호화 하기 위해 사용한다. 이 키는 대칭 키로 서버와 같은 값을 공유해야 한다. 따라서 제 3자에게 노출이 되면 안 된다. 이를 위해 pre master key 인증서 내부에 있던 서버의 공개키로 암호화하고 서버에 전송한다. 이 값은 전송 중에 유출 되더라도 비밀 키는 서버만이 가지고 있기 때문에 안전하다.

 

d. pre master secret 키를 자신의 비밀 키로 복호화해 pre master secret 키를 공유한다. 그리고 서버와 클라이언트는 일련의 과정을 거쳐 pre master key를 master secret key로 만들고 이를 다시 session key로 만든다. session key는 전송 단계에서 실제 데이터의 대칭 키 값이 된다.

 

e, 서로에게 handshake 종료를 알린다.

 

2. 세션 : 실제로 데이터를 주고 받는 단계로 session key를 이용해 실제 데이터를 암호화 한다.

 

3. 세션 종료 : 서로에게 SSL 통신이 끝났음을 알리고 세션키는 폐지한다.

 

 

"참고로 위 내용은 생활 코딩에 있는 강좌를 토대로 요약했다"

+ Recent posts