[ 오늘의 TODO ]
코드 스테이츠) 수~금 내용 복습// Cookie// Session// Token// OAuth패스트 캠퍼스) 인강 3개 이상 듣기 // optional스터디 그룹) 프로그래머스 문제 풀기생활) 물 1L 이상 마시기생활) 1시간 이상 걷기

[ 오늘의 복습 ]
1. Cookie (쿠키)
쿠키는 서버에서 클라이언트에 데이터를 저장하는 방법 중 하나다. 서버가 원할 때 쿠키를 이용해 데이터를 가져올 수 있고, 서버에서 필요로 할 때 쿠키를 전송해 클라이언트에 저장할 수 있다. HTTP 는 무상태성이라고 배웠다. 그러나 클라이언트에 접속할 때 정보가 유지되는 이유는 (예를 들어 네이버에 로그인을 해놓고 잠시 꺼놓았다가 다시 켰을 때 로그인 상태로 유지되어 있는 것 등) 쿠키 덕분이다.
1-1) 쿠키의 정의
쿠키란 서버가 일방적으로 클라이언트에 전달하는 작은 데이터를 의미한다. 일반적으로 쿠키는 클라이언트에게 의사를 묻지 않고 전달해주는데 최근 보안 이슈로 해외 몇 사이트에서는 쿠키 전송 허가를 받는 창이 뜨기도 한다. 크롬 설정 탭에서 쿠키를 검색하면 내 컴퓨터에 어떤 정보가 저장돼 있는지를 확인할 수 있다.
정리하면 서버가 웹 브라우저에 정보를 저장하고 불러올 수 있는 수단이다. 만약, 서버가 해당 도메인에 쿠키가 존재하면 브라우저는 도메인에게 HTTP 프로토콜 요청을 할 대 쿠키를 담아 함께 전달한다.
1-2) 쿠키 이용 방법
쿠키의 특성은 삭제하지 않는다면 사라지지 않는다는 것이다. 브라우저 설정으로 쿠키를 지울 수 있고, 서버에서 쿠키의 유효기간을 지정해줘서 유효기간이 끝나면 삭제할 수 있다. 그러나 그런 이벤트나 옵션을 달아주지 않으면 쿠키는 사라지지 않는다. 그래서 보통 로그인 상태 유지, 테마 등 개인 정보들을 장기간 저장할 경우에 사용된다. 서버가 응답 헤더에 Set-Cookie 라는 이름으로 값, 경로 등의 옵션을 저장한다. 쿠키가 담긴 응답을 받은 클라이언트는 Set-Cookie 를 확인한다. 이후, 요청할 때마다 Cookie 이름과 값을 서버에 전송한다. 서버가 쿠키를 저장하면 이후로 해당 웹사이트를 이동할 때마다 자동으로 쿠키가 전달된다.
그러나 여기서 문제가 하나 발생한다. 쿠키는 브라우저에 저장돼 있기 때문에 해킹 당하는 것에 취약하고 만약 악의적인 목적으로 쿠키를 탈취 당하면 개인 정보가 유출된다. 그 점을 방지하기 위해 보통 쿠키는 해싱(Hashing)과 솔트(Salt) 를 통해 암호화한다. 특히 인증 정보와 관련된 민감한 정보라면 보안을 더 높이기 위해 강도 높은 해싱이 부여된다. 그러나 이렇게 해도 해킹에 취약하다. 왜냐하면 자바스크립트로 쿠키에 접근이 가능하기에 해커가 자바 스크립트 언어를 페이지에 심어서 서버와 웹 브라우저가 암호화 되기 전의 정보, 혹은 복호화한 후의 정보를 갈취할 수 있기 때문이다. 그런 것들을 막기 위해 쿠키를 전달해줄 때 여러 옵션이 존재한다.
1-3) Cookie Option
예시 URL : http://www.example.com:3000/user/login
domain
도메인이란 우리 흔히 볼 수 있는 서버에 접속할 수 있는 이름이다. 쿠키 옵션에서 도메인은 포트 및 서브 도메인 정보, 세부 경로를 포함하지 않는다. 서브 도메인이란 www 같은 도메인 앞에 추가되는 부분을 뜻한다. 예를 들어 위의 주소에서 도메인은 example.com 이 된다. 만약 쿠키 옵션에서도 도메인 정보가 존재한다면 클라이언트에서는 쿠키의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송할 수 있게 된다.
path
세부 경로는 서버가 라우팅할 때 사용하는 경로다. 만약 요청해야 하는 URL 이 위의 URL 과 동일하다면 /user/login 이 path 가 된다. 명시하지 않으면 / 가 된다. Path 옵션의 특징은 설정된 path 를 전부하는 만족하는 경우, 요청하는 path 가 추가로 더 존재하더라도 쿠키를 서버에 전송할 수 있다. 즉, Path가 /user/login 이라 설정돼 있고, 요청하는 경로가 /user 라면 쿠키 전송 가능하다.
maxAge or expires
쿠키의 유효 기간을 지정한다. MaxAge 는 앞으로 몇 초동안 쿠키가 유효한지를 설정한다. 그래서 보통 Number, 수식, 연산 등으로 구성된다. Expoires 의 경우 Date 를 지정한다 '1s' 이면 1초, '1m', '1h' 라면 각각 1분, 1시간을 의미한다. Date 를 셀 때는 현재 시간을 기준으로 한다. 이렇게 경과를 적지 않고 'Tue, 19 Jan 2038 00:00:00 GMT' 로 지정하면 이 일자가 되기 까지만 유효하다. 이후 지정된 시간이나 날짜를 초과할 때 쿠키가 자동으로 파괴된다. 만약 두 옵션이 지정되지 않는다면 브라우저 탭을 닫았을 때 쿠키가 제거된다.
secure
쿠키를 전송해야할 때 사용하는 프로토콜에 따라 쿠키 전송 여부를 결정한다. 만약 해당 옵션이 true 로 설정된다면 오직 HTTPS 프로토콜을 이용해만 쿠키를 보내줄 수 있다. 만약 secure 를 따로 설정해주지 않는다면 http://www.example~ 에서 설정한 쿠키를 https://www.example~ 에서 읽을 수 있고 마찬가지로 https 에서 생성한 쿠키를 http 에서 읽을 수 있다. 쿠키는 기본적으로 도메인만 확인할 뿐 프로토콜을 확인하지 않기 때문이다. 그러나 secure 옵션이 설정된다면 https:// 에서만 쿠키가 설정되기에 http 에서는 쿠키의 내용을 확인할 수 없다.
httpOnly
자바 스크립트에서 브라우저의 쿠키로 접근할 지 여부를 결정한다. 만약 해당 옵션이 true 로 설정된다면 자바스크립트에서 쿠키에 접근이 불가능하다. 명시되지 않으면 기본값은 false 가 되어 XSS 공격에 취약해진다. 자바 스크립트에서 쿠키에 접근할 수 없다는 건 클라이언트의 스크립트가 쿠키를 사용할 수 없도록 만드는 것이다. 만약 이 옵션이 적용되지 않으면 해커가 악의적인 스크립트 코드를 페이지에 삽입해서 쿠키 정보를 훔쳐 조작할 수 있게 된다.
sameSite
Cross-origin 요청을 받았을 때 요청에 사용한 메소드와 옵션의 조합으로 서버의 쿠키 전송 여부를 결정한다. 여기서 한 가지 주의할 점은 SameSite (이후, 대문자로 시작하면 sameSite 옵션을 의미하는 것이 아니라 일반적인 용어로써 same-site 를 의미하는 것으로 함) 와 SameOrigin 은 다르다는 점이다. SameSite 는 SameOrigin 이란 스키마, 도메인, 포트까지 모두 동일한 것을 의미한다. 예를 들어 위의 예시와 https://www.example.com:6000/user/login 은 다른 origin 이다. 뒤의 포트가 다르기 때문이다. 그러나, 두 URL 은 SameSite 다. domain 중에서 subdomain (예: www) 를 제외한 부분이 동일할 때 SameSite 로 파악하기 때문이다. domain은 둘다 www.example.com 이고 www는 sub 도메인이니까 제외하면 example.com 이 되어 동일하다. 만약 ex.example.com, el.exapme.com 이 있다면 둘은 subdomain 이 달라도 SameSite 로 파악한다 (물론, 둘은 절대 같은 도메인이 아니다.) 그렇기에 SameSite 를 작성하기 전에 domain 옵션을 잘 설정해줘야 한다. 우리가 사용하는 sameSite 옵션은 일단 같은 SameSite 의 경우, 쿠키를 보내줄 수 있지만, Cross-origin 요청일 경우 제한된 상황에서 쿠키를 보내주겠다는 의미다. (위의 예시와 example.com:6000 은 다른 origin 이지만 SameSite 다) 이렇게 Cors 요청을 까다롭게 설정해주는 이유는 XSRF 공격을 막기 위함이다.
XSRF 공격을 쉽게 설명해보자면 스팸창을 들 수 있다. 기훈이가 신한 은행 페이지에 로그인된 상태에서 웹서핑하다 "기훈 님은 현금 456억에 당첨되셨습니다! <오징어 게임 참가하기> 버튼을 누르셔서 지금 당장 456억의 주인공이 되어보세요!" 라는 창이 떴다고 해보자. 이 버튼은 신한 은행 송금과 관련된 링크와 연결돼 있다. 만약 기훈이가 이 버튼을 누르면 신한 은행에 로그인 돼 있어 미처 사라지지 않은 기훈이의 인증 정보 쿠키가 은행 송금 링크로 연결 시켜 돈을 유출시킬 수 있다. 이런 문제를 방지 하기 위해 sameSite 옵션을 사용하는 것이다.
첫 번째 값으로 Strict 가 있다. 오직 same-site 인 경우에만 쿠키를 전송할 수 있도록 한다. 값을 따로 입력하지 않고 sameSite 키값만 적고 value 값을 따로 주지 않는다면 이 옵션으로 설정된다.
두 번째 값으로 Lax 가 있다. sameSite 라는 키값도 설정해주지 않았을 경우의 default 값으로, 외부에서 요청을 보낼 때 브라우저가 쿠키를 보내는 것을 막는다. 단, GET 요청은 허용한다.
세 번재 값으로 None 이 있다. 항상 쿠키를 보내줄 수 있으나 Secure 옵션이 true 값으로 돼 있어야만 가능하다. 즉 HTTPS 통신에서만 보내줄 수 있다.
2. Session (세션)
접속 상태를 서버가 가지는 것을 세션이라고 한다. 접속 상태와 권한 부여를 위해 세션 아이디를 쿠키로 전송한다. 그러면 앞으로 그 쿠키가 서버에 전달될 때마다 이 사람이 접속한 상태임을 확인하고 적절한 권한 부여를 해준다. 말로 설명하면 어려우니 아래의 예제를 확인해보자
2-1) 로그인의 과정
Session 은 서버가 클라이언트에 유일하고 암호화된 ID 를 부여하는 방식이다. 중요 데이터는 서버가 가지고 있고 클라이언트에게 이 정보에 접근할 수 있도록 ID 를 주는 것이다. 이 session_id 는 클라이언트에 쿠키로 저장된다.
위의 과정을 자세하게 설명해본다면 아래와 같이 될 것이다
- 유저가 로그인을 한다. 로그인을 입력을 받은 Client 가 Server 에 로그인 Request 를 날린다
- 데이터베이스에 회원 정보가 존재한다. 그렇기에 서버는 Client 에게 입력받은 내용을 Database 로 보내어 우리 서비스에 회원가입된 유저인지 확인한다
- 데이터베이스에서 우리 회원이 맞다고 서버에게 알려준다.
- 서버는 이 사람이 우리 회원이 맞다는 것을 인증을 해주고, 우리 서비스를 마음껏 이용할 수 있도록 서비스 이용 티켓 같은 걸 끊어줘야 한다. 그러나 그 서비스 이용 티켓을 발급하기 전에 누군가 얼핏 보고 복사해서 악용하지 않게 하기 위해 티켓에 바코드를 넣어 유저 인증을 해주고자 한다. Session 정보에 요청을 해서 바코드 발급을 기다린다
- Session 에서 암호화한 바코드, 바로 session_id 를 발급한다.
- 당신은 우리 회원이며 앞으로 우리 서비스를 이용할 수 있다는 유저 정보 바코드, session_id 를 건네준다.
- Client 는 그 바코드, session_id 를 서비스 이용 티켓, 쿠키에다가 찍어서 지갑, 즉 브라우저 쿠키 목록 리스트에 넣는다
- 그리고 앞으로 서비스를 이용할 때마다 내가 이용권이 있다는 것을 증명하기 위해서 지갑에서 그 바코드가 담긴 서비스 이용 티켓을 꺼내 Client 에게 준다, 즉 session_id 정보가 담긴 쿠키를 브라우저 쿠키 목록 리스트에서 꺼내 Client(사실상 브라우저임) 에다가 전달해준다
- 어떤 서비스를 이용하고자 할 때 나는 인증 받은 사람이 맞다고 바코드가 담긴 서비스 이용티켓, session_id 가 담긴 쿠키를 전달한다.
- 서버는 바코드가 담긴 서비스 이용티켓을 받고 바코드를 해석하기 위해 바코드를 만든 곳에 정말 맞는지 물어본다. 즉, session_id 가 담긴 쿠키를 받고 session_id 가 정말 우리 서버에서 발급한 것이 맞는지를 물어본다.
- 우리쪽에서 발급한 것이 맞다고 인증해준다
- 그러면 우리의 회원임이 분명하므로 우리의 서비스를 제공한다.
2-2) 로그아웃의 과정
로그아웃은 어떻게 구현해야할까? 앞의 로그인 예시에서 든 비유를 다시 한 번 이용하면 이 사람이 우리 서비스를 이용해도 된다는 권한을 부여하는 것이 바코드(세션 아이다)고 그 사람이 이 바코드를 사용할 수 있도록 티켓(쿠키)에 바코드를 찍어서 주었다. 즉, 이 사람이 더이상 서비스를 이용하지 않는다고 하면 티켓과 바코드를 모두 파기하면 된다. 즉 해야할 일은 두 가지다.
- 서버의 세션 정보를 삭제한다
- 클라이언트의 쿠키를 갱신한다
서버가 클라이언트의 쿠키를 임의로 삭제할 수 없기에 쿠키를 전달하는 요청으로 세션 아이디의 키 값을 무효한 값으로 갱신할 수 있다.
(더 공부해봐야할 것: 서버에서 res.clearCookie 를 이용해 쿠키를 지울 수 있기는 한데 이 부분의 대해서는 왜 임의로 삭제할 수 있다고 하는지 더 찾아봐야할 것 같다.)
2-3) 세션의 장단점
장점
세션 인증 방식은 클라이언트에 인증 정보를 저장하지 않고 서버에 저장한다. 클라이언트에게는 인증할 수 있는 바코드만을 전해준 것이다. 즉, 외부로부터 개인정보가 유출될 가능성이 줄어든다.
클라이언트는 전달 받은 쿠키를 매 요청마다 자동으로 서버에 제공하게 되어 해당 요청이 세션이 연결된 클라이언트라는 것을 서버에 알려준다. 서버는 쿠키로 전달받은 세션 아이디를 비교해서 적절한 응답으로 되돌려준다.
쿠키는 앞서 말했듯이 클라이언트에 저장해서 부담이 없다. 그나 세션이 서버에서 한 번 더 검증할 때 이 사람이 정말 신뢰할 수 있는 사람인지의 여부를 추가적으로 서버에서 확인할 수 있는 것이다. 예를 들어 동시에 다른 클라이언트에서 같은 세션 아이디로 접속하는 경우를 발견하던가, 한국에서 검증하던 사람이 미국에서 검증을 요청할 때를 구별할 수 있다. 쿠키는 상대적으로 변조가 쉬운데 서버에서 다양한 방법으로 검증하기에 굉장히 유용하다.
여기서 우리가 헷갈리면 안되는 점은 쿠키가 그 자체로 인증이 아니라는 점이다. session_id 를 발급해줬기에 비로소 인증할 수 있는 도구가 되는 것. 서비스 이용할 때 바코드로 우리 유저인지 확인하는 것이지 티켓 겉 표지만을 보고 유저인지 확인하는 것이 아니기 때문이다.
단점
세션은 서버의 메모리에 세션 정보를 저장하고 있다. 만약, 서버 이용자가 많은 경우 메모리같은 저장 공간의 일정 부분을 항상 차지하기에 가용 메모리 양이 줄어든다.
또, 세션은 기존 쿠키를 완전히 대체한 것이 아니다. 그렇기에 여전히 쿠키의 보안상 취약한 점은 세션도 함게 가지고 있다. 만약, httpOnly 나 sameSite 옵션 등이 주어지지 않는다면 세션도 똑같은 문제에 봉착한다. 그래서 공공장소에 가면 항상 로그아웃을 해야하는 이유가 여기에 있다.
3. Token (토큰)
세션 기반은 서버 혹은 데이터베이스의 유저 정보를 담아 인증해주는 방식이다. 서버에는 유저가 민감하거나 제한된 요청을 할 때마다 지금 요청을 보낸 유저에게 정보를 전해도 괜찮은지 확인하기 위해 서버에 따로 마련된 세션 값과 일치하는 지를 확인한다. 그러면 매 요청마다 정보를 비교하고 데이터베이스를 살펴야 하는데 이 부담을 덜기 위해 사용하는 것이 토큰 기반 인증이다.
3-1) 토큰이란?
토큰은 우리가 흔히 게임을 할 때 사용하는 동전이나 행사장에서 받는 토큰을 떠올릴 수 있다. 토큰은 내가 돈을 지불했고, 이 시설을 사용할 수 있다는 메시지를 담는다. 토큰 기반 인증 방식은 서버가 아닌 클라이언트에서 인증 정보를 보관하는 방법으로 고안됐다. 클라이어트가 토큰을 가지고 있으면 서버에게 보여주고 다양한 기능 요청을 할 수 있다. 그렇다면 생기는 의문은 과연, 인증 정보와 같이 민감한 정보를 XSS, CSRF 등의 공격으로 노출된 클라이언트에 담을 수 있냐는 것이다. 토큰은 유저 정보를 암호화한 상태로 담았고, 그렇게 암호화를 했기 때문에 클라이언트에 담을 수 있다. 암호화된 토큰 정보를 복호화하는 방법은 거의 불가능에 가깝기 때문이다.
3-2) JWT
여러 토큰 인증 방식 중에서 자주 사용하는 것이 JWT 다. JSON Web Token 의 약자로 Node.js 환경에서는 jsonwebtoken 이라는 npm 패키지로 사용할 수 있다. JWT 는 아래의 구조를 지닌다.
JWT 는 점을 기준으로 세 부분으로 나뉜다. 위의 예시로 보면 맨 처음 진분홍색이 Header, 연보라 색이 Payload, 하늘 색이 Signature 다. 위의 토큰 내용을 복호화하면 밑의 창으로 표현된다.
Header
Header 는 토큰의 가장 앞에 위치한다. 이게 어떤 알고리즘으로 암호화 했는지(alg), 어떤 종류의 토큰인지(typ) 를 나타낸다. 형태는 JWT 의 경우 JSON 의 형태로 복호화해서 나타난다
Payload
이곳에는 유저에 대한 정보가 담긴다. 어떤 정보의 접근이 가능한지에 대한 권한, 유저 이름 등의 필요한 데이터를 이곳에 담아서 암호화한다. 암호화하기에 클라이언트에 담을 수는 있지만 그렇다고 너무 민감한 정보는 Payload 에 담지 않는 것이 좋다.
Signature
base 64 로 인코딩된 첫 번재, 두 번째 부분이 완성됐다면(base64UrlEncode) 여기에 salt 값을 추가해서 넣는다. base 64 로 인코딩한 건 쉽게 디코딩할 수 있으나 서버에서 사용하는 비밀키를 가지고 있지 않다면 해독하는데 많은 시간과 에너지가 필요하다.
3-3) 토큰 기반 인증 절차
- 클라이언트(사용자)가 서버에게 아이디와 비밀번호를 담아서 로그인 request(요청)를 보낸다
- 서버는 클라이언트로부터 받은 로그인 정보를 받고, 회원 정보를 관리하는 DB 에 해당 로그인 정보와 일치하는 회원이 있는지를 확인한다
- 만약, 일치한다면 클라이언트에게 보낼 Access Token(* Refresh Token 은 옵션으로 발급한다. 자세한 내용은 이후에) 을 발급한다. 이때 토큰 발급은 JWT로 한다.
- JWT 토큰이 생성되면 클라이언트에 Response(응답)으로 보낸다. 클라이언트는 해당 Access Token 을 저장한다. 저장 공간은 Local Storage, Cookie, React의 State 등 다양한 공간에 담을 수 있다.
- 클라이언트가 HTTP 헤더에 토큰을 담아서 서버에 데이터를 요청한다.
- 서버는 받은 토큰을 해석하고 우리가 발급해준 토큰이 맞는지를 검사한다.
- 우리쪽에서 발급해준 토큰이 맞다고 판단하면 클라이언트에게 요청한 데이터를 응답으로 보내준다.
3-4) JWT 의 종류
Access Token(액세스 토큰)
액세스 토큰은 보호된 정보(유저 이메일, 연락처, 사진 등) 에 접근할 수 있는 권한 부여에 사용된다. 이런 권한은 보통 payload 부분에 담긴다. 클라이언트가 처음 로그인을 할 때 액세스 토큰과 리프래쉬 토큰을 둘 다 받지만 실제 사용자가 서비스를 이용할 수 있도록 권한을 부여해주는 토큰은 액세스 토큰이다
Refresh Token(리프래쉬 토큰)
액세스 토큰을 건네줄 때는 언제 이 토큰이 expire 될지를 설정해준다(유효 기간을 설정하는 것). 만약 액세스 토큰의 유효기간이 만료되면 토큰은 자연적으로 사라지게 된다. 그러면 다시 액세스 토큰을 발급해야 하는가? 만약 리프래쉬 토큰이 존재한다면 서버에서 리프래쉬 토큰을 해석하고 새롭게 액세스 토큰을 발급받는다. 이 과정을 통해 유저는 액세스 토큰을 발급받기 위해 다시 로그인할 필요가 없어진다.
액세스 토큰과 리프래쉬 토큰 비교
액세스 토큰을 서비스를 사용하는 유저가 서비스를 이용하는데 필요한 권한을 허가해주는 토큰이다. 그리고, 유효 기간이 리프래쉬 토큰과 비교하여 상대적으로 짧은 시간 동안으로 부여된다. 왜냐하면 만약 해커가 악의적인 용도로 토큰을 탈취해서 자기가 이 토큰의 주인인 것 마냥 서버에 여러 요청을 할 수 있기에 짧은 유효 기간만을 부여한다. 그 결과 유저는 액세스 토큰의 유효 기간이 매우 짧으므로 서비스를 이용하는 중간에 액세스 토큰을 다시 발급받는 상황이 일어날 수 있다. 이를 대비한 것이 리프래쉬 토큰이다. 액세스 토큰의 유효기간이 만료되면 리프래쉬 토큰을 이용해 따로 로그인을 하지 않더라도 액세스 토큰을 발급 받을 수 있도록 도와준다. 이처럼 액세스 토큰과 리프래쉬 토큰의 역할이 다르므로 안에 들어가는 정보도 같을 필요는 없다.
여기서 한 가지 문제가 발생한다. 유효기간이 긴 리프래쉬 토큰이 해킹당하면 큰 문제가 된다. 액세스 토큰이 만료되도 리프래쉬 토큰으로 계속 액세스 토큰을 발급받으면서 서비스를 이용하면 실제 토큰 주인에게 악영향을 끼칠 수 있다. 그래서 유저의 편의보다 보안을 더 중요하게 여기는 웹 사이트들은 리프래쉬 토큰을 발급하지 않는 경우가 많다.
3-5) 토큰 기반의 장점
무상태성을 가지고 확장성을 가진다.
서버는 클라이언트에 대한 정보를 저장할 필요가 없다. 토큰이 해독되는지만 판단하면 된다. 그렇기에 서버와 데이터베이스에게 부담을 덜어줄 수 있다. 또, 클라이언트는 새로운 요청을 보낼 때마다 토큰을 헤더에 포함시키면 된다. 따라서 서버를 여러개 가지고 있다면 하나의 토큰으로 여러 서버에서 인증을 받을 수 있기 때문에 더 좋은 효과를 지닌다.
안정성
암호화된 토큰을 사용하고 암호화된 키를 노출할 필요가 없다.
어디서나 생성 가능하다
토큰을 확인하는 서버가 곡 그 토큰을 만들지 않아도 된다. 토큰만 생성해주는 토큰 생성용 서버를 만들거나 다른 회사에서 토큰을 생성하는 작업을 맡길 수 있다.
권한 부여에 용이하다
토큰은 Session 처럼 단순히 인증하는 용도로만 사용하지 않고 유저의 정보와, 우리 서비스에서 어떤 권한을 지니는지 Payload 부분에 담을 수 있다.
4. OAuth
4-1) OAuth 란?
가끔 회원가입할 때 "구글 아이디로 로그인", "카카오 아이디로 로그인", "네이버 아이디로 로그인" 등의 타 웹 사이트에 저장된 정보를 가지고 아이디를 만드는 경우를가 종종있다. 이렇게 구글, 카카오톡, 네이버 등 자신들이 갖고 있는 회원 정보, 리소스들을 다른 웹 사이트나 애플리케이션에 접근 권한으 부여해주는 개방형 표준 프로토콜을 OAuth 라고 한다.
4-2) OAuth 용어
CaseStudy: Je는 카카오로 오잉 사이트에 새로 회원가입을 하고자 한다.
Resource Owner
리소스의 주인을 의미하며, 여기서는 Je 가 된다.
Client
Resource Owner 대신에 보호된 리소스에 액세스 하는 프로그램, 웹 앱을 의미한다. 여기서는 오잉 사이트가 될 것이다. 보호된 리소스란 카카오에 저장된 Resource Owner 의 기본 정보, 즉 카카오에 저장된 Je 의 정보를 의미한다.
Authorization Server
Resource Server 에게 액세스 토큰을 발급하는 서버를 의미한다.
Authorization Grant
Client 앱이 액세스 토큰을 얻는 방법 중 대표적인 방법이다. 간단하게 설명하면 Client 앱이 액세스 토큰을 얻을 때 사용하는 증명 방법을 의미한다. 우리는 Authroization Code 로 인증하는 방법을 사용할 거고 자세한 설명은 밑에서 한다. 일단은 이런 컨셉이라는 것만 알면 될 것 같다.
Authorization Code
액세스 토큰을 발급 받기 전에 Client Id, Client Secret 이 필요한데 이 두개가 포함된 일종의 허가증을 의미한다.
Resource Server
유저의 리소스를 갖고 있는 서버를 의미한다. Client(오잉 사이트)의 요청을 수락하고 응답하는 역할을 한다. 여기서의 응답은 Je의 기본 정보를 넘기는 역할을 맡는다. Resource Server 의 주인은 카카오가 될 것이다.
위 사진처럼 큰 규모의 서비스 경우 여러 Resource Server 를 구축하고 있다. 각 Resource Server 는 독립적으로 구별되어 있지만, 동일한 Authorization Server 로 연결된다. Resource 서버의 주 역할은 액세스 토큰이 포함된 요청을 받고, 그 토큰이 Authorization Server 에서 발급한 토큰이 맞다면 요청한 정보를 제공하는 것이다.
4-3) OAuth 흐름 (Authorization Code Grnat Type)
위의 케이스 스터디를 그대로 끌고 와서 위의 스크린 샷 플로우를 따라 서술하고자 한다
- Je(User) 오잉 사이트(App XYZ) 에 회원가입을 하고자 한다. 회원 가입 방법은 "카카오로 로그인" 으로 카카오 서비스(Service ABC) 를 이용해서 진행하고자 한다
- 오잉 사이트는 카카오에서 정한 Authoriztion Endpoint 형식에 맞추어(보통 카카오 공식 문서에 정해놓음) ABC Authorization Server 에 요청을 보낸다.
- Aiuthorzation Endpoint 로 받은 요청은 Authorization Page 를 생성하여 App에게 Redirection 한다.
- 이건 마치 Je 가 카카오로 로그인하기 버튼을 눌렀을 때 카카오 로그인창이 떠서 로그인을 하고, "오잉 사이트에 다음의 정보를 주는 것을 허가하십니까?" 라는 창이 현재 창에서 뜨는 것과 유사하다.
- Je는 로그인을 하고 정보 권한 요청을 허가해준다. 이때 보통 이름, 이메일, 등의 가장 기본적인 권한만을 체크하여 허락한다.
- 허가를 받으면 Authorization Server 에서 오잉 사이트(App XYZ) 에게 Authorization Code 를 발급해준다. 이 Code 는 유효 기간이 짧다.
- 오잉 사이트는 받은 Authorization Code 를 Authorization Server 에서 정해 놓은 Token 발급 Endpoint 형식에 맞추어 액세스 토큰을 발급 받기 위한 요청을 보낸다
- Authorization Server 에서는 해당 Authorization Code 가 유효한지를 판별하고 오잉 사이트에게 Access Token 을 발급해준다. 이 Access Token 은 오잉 사이트가 카카오 서비스에게 Je 의 정보를 열람할 수 있도록 해주는 Access Token 이다. 단, 여기 Payload에서 오잉 사이트에게 부여해준 권한은 유저 Je 가 5번 과정에서 수락한 기본적인 권한만 들어가 있다.
- (그림 상에서 A 선) 오잉 사이트는 발급받은 Access Token 을 이용해 본인이 부여 받은 권한을 행사한다. 즉 Je가 5번에서 허가해준 정보들을 카카오로부터 얻기 위해 해당 Resource(정보)를 갖고 있는 카카오의 Resource Server 에 요청을 보낸다
- (그림 상에서 B 선) Resource Server 는 들어온 Access Token 이 진짜 우리 카카오 서비스에서 발급해준 토큰인지 확인을 해줘야 한다. 대규모의 서비스는 여러 Resource Server 를 갖고 있지만 Authorization Server, 즉 Access Token 을 발급해주는 서버는 단 하나이므로, Access Token 이 포함된 요청을 받은 Resource Server 는 해당 토큰을 Authorization Server 에게 정말 우리 카카오 서비스에서 발급해준 토큰이 맞는지를 검토한다
- (그림 상에서 C 선) Authorization Server 는 Access Token 이 우리 서버에서 발급해준 것이 맞는지, 아닌지에 대한 정보를 Resource Server 에게 전달해준다
- (그림 상에서 D 선) 만약 우리 카카오 서비스에서 발급해준 것이 맞다고 한다면 Resource Server 에서 오잉 사이트가 요청한 Je 의 정보를 전달해준다.
- 그림 상에서 나타나 있진 않지만 정보를 전달 받은 오잉 사이트는 Je의 회원 가입을 카카오에서 받은 Je 의 유저 정보로 진행한다.
이러면 생기는 의문은 액세스 토큰을 뭐 이리 복잡하게 받아오는가 하는 점이다. 그냥 액세스 토큰만 받아오면 되지 굳이 Authorization Code 를 발급하면서 다시 제공해줘야 하는 이 과정이 왜 필요한가다. (6, 7, 8 번에 해당하는 내용)
이렇게 복잡하게 하는 이유는 보안을 강화하기 위한 목적이다. Client 에서 Client Secret Key 만을 사용해 Access Token 을 발급 받으면 탈취 당하기 쉽다. 그래서 Client는 Client Id 만 이용해서 받아올 수 있도록 도와주는 Authorization Code 를 받아 오고 Client Secret 까지 포함해 Access 요청을 진행한다.
간략 정리
간단한 설명 | 저장 장소 | 단점 | |
쿠키 | 쿠키는 단순히 http의 stateless 한 점을 보완해주는 도구일 뿐이다. 브라우저에 저장하는 작은 데이터일 뿐. |
클라이언트 (브라우저) | 쿠키는 그 자체로 인증이 될 수 없다. |
세션 | 접속 상태를 서버가 갖는다. 접속 상태와 권한 부여를 위해서 세션 아이디를 쿠키로 전송한다. 세션 아이디는 토큰의 형태가 된다. |
서버 | 하나의 서버에서만 접속 상태를 가진다. 그러므로 많은 서버에 접근하기에는 불리하다. |
토큰 (JWT) | 토큰 자체가 무결성을 증명할 수 있다. 서버가 접속 상태를 갖지 않는다. |
클라이언트 (쿠키, localSotrage, in-memory) |
모든 요청에 토큰을 실어서 보내야만 한다. |
OAuth | 제 3자로부터 인증을 대행하고, 액세스 토큰을 받는다. 인증을 대신할 뿐, 권한 관리는 토큰 방식과 유사하다 |
토큰과 동일 | 토큰과 동일 |
'코드스테이츠 > 코드스테이츠 @ 개발 복습' 카테고리의 다른 글
[코드 스테이츠] 105일차, "15주차 복습(2) - 네트워크' (0) | 2021.10.31 |
---|---|
[코드 스테이츠] 104일차, "15주차 복습(1) - 컴퓨터 공학 기초" (0) | 2021.10.30 |
[코드 스테이츠] 97일차, "14주차 복습 (1) - MongoDB, HTTPS, Hashing" (0) | 2021.10.23 |
[코드 스테이츠] 91일차, "13주차 복습 (2)" (0) | 2021.10.17 |
[코드 스테이츠] 90일차, "13주차 복습 (1)" (0) | 2021.10.16 |