사실 인증과 인가는 한번에 쓰일 수도 있다. 회사에 출근하면 찍는 지문 인식기는 내가 누구인지도 인식하면서, 내가 회사 출입문을 통과할 수 있도록 회사 내부 접근을 인가하기도 한다.
인증은 인가로 이어질 수 있지만, 인가는 인증으로 이어지지 않을 수도 있다. 편의점에서 구매한 버스카드는 내가 누구인지에 대한 인증 정보는 담고 잇지 안지만, 잔액이 충분하다면 얼마든지 버스 탑승을 인가받을 수 있다.
HTTP는 stateless 한 특성을 가지기 때문에 각 통신의 상태는 저장되지 않습니다. 하지만 우리가 웹 서비스를 사용할 떄를 생각해봅시다. 매번 새 페이지를 요청할 때마다 로그인을 해야 한다면 사용이 불가능할 것입니다.
이 문제를 해결하기 위한 대표적인 도구 두 가지가 바로 세션(Session) 과 토큰(Token) 입니다.
유저가 로그인을 시도할 때 서버상에서 일치하는 유저 정보를 찾았다면 인증(Authentication) 확인의 표시로 세션이나 토큰을 발급/전달 해 줍니다.
그럼 웹 브라우저 측에서 해당 세션/토큰 정보를 받아 간직하고 있다가 새로운 request를 보낼때마다 인가(Authorization)를 위해 해당 세션/토큰을 함께 보냅니다.
그런데 세션과 토큰 모두 존재 목적은 거의 같지만 차이점은 존재합니다. 그 중 가장 큰 차이점은 세션은 데이터베이스 서버에 저장된다는 것, 토큰은 클라이언트 측에서만 저장한다는 점입니다.
웹을 이용하다보면 흔히 쿠키라는 이름을 듣는다. 쿠키는 클라이언트 측에서 로컬 웹 브라우저가 저장하는 데이터다. 인증을 하는 과정에서 처음에 서버는 쿠키를 생성해서 클라이언트에게 보내게 된다면, 클라이언트는 쿠키를 웹 브라우저에 key-value 형식으로 저장이 된다. 이후 클라이언트가 데이터를 요청시 헤더에 쿠키를 실어서 서버에 보내게된다. 따라서 로그인 정보가 쿠키에 담겨져있다면 더이상의 인증은 필요없게 된다.
쿠키의 유효기간은 서버에서 설정하여 보낼 수 있다. 유효기간이 지나면 쿠키는 자동으로 소멸된다. 만약 유효기간을 설정하지 않는다면 웹 브라우저를 종료하는 순간 사라진다.
그런데 사실 인증을 여러번 하지 않는 큰 이유중 하나가 보안에 취약하다는 점이다. 서버에게 인증 요청을 하기 위해서 네크워크로 개인정보를 보내는데 이를 탈취해 나갈 가능성이 있기때문에 보완점이 필요했다. 구리는 이를 보완하고자 세션(Session)을 사용한다.
일정 시간동안 같은 사용자(브라우저)로 부터 들어오는 일련의 요구를 하나의 산태로 보고, 그 상태를 일정하게 유지시키는 기술이다. 여기서 일정 시간은 방문자가 웹 브라우저를 통해 웹 서버에 접속한 시점으로부터 웹 브라우저를 종료하여 연결을 끝내는 시점을 말한다.
즉, 방문자가 웹 서버에 접속해 있는 상태를 하나의 단위로 보고 그것을 세션이라고 한다.
화면이 이동해도 로그인이 풀리지 않고 로그아웃하기 전까지 유지
아직 나에게는 어려운 것 투성이였지만,, 그래도 정리를 해보려고한다. 머리에 넣자..
평문(Plaintext)
단방향암호는 흔히 Hash를 이용해 암호화를 하는것으로, 임의의 평문을 hash 처리하였을때 그 복호화가 불가능한 암호화를 말한다. hash 처리된 암호문을 평문으로 복호화가 불가능하므로, 단방향 암호라고 부르며 패스워드 등에 사용된다.
ex)
웹사이트에 비밀버노를 입력하면, 해당 비밀번호의 hash 값만 서버에서 저장해서 서로 비교대조 후 사용자에게 access 권한을 부여한다. 즉, 데이터의 진위여부는 확인하고싶으나, 본데이터의 privacy를 지키고 싶은 경우에 사용한다.
해시 알고리즘은 동일한 평문에 대해서 항상 동일 해시값을 갖습니다. 따라서 특정 해시 알고리즘에 대해서 어떠한 평문이 어떠한 해시값을 갖는지 알 수가 있습니다. 이런 특징을 이용하여 해시 함수의 해시 값들을 대량으로 정이한 테이블이 존대하며, 이를 레인보루 테이블이라고 한다.
해시 함수는 본래 데이터를 빠르게 검색하기 위해서 탄생 되었습니다. 이러한 해시 함수의 빠른 처리 속도는 공격자에게 오리혀 장점이 됩니다.
솔팅은 단방향 해시 함수를 통해 암ㅁ호화를 진행 할 때 본래 데이터에 추가적으로 랜덤한 데이터를 더하여 암호화를 진행하는 방식입니다. 원래 데이터에 추가 데이터가 포함되었기 때문에 원래 데이터의 해시값과 다르게 됩니다.
키 스트레칭은, 단방향 해시값을 계산 한후, 그 해시값을 또 다시 해시하고 또 이를 반복하는 방식입니다.
단방향 암호화와 달리 양방향 암호화는 암호화된 값을 다시 암호화 하기 전의 값으로 복호화가 가능합니다. 양방향 암호화는 암호화 알고리즘 키(key)을 이용해서 암호화를 진행하는데, 이 키를 통해서 암호화된 값을 보호할 수 있습니다.
비대칭키 암호화 또한 암호화와 복호화 모두 가능하며, 암호화를 진행 할 떄 키를 이용합니다. 비대칭키 암호화에서는 암호화 때 사용하는 키와 복호화 할 떄 사용하는 키를 다르게 사용한다. 일반적으로 다른 사람들에게 공개하는 Public key와 정대 노출을 하지 않는 private key가 있으며, 이 두개의 키를 key pair라고 부릅니다. 비대칭키 암호화는 암호화하는 키와 복호화 하는 키를 구분하여 대칭키 암호화의 고질적인 문제였던 키의 탈취 또는 관리의 단점 부븐을 보완할 수 있씁니다.
Bcypt는 브루스 슈나이어타 설계한 키(key) 방식의 대칭형 블록 암호에 기반을 둔 암호화 해시 함수로써 Niels Provos 와 David Mazières가 설계했습니다. Bcrypt는 레인보우 테이블 공격을 방지하기 위해 솔팅과 키 스트레칭을 적용한 대표적인 예입니다.
2b
: 해시 알고리즘 식별자12
: Cost Factor로 Key Stretching의 수 (2의 12승번)76taFAFPE9ydE0ZsuWkIZe
: 16Byte 크기의 Salt, Base64로 인코딩된 22개의 문자xWVjLBbTTHWc509/OLI5nM9d5r3fkRG
: 24Byte의 해시 값, Base64로 인코딩된 31개의 문자Bcrypt는 단방향 해시 알고리즘 입니다. 따라서 복호화가 불가능 합니다. Berypt의 검증은 암호화된 값이 가지고 있는 알고리즘, Cost Factor, Salt를 이용합니다. 비교하고 싶은 평문을 암호화된 값이 가지고 있는 알고리즘, Cost Factor, Salt을 이용하여 해시를 진행한 후 암호화된 값과의 비교를 통해 검증을 진행 합니다.
JWT는 클라이언트(사용자)dhk 서버간에 정보를 JSON 개체로 안전하게 전송하기 위한 개방형 표준(RFC 7519)입니다. SAML(Security Assertion Markup Langauge Token)보다 크기가 작아 더 컴팩트하게 사용할 수 있습니다.
JWT는 일반적으로 Base64로 인코딩된 데이터와 전자 서명으로 구성되어 있습니다. JWT 역시 데이터를 암호화 할 수 있지만, JWT가 전자 서명이 되어 있다는 점이 중요하다. 전자 서명된 JWT의 목적은 데이터를 숨기는 것이 아니라 데이터릐 신회성을 보장하는 것입니다. 그렇기 때문에 서명된 JWT와 함께 HTTPS를 사용하는 것이 좃습니다.
JWT을 이용한 인증 과정은 사용자 측에 사용자의 정보를 관리하는 토큰 기반 인증 메커니즘입니다. 따라서 서버에서 세션 정보를 저장하기 위해 세션 스토리지 또는 데이터베이스에 완전히 의존할 필요가 없습니다. 또한, 서버의 확장성과 멀티 기기 및 도메인에서의 활용에서도 이점을 가지고 잇습니다.
JWT는 3가지 구성요소(Header, Payload, Signature)로 이루어져 있으며, 각 구성 요소들은 dot(.)으로 구분이 되어 있습니다.
Header는 JWT의 첫번쨰 구성 요소이고, 일반적으로 2가지 정보를 담고 있습니다.
alg
: Signature을 만드는데 사용한 알고리즘 정보typ
: Token의 타입Payload는 JWT의 두번쨰 구성요소로 실질적으로 전달해야 하는 정보들을 가지고 있다. payload에 담긴 정보 하나하나를 claim 이라고 하는데, 3가지 종류의 claim이 존재합니다.
Regidtered claims: 이미 JWT 표준으로 지정된 claim입니다. 총 7가지의 registered claim이 존재하며, 해당 claim을 무조건 전부 사용해야 되는 것이 아니고 적절히 상황에 맞제 사용하면 됩니다.
lss
: 토큰 발급자
sub
: 토큰 제목
aud
: 토큰 대상자
exp
: 토큰 만료시간
iat
: 토큰 발급 시간
nbf
: 토큰 활성화 시간
jti
: JWT의 고유 식별자
Public Claims: JWT를 사용하는 사람들이 공개적으로 정의할 수 있습니다. 그러나 기본에 이미 등록되어 있는 Claims와 충졸을 방지하려면 IANA JASON Web Token 레지스트
를 참고하거나 UUID, OID, 도메인 이름 들을 사용해야 합니다.
Private Claims: Public Claims과 달리 오직 사용자와 서버 사이에서만 합의하여 사용하는 claim 입니다.
Signature는 JWT의 세번째 구성요소이고, 문자 그대로 JWT으 ㅣ서명 부분입니다. Header의 인코딩된 내용과 Payload의 인코딩된 내용을 더한 뒤에 Secret key와 알고리즘을 이용하여 암호된 값을 나타냅니다.
전달 ㅂ다은 토큰의 Header와 Payload를 서버의 secreat key를 이용해서 암호화를 진행합니다. 그리고 해당 값이 전달 받은 signature와 같은지 비교하여 JWT의 신뢰성을 확인 할 수 있습니다. 서버에서 관리하고 있는 Secret Key가 아닌 다른 Key로 JWT를 잘급 한다면 Signature가 달라지기 때문에 해당 JWT는 신뢰 할 수 없는 토큰입니다.