인증과 인가
인증은 무엇이고 왜 해야할까?
인증(Authentication)
- 로그인 절차에서 정확한 이메일/비밀번호 조합을 입력했는지 확인하는 과정
인증은 왜 필요할까?
- 해당 서비스를 누가, 어떻게 사용하는지 추적이 가능하도록 함
인증에 필요한 정보
- 아이디,이메일주소,비밀번호
- 여기서 가장 중요한 것은 비밀번호이다.(암호화의 과정이 필요하다)
비밀번호는 어떻게 관리할까?
- 법규상의 강제가 필요하다
개인정보의 암호화등을 통해 개인정보 취급자의 실수 또는 해커의 공격 등으로 인해 개인정보가 비인가자에게 유출,노출되더라도 그 내용 확인을 어렵게 하는 보안기술이 필요
- Database에 저장 시 개인 정보를 해싱하여 복원할 수 없도록 함
암호화는 어떻게 할까?
단방향 해쉬
- 본래 해쉬함수는 자료구조에서 빠른 자료의 검색, 데이터의 위변조 체크를 위해서 쓰이지만, 복원이 불가능한 단방향 해쉬함수는 암호학적 용도로 사용된다.
ex) 사용자가 비밀번호로 hello라는 string을 전달하면 해쉬함수는 암호화 알고리즘을 통해서 아무도 알 수 없는 랜덤한 string을 리턴한다. 단방향 해쉬는 이렇게 암호화된 string을 다시 hello로 바꿀 수 없다.
(cf.반대로 양방향 해쉬는 암호화된 string을 다시 원래의 hello로 바꿀 수 있는 것을 의미한다.)
- 결과만 봐서는 당장 식별이 불가능하므로 완벽해보일 수 있다.
- SHA-256, MD5, SHA-1 등의 종류가 있는데 보통 SHA-256을 사용한다.
단방향 해쉬의 단점
- 이러한 단방향 해쉬는 같은 알고리즘으로 같은 비밀번호를 다시 해싱하면 항상 같은 결과가 도출된다.
- 이와 같은 허점을 이용해서 가능한 경우의 수를 모두 해시값으로 만들어서 판매하는 서비스도 생기는 등의 단점이 있다.
SALTING & KeyStretching
- 단방향 해쉬의 단점을 보완하고자 나온 입력한 비밀번호와 임의로 생성한 문자열(Salt)을 합쳐서 해싱하여 이 해시값을 저장하는 방법
- 단순 해쉬값이 해킹에 쉽게 노출되므로 Salting이라는 아이디어가 등장함
- 비교를 위해 결과 값에는 항상 해시 값과 Salt 값을 같이 저장함
- 여기에서 해커가 비밀번호 무작위 대입을 통해 해시값을 계산하는데 필요한 시간을 대폭 늘리기 위해 Salting 및 해싱을 여러번 반복해서 원본 값을 유추하기 어렵게 만드는 것이 Key Stretching 개념
bcrypt
- Salting & Key Stretching의 대표적인 오픈소스 라이브러리
- 다양한 언어 지원, 사용이 간편하여 쉽게 적용 가능
인가는 무엇이고 왜 해야할까?
인가(Authorization)
- 사용자가 서버에 요청을 보내면 인증 과정을 거쳐 확인된 사용자가 맞는지 확인하는 과정
인가는 왜 필요할까?
- HTTP의 Stateless한 특성 때문에 필요함 (과거의 상태를 기록하지 않는 성질)
그렇다면, HTTP는 Stateless한데 서버에서 요청을 받으면 사용자가 로그인한 상태인지 어떻게 알 수 있을까?
- 매 HTTP 요청마다 headers를 활용하여 사용자가 인증 절차를 거친 사용자임을 증명하는 정보를 담아서 보내는 방법: authorization이라는 key에 해당 정보를 담는다
실제로 통신이 어떻게 이루어질까?
기존 방식
기존 방식의 단점
- 분산 서버시스템일 경우 Session이 한 쪽 서버에만 저장되어있는 경우 다른 서버들에서는 해당 정보를 알 수 없다.
기존 방식의 단점을 보완하기 위한 JSON Web Token(JWT)의 등장
-
JavaScript 구조로 되어있는 웹 토큰
-
헤더(header)에 들어가는 정보
1. 토큰의 타입과 해시 알고리즘의 정보
2. BASE64 방식으로 인코딩(암호화는 아니고 다른 방식으로 바꾼 것임)해서 JWT의 가장 첫 부분에 기록됨
3. 예시: {"alg" : "HS256", "typ":"JWT"}
-
내용(Payload)에 들어가는 정보
1. exp와 같이 웹 토큰의 만료시간을 나타나는 공개적인 내용
2. 클라이언트와 서버간 협의 하에 사용되는 비공개적 내용 (Primary key의 id 등)
3. 그 외 어떤 내용이던 상관없이 추가 가능
4. 암호화가 아닌 BASE64로 인코딩하며 JWT의 두 번째 요소에 위치
5. 예시: {"user-id":1, "iat":1539517391}
-
서명(Signature)에 들어가는 정보
1. JWT의 무결성을 확인(JWT가 원본 그대로라는 것을 확인)
2. 토큰의 발행 주체는 백엔드로, 백엔드에서 패스워드 암호화, JWT 생성
3. 실제로 백엔드에서 JWT 토큰을 만들어서 프론트에 전달하면 프론트는 보통 Cookie, local storage, session storage에 저장하게 됨
4. 서명에서는 BASE64URL 인코드된 헤더와 내용 그리고 JWT Secret Key(별도로 생성함)을 헤더에 지정된 암호 알고리즘으로 암호화하여 전송 한다.(복호화 가능)
5. 프론트엔드가 JWT를 백엔드 API 서버로 전송하면 서버에서는 전송받은 JWT 의 서명부분을 복호화하여 서버에서 생성한 JWT가 맞는지 확인한다. 이는 마치 계 약서의 위변조를 막기 위해 서로 사인하는 것과 동일한 것임
6. 헤더와 내용은 암호화가 아닌 BASE64 인코딩한 것이므로 디코딩을 하면 누구나 원본을 볼 수 있으므로 개인정보를 담으면 안됨
JSON Web Token의 예시
- 프론트에서 이 token을 받으면 Cookie, Local Storage, Session Storage 셋 중 한 군데에 저장하여 HTTP 통신 시 headers 부분에 key와 value로서 이 token을 넣어 보내면, 서버에서 확인 과정을 통해 인가가 진행된다.
JSON Web Token의 활용
기존 방식의 단점을 어떻게 보완하는가?
- 서버들끼리 다같이 똑같은 Secret key를 공유하여 같은 키로 계속 암호화, 복호화가 가능하게 된다.