이번주는 보안에 대한 것들을 훑었다. 대표적으로 Authentication, Authorization에 대해서 알게 되었는데, 생각보다 넘 어려웠다. 근데 당연히 어려워야 하는 파트 같다.
사전에서 찾아보면 authentication은 인증이라는 뜻이 있고, authorization은 인가/권한위임 이라는 뜻이 있다. 이 두 가지가 비슷해보이지만 엄연히 다른데, 인증은 내가 누구인지를 확인, 체크해주는 거라면, 인가는 말 그대로 내가 접근권한을 가지고 있는지, 혹은 내 권한을 위임해서 그 권한으로 행위를 대리하게 하는 것이라고 생각하면 된다.
이러한 맥락에서, 개인정보/ 중요 데이터가 오갈 때는 암호화하여 전송해야한다. 그래서 http + secure인 https를 이용해서 데이터를 암호화하여 전송한다.
https같은 경우에는 HTTP 요청을 SSL 혹은 TLS 라는 알고리즘을 이용해, HTTP 통신을 하는 과정에서 내용을 암호화하여 데이터를 전송한다.
SSL & TLS정리
아직 이해하지 못했지만 언젠가 보리라... / [Security] SSL과 인증서 구조 이해하기 : CA (Certificate Authority) 를 중심으로
이렇게 https를 사용하는 이유는 http보다 상대적으로 안전한 방법이고, 데이터 제공자의 신원을 보장받을 수 있기 때문.
그렇다면 왜 제공자의 신원을 보장 받는 것이 중요할까?
그러나 HTTPS는 암호화된 데이터를 주고 받기 때문에 중간에 탈취되더라도, 그 내용을 알아 볼 수 없기 때문에, HTTPS가 HTTPS보다 좀 더 안전하다.
하지만 HTTP와 마찬가지로 stateless하기 때문에, 예를 들어 로그인을 유지시키려면 끊임없이 그 웹앱을 사용하는 내내 요청과 응답을 보내야한다. 이를 보완하기 위해서 여러 인증방법들을 사용한다.
(사실 이 스프린트 하면서 칙촉 엄청 먹었다. 왜 저 단어만 봐도 초코칩쿠키가 땡기던지. 우리집 근처에 편의점이 없다는 걸 감사히 여겼음..)
니콜라스의 페이스북과 쿠키의 상관관계 이거 짱많이 봤음.
아~ㄹ겠나요?! 얄팍한 코딩의 울랄라스파 이것도 도움이 많이 되었음. (이 분 넘 중독적이야...)
하여튼, 위의 HTTP의 stateless함을 보완하기 위한 방법 중의 하나로 쿠키를 사용한다.
쿠키란?
쿠키(영어: cookie)란 하이퍼 텍스트의 기록서(HTTP)의 일종으로서 인터넷 사용자가 어떠한 웹사이트를 방문할 경우 그 사이트가 사용하고 있는 서버를 통해 인터넷 사용자의 컴퓨터에 설치되는 작은 기록 정보 파일을 일컫는다.
HTTP 쿠키, 웹 쿠키, 브라우저 쿠키라고도 한다. 이 기록 파일에 담긴 정보는 인터넷 사용자가 같은 웹사이트를 방문할 때마다 읽히고 수시로 새로운 정보로 바뀐다. 이 수단은 넷스케이프의 프로그램 개발자였던 루 몬툴리(Lou Montulli)가 고안한 뒤로 오늘날 많은 서버 및 웹사이트들이 브라우저의 신속성을 위해 즐겨 쓰고 있다. by wikipedia
그러니까 간단하게 말하자면, 서버가 일종의 데이터를 웹브라우저에 저장하고 불러올 수 있는 수단이며, 해당 도메인에 대해 쿠키가 존재하면, 웹브라우저는 도메인에게 HTTP요청 시 쿠키를 함께 전달한다.
쿠키는 삭제하지 않으면 사라지지 않는다. 그렇기 때문에 사용자의 선호, 테마 등 장기간 보존해야 하는 정보를 저장하는데 적합하다.
그러나 쿠키는 브라우저 상에서 누구나 접근할 수 있기 때문에, 만약 꼭 인증정보를 담아야 한다면 암호화처리(해싱, hashing)을 해서 담는다.
클라이언트에서 요청(request)를 보내면, 서버에서 응답 안에 Set-Cookie를 넣어서 보낸다. 그러면 이후 클라이언트에서는 그 쿠키 값을 넣어 요청을 보내면 서버에서는 해당 쿠키를 확인하는 작업을 통해 로그인을 유지하거나, 테마를 보여주는 작업등을 한다.
아래 캡쳐본 참조(코드스테이츠 강의 내용 중)
쿠키를 보낼 때는 옵션을 추가해서 보낼 수 있다.
위와 같은 CSRF공격을 samesite를 이용해 막을 수 있다.
SameSite요청에는 3가지 옵션이 있는데, Lax, Strict, None이 있다.
그렇지만 사실 쿠키에다가 인증정보를 넣는 것은 굉장히 위험하다. 그래서 나온 것이 그렇다면 중요정보는 서버에 객체형태로 저장을 하고 그걸 볼 수 있는 아이디만 암호화된 형태로 클라이언트가 가지고 있으면 어떨까? 라는 생각에서 나온 것이 바로바로 session, 세션!
세션은 아래와 같은 방법으로 전달된다.
그러나 세션에는 단점이 있는데, 그것은 바로 서버에 세션을 저장하기 때문에 메모리의 일정부분을 항상 차지하고 있기 때문에 서버의 성능이 안 좋아질 수 있고, 여전히 쿠키를 사용하고 있기 때문에, 쿠키의 한계를 그대로 가지고 있다.
토큰기반 인증은 왜, 그리고 언제 쓸까요?
세션기반 인증은 서버(혹은 DB)에 유저 정보를 담는 인증 방식이었습니다. 서버에서는 유저가 민감하거나 제한된정보를 요청할때마다 "지금 요청을 보낸 유저에게 우리가 정보를 줘도 괜찮은가?" 를 확인하기 위해 가지고 있는 세션 값과 일치하는지 확인합니다.
매 요청 마다 데이터베이스를 살펴보는 것이 불편하고, 이 부담을 덜어내고 싶다면 어떤 방법이 있을까요? 이럴 때 사용할 수 있는 토큰기반 인증 중 대표적인 JWT (JSON Web Token) 에 대해서 알아봅시다.by 코드스테이츠 강의 중 내용.
이와 같이 서버의 부담을 덜기 위해, 클라이언트에서 사용하는 토큰 기반 인증이 고안되었다.
그러니까 클라이언트는 토큰이라는 것에 인증정보를 담아서 저장하고, 클라이언트가 서버에 무엇인가를 요청할 때, 서버는 그 토큰을 검증한 후에 요청한 것에 대한 응답을 준다는 것이 가장 기본적인 개념이다.
그런데 클라이언트에는 인증정보를 담는 것이 위험하다고 했었는데, 클라이언트에 토큰을 저장해도 되는 걸까? 라는 의문이 들 수도 있다.
하지만 토큰은 유저 정보를 암호화한 상태로 담을 수 있고, 암호화 했기 때문에 클라이언트에 담을 수 있기 때문에 가능하다.
토큰에는 여러가지 종류가 있는 것 같은데, 이번 스프린트에서는 JSON WEB Token인 JWT을 사용하였다.
JWT에는 두 가지 종류의 토큰이 있는데, 하나는 Access Token, 또 다른 하나는 Refresh Token으로 나뉜다.
Header : Header는 이것이 어떤 종류의 토큰인지(지금의 경우엔 JWT), 어떤 알고리즘으로 sign(암호화) 할지가 적혀있다. JSON Web Token 이라는 이름에 걸맞게 JSON형태로 이런 형태를 가짐.
Payload : Payload에는 정보가 담겨 있음. 정보에 접근 가능한지에 대한 권한을 담을 수도 있고, 사용자의 유저이름 등 필요한 데이터는 이곳에 담아 암호화 시킨다. 물론 암호화(헤더에서 정의한)가 될 정보지만, 민감한 정보는 되도록 담지 않는 것이 좋다.
Signature : base64로 인코딩 된 첫번째, 그리고 두번째 부분이 완성 되었다면, 원하는 비밀 키(암호화에 추가할 salt)를 사용하여 암호화한다.
기본적으로 OAuth는 authorization에 가깝다. 내가 직접 인증을 하는 것이 아니라, 제 3자로부터 권한을 위임받아 인증을 받는 방법이라고 보면 된다.
예를 들어, 어떤 웹사이트에 직접 회원가입을 하는 것이 아니라, 페이스북, 카카오톡, 깃허브 등의 다른 다른 웹 앱에 이미 인증된 나의 정보를 불러 위임해서 쓰는 것이라고 생각하면 된다. 이에 대해 가장 큰 이점은 직접 유저의 민감한 정보가 App에 노출될 일이 없고 인증 권한에 대한 허가를 미리 유저에게 구해야 되기 때문에 더 안전하게 사용 가능하다.
우선 용어를 설명하기 전에, 위 로직 플로우를 이해하면 더 좋을 것 같아서 가져옴.
회원가입을 예로 들면, 회원가입을 하려고 하는 클라이언트에서, 카카오톡으로 회원가입을 하려고 하면, 카카오톡으로 authorization code를 받기위한 요청을 보낸다.
그러면 카카오톡에서는 유저에게 권한을 넘기는 것에 대한 허가를 구하고, 허가가 나면, 다시 해당 클라이언트의 uri로 authorization code를 보낸다.
그럼 클라이언트는 이 코드를 들고 서버에 전달하여, Access Token을 받아달라고 요청하는데, 이 토큰을 서버가 받는 이유는 만약 클라이언트에서 토큰을 받아오게 되면, 탈취를 하기 쉽기 때문이다.
그러면 서버에서 시크릿키를 포함한 토큰을 대신해서 받아오게 된다. 그러고 나서 서버에서 받아온 토큰을 클라이언트로 보내게 된다.
여기에 더해서, Access Token의 유효기간이 끝나게 되면, Refresh Token으로 Access Token을 갱신한다.
(코드스테이츠 강의내용 중)
Resource Owner : 액세스 중인 리소스의 유저입니다. 김코딩의 구글 계정을 이용하여 App에 로그인을 할 경우, 이 때 Resource owner은 김코딩이 됩니다.
Client : Resource owner를 대신하여 보호된 리소스에 액세스하는 응용프로그램입니다. 클라이언트는 서버, 데스크탑, 모바일 또는 기타 장치에서 호스팅할 수 있습니다.
Resource server : client의 요청을 수락하고 응답할 수 있는 서버입니다.
Authorization server : Resource server가 액세스 토큰을 발급받는 서버입니다. 즉 클라이언트 및 리소스 소유자를 성공적으로 인증한 후 액세스 토큰을 발급하는 서버를 말합니다.
Authorization grant : 클라이언트가 액세스 토큰을 얻을 때 사용하는 자격 증명의 유형입니다.
Authorization code : access token을 발급받기 전에 필요한 code 입니다. client ID로 이 code를 받아온 후, client secret과 code를 이용해 Access token 을 받아옵니다.
Access token : 보호된 리소스에 액세스하는 데 사용되는 credentials입니다. Authorization code와 client secret을 이용해 받아온 이 Access token으로 이제 resource server에 접근을 할 수 있습니다.
Scope : scope는 토큰의 권한을 정의합니다. 주어진 액세스 토큰을 사용하여 액세스할 수 있는 리소스의 범위입니다.
JWT Usage를 위한 공식문서 링크(Node.js기준)
이렇게 인증 및 인가에 대해서 알아봤는데, 확실하게 이해하지 못한 부분도 있고, 제대로 작성하지 못한 부분도 있으니, 언제든 수정사항은 코멘트로 남겨주세요. 휴.. 힘들었다.