인증과 인가란
인증 : (식별가능한 정보로) 서비스에 등록된 유저의 신원을 입증하는 과정
인가 : 인증된 사용자에 대한 자원 접근 권한 확인
자원을 적절한/유효한 사용자에게 전달/공개하기 위한 방법
인증하기(로그인하기) - Request Header
아이디와 비밀번호를 앞에 달아주기만 해도 API가 구축되어 있는 상황이라면 자동으로 로그인 요청이 간다. (브라우저가 처리)
들어온 URI에서 user:1q2w3e!를 파싱한 후 Base64 인코더를 이용해서 인코딩을 한 후에 전달을 해준다. 그 다음 요청 헤더에 넣어서 보내주는 개념이다.
HTTP로 쏘면 서버가 DB checking을 하고 DB에 실제로 값이 있으니 ok 싸인을 준다.
문제점
사용자가 매번 로그인을 계속 해주어야 한다.
이걸 해결하기 위해 브라우저에 있는 storage의 힘을 빌린다.
인증 유지하기 - Browser(cookie)
쿠키에 간단하게 사용자의 아이디, 비밀번호를 집어넣는다. 그리고 사용자가 인증이 필요한 요청을 할 때 같이 넣어서 보내준다.
- 사용자 입장에서 편리하지만 해커 입장에서도 편리하다.
- storage에 row하게 사용자의 정보가 노출이 되어있으니 해커가 가져갈 수 있다. 또한 클라이언트가 서버보다 상대적으로 보안에 취약하다는 단점이 있다.
안전하게 인증하기 - Server
보안을 향상하기 위해서 서버에 도움을 요청한다.
- 원하는 자원을 바로 클라이언트에 주지 않고 seccion 개념을 도입한다.
- session은 인증된 사용자의 식별자와 랜덤한 문자열로 sessionid로 만들어서 응답의 헤더로 넘겨주고 클라이언트가 저장을 할 수 있도록 만든다.
- 클라이언트에서 사용자의 row한 데이터를 가지고 있지 않으니깐 해커가 정보를 가지고 가더라도 크게 위험하지 않다.
- session의 만료 기간을 정할 수 있어서 만료 기간이 지나게 되면 해커가 가지고 가더라도 유효하지 않다.
- session의 관리를 서버 자체가 하고 있어서 탈취된 session을 서버에서 삭제를 해버리면 이 session 자체는 이용하지 못하게 된다.(보안 상의 이점)
문제점
서비스 성장 → 다중 서버 배치 → 로드 밸런서 도입 → 처음에 요청 전달을 한 서버와 다른 서버에 요청을 전달 → sessionid 부재 → 오류 발생
서버 하나하나 자체에서 session을 관리하고 있어서 생긴 문제이다.
해결 방법
세션 stroage를 두어서 해결한다. → 서버들에 있는 session들을 한 곳에서 관리하자
→ 클라이언트가 많아질 경우에 계속 쌓여서 터진다.
클라이언트/서버/세션저장소 통신 → HTTP/REST API 무상태성 지향 → 서버 REST API 지향 → 인증/인가 시 사용자 정보 보유 → 상태성 발생 → 패러다임 충돌 → 충돌 해소 필요
효율적으로 인증하기 - Token
정보의 요청과 응답 (content) 안에 사용자의 상태를 담아보자 → JWT(JSON WEB TOKEN)
secret key를 사용해서 JWT를 만들어내고 secret key를 사용해서 JWT의 인증 과정을 거친다.
JWT 자체는 해독하기 매우 쉽기 때문에 비밀번호 같은 민감한 정보를 대부분 담지 않는다. secret key가 중요한 만큼 노출되면 JWT 자체도 끝이 나기 때문에 서버 내부에 잘 관리해야 한다.
DB와 체킹 후 세션스토리지와 연결되는 것이 아니라 secret key를 이용해서 토큰을 만들어낸다. 헤더에 넣어서 다음부터는 이 키를 이용해서 요청을 보내고 응답을 받는 형태가 된다.
토큰
토큰이 클라이언트로부터 서버로 넘어가면(요청이 가면) 서버는 토큰의 유효성 검사를 본인이 가진 secret key로 진행한다. 유효하지 않으면 버리고 유효하면 다음 단계인 사용자 정보를 파악한다.
이름으로 어떤 유저인지 찾아낸다. → 만료된 토큰이면 더 이상 진행하지 않는다. → 권한 확인
secret key를 통해서 유효성 검사를 통과한 토큰은 이미 인증을 받은 토큰이다.
장점
- 서버가 여러 대 있다.
- 로드 밸런서가 쏘는 것을 각자 자기가 가진 시크릿 키로 해독을 해서 인증을 진행하면 된다.(요청을 반환하면 된다.)
단점
- 액세스 토큰이 탈취 당하면 해커는 사용자와 똑같은 지위를 가지고 사용자처럼 원하는 자원에 접근할 수 있게 되니깐 위험하다.
- 이를 막기 위해서 만료 기한을 설정한다. 그러나 이렇게 하면 사용자도 30분이 지나면 사용할 수 없어서 불편하다.
- 그래서 나온 개념이 Refresh Token
Refresh Token
- 로그인 및 토큰 생성 로그인 요청 → 서버가 액세스/리프레시 토큰 생성 서버는 로그인 요청을 받아 두 종류의 토큰을 생성한다.
- 토큰 저장 및 전송 리프레시 토큰 저장 → 두 토큰 클라이언트로 전송 서버는 리프레시 토큰만 저장하고, 두 토큰을 클라이언트에 보낸다.
- 클라이언트가 액세스 토큰으로 요청 → 서버 처리
- 토큰 만료 및 갱신 액세스 토큰 만료 → 서버 통보 → 클라이언트가 두 토큰 재전송 → 서버 확인 후 새 액세스 토큰 발급 액세스 토큰 만료 시, 서버 확인 후 새 토큰을 발급
토큰으로 상태 관리를 하기에 따로 세션을 둘 필요가 없다. 효율성이 좋아지고 DB를 찔러도 되지 않기 떄문에 속도가 빠르다는 장점이 있다. 토큰 관리를 해야 한다. 결국 토큰도 탈취당할 수 있다.
다른 채널을 통해 인증하기 - OAuth