1. 암호화?
1) 개인 정보는 개인정보보호법으로 인해 암호화해서 저장해야 한다.
2) 단방향 해시
- 원래 해시(hash)함수는 자료구조에서 빠른 자료의 검색, 데이터의 위변조 체크를 위해 사용된다. 하지만, 복원이 불가능한 단방향 해시함수는 암호화적 용도로 사용된다.
ex) MD5, SHA-1, SHA-256 등이 있다.
- 결과만 봐서는 당장 식별이 불가능하지만, 같은 비밀번호를 해싱하면 항상 같은 결과가 도출된다. 이런 허점을 이용한 Rainbow table이라 불리는 가능한 경우의 수를 해시값으로 만들어서 판매하는 서비스도 있다.
3) Salting & KeyStretching
- 단방향 해시의 단점을 보완하기 위해 생겨난 아이디어.
- 비밀번호와 함께 임의로 생성한 문자열(salt)를 합쳐서 해싱한 값을 저장한다. 비교를 위해 해시값과 salt 값을 같이 저장한다.
- 추가적으로 무작위 대입을 통해 해시값을 계산하는데 걸리는 시간을 늘리기 위해 Key Stretching을 사용한다.
- Key Stretching은 salting 및 해싱을 반복해서 키값을 계속 늘리는 작업이다.
4) bcrypt
- Salt와 Key Stretching 개념들을 실제로 적용하기 편하게 해주는 대표적인 라이브러리이다.
- 다양한 언어를 지원하며, 사용이 간편해서 쉽게 적용이 가능하다.
- bcrypt는 hash결괏값에 소금값과 해시값, 반복 횟수를 같이 보관하기 때문에 비밀번호 해싱을 적용하는데 DB 설계가 덜 복잡하다.
- bcrypt 사용 시 해싱된 결괏값(Digest)의 구조는 아래와 같다.
5) JWT
- 사용자가 서버에 로그인했을 경우, http의 특성상 로그인했다는 것을 기록할 수 없다. 이때 headers에 메타데이터를 보내서 확인다는데 이 메타데이터가 JSON Web Token으로 JWT라고 부른다.
- 암호화는 무거운 작업이라 지속적으로 로그인 요청을 보내면 부담스러우므로 Token 사용으로 가볍게 돌린다.
- JWT구조
-Header(헤더) : 토큰 타입과 해시 알고리즘 정보가 들어간다.
헤더의 내용은 BASE64방식으로 인코딩후 기록된다.
ex) {"alg":"HS256","yyp":"JWT"}
-Payload(내용) : 만료시간을 나타내는 exp와 같이 미리 정의된 집합인 Registered Claim, 공개용 정보 전달을 목적으로 하는 Public Claim, 그리고 클라이언트와 서버 간 협의하에 사용하는 Private Claim가 있다. 이 세 가지 요소를 조합하여 작성한 뒤 BASE64 인코딩 후 기록된다.
ex) {"user-id":1,"exp:1539517391}
-> pk 값(user_id...)을 사용하는데, 개인 정보가 아니기 때문이다.
-> 우리 쪽 정보임을 알 수 있는 건, 시그니처가 붙기 때문이다.
-> 토큰에는 만료시간을 주고 시간 리필 혹은 재충전을 해주어야 한다.
-Signature(서명) : JWT가 원본 그대로임을 확인할 때 사용하는 부분이다.
시그니처는 BASE64URL 인코드된 header와 payload 그리고 JWT secret(별도 생성)을 헤더에 지정된 암호 알고리즘으로 암호화하여 전송한다. (복호화가 가능하다)
프론트에서 JWT를 백엔드 API 서버로 전송하면, 서버에서는 전송받은 JWT의 서명 부분을 복호화 하여 서버에서 생성한 JWT가 맞는지 확인한다.
- Header와 Payload는 BASE64 인코딩 한 것으로 누구나 원본을 볼 수 있다. (암호화가 x) 그러므로 개인 정보는 담으면 안 된다. ( 그래서 settings.py에 있는 SECRET KEY를 사용하는 것 )