프론트엔드 개발자로서 알아야 하는 HTTP (2)

simoniful·2021년 6월 20일
2

Wecode

목록 보기
13/14
post-thumbnail

인증(Authentication) & 인가(Authorization)

  • 인증과 인가는 API에서 가장 자주 구현되는 기능 가운데 하나입니다.
  • 활동 가능 여부를 증명하고 확인하는 절차로 토큰을 활용하고 암호화하며 저장하는 모든 일련의 과정을 뜻합니다.
  • Private / Public API 모두 기본적인 인증과 인가를 요구합니다.

인증(Authentication)

인증을 하기 위해서는 먼저 유저의 아이디와 비밀번호를 생성(회원가입)할 수 있는 기능도 필요합니다.
ID와 PW의 조합을 입력하고 확인하는 과정을 통하여 누가 서비스의 이용자인지, 어떻게 사용하고, 또 이를 추적할 것인지를 통하여 사용자의 동작을 파악할 수 있습니다.

:: 로그인 절차

  1. 유저 아이디와 비번 생성(회원가입)
  2. 유저 비번 암호화 해서 DB에 저장(알고리즘을 통한 난수 처리).
  3. 유저 로그인 -> 아이디와 비밀번호 입력
  4. 유저가 입력한 비밀번호 암호화 후 암호화되어 DB에 저정된 유저 비밀번호와 비교.
  5. 일치하면 로그인 성공
  6. 로그인 성공하면 access token을 클라이언트에게 전송(유저는 localStorage, Cookies 등 저장).
  7. 유저는 로그인 성공 후 다음부터는 access token을 첨부해서 request를 서버에 전송함으로서 매번 로그인 해도 되지 않도록 처리

:: 유저 비밀번호 암호화

유저의 비밀번호는 절대로 비밀번호 그대로 DB에 저장하지 않습니다(법률적 강제).
DB가 해킹을 당하거나 내부 개발자나 인력이 유저의 비밀번호를 볼 수 있기에 유저의 비밀번호는 반드시 암호화해서 저장해야 합니다.
비밀번호 암호에는 단방향 해쉬 함수(one-way hash function)가 일반적으로 쓰입니다.

단방향 해쉬 함수(one-way hash function)

DataBase에 저장 시 난수 처리를 통하여 해싱하여 복원할 수 없도록 처리하는 방법입니다.
원본 메시지를 알면 암호화된 메시지를 구하기는 쉽지만 암호화된 메시지로는 원본 메시지를 구할 수 없어서 단방향성(one-way)라고 합니다.
SHA-256 이상 암호화 알고리즘을 활용하여 진행하며 단방향 해시 함수는 원본 메시지를 변환하여 암호화된 메시지인 다이제스트(digest)를 생성합니다.

"test password" -> hash256 -> 0b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e
"test password2" -> hash256 -> d34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb

실제 비밀번호는 비슷하지만 해시 함수 값은 완전히 다릅니다. 이러한 효과를 avalance라고 하는데 비밀번호 해시 값을 해킹하기 어렵게 만드는 하나의 요소입니다.

Bcyrpt 해쉬 함수

단방향 해시 함수는 원래 패스워드를 저장하기 위해서 설계된 것이 아니라 짧은 시간에 데이터를 검색하기 위해 설계되었기에, 매우 빠른 속도로 임의의 문자열의 다이제스트와 해킹할 대상의 다이제스트를 비교한다면 역행을 통하여 비밀번호가 노출될 수 있습니다.
bcrypt는 적응형 함수의 하나(라이브러리)로 다양한 언어를 지원함과 동시에 위와 같은 레인보우 테이블 공격 방지를 위해 Salting과 Key Stretching을 통하여 단방향 해쉬 함수의 취약점을 보완합니다.

레인보우 테이블(rainbow table)

  • 해시 함수를 사용하여 변환 가능한 모든 해시 값을 저장시켜 놓은 표
  • 보통 해시 함수를 이용하여 저장된 비밀번호로부터 원래의 비밀번호를 추출해 내는데 사용
  • 미리 해쉬값들을 계산해 놓은 테이블

Salting
실제 비밀번호 이외에 추가적으로 랜덤 데이터를 더해서 해시 값을 계산하는 방법

Key Stretching
단방향 해시값을 계산한 후 그 해시 값을 또 해시하고 또 하고.. 반복하는 것

JWT(JSON Web Tokens)

유저가 로그인을 성공한 후에는 access token이라고 하는 암호화된 유저 정보를 첨부해서 클라이언트에게 전송합니다. 즉, 프론트에서 ID/PW를 서버(백엔드)로 넘겨주면 백엔드가 DB에서 ID/PW를 비교하고, 확인 후 맞으면 다시 프론트에게 access token을 전달하는 것입니다.

이 토큰은 클라이언트의 브라우저에 저장이 되어 보관되다가 마이페이지와 같이 인증이 필요한 곳에서 프론트가 다시 access token을 백엔드에게 넘겨주면 백엔드는 유저를 확인하고 마이페이지에 해당하는 정보를 다시 전달하게 됩니다.

  • 유저 로그인
POST /auth HTTP/1.1
Host: localhost:5000
Content-Type: application/json
{
    "username": "joe",
    "password": "pass"
}
  • access token
HTTP/1.1 200 OK
Content-Type: application/json
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
    // access tocken은 난수화 된 string으로 되어있다.
}

그러면, 서버에서는 access token을 복호화해서 해당 유저 정보를 얻게 됩니다. 복호화하여 얻은 유저 아이디를 통해 해당 유저가 누군지 알 수 있습니다.이러한 절차를 통하여 해당 유저가 매번 로그인할 필요가 없도록 합니다.

access token을 생성하는 방법에는 여러가지가 있으나 그 중 가장 널리 사용되는 기술 중 하나가 JWT입니다. JWT는 말 그대로 유저 정보를 담은 JSON 데이터를 암호화해서 클라이언트와 서버 간에 주고 받는 것을 의미합니다.

왜 아이디와 패스워드 대신에 Access Token을 사용할까?
무거운 bcrypt를 재사용할 필요없이 간단한 해시로 작동합니다. 실제 아이디나 패스워드가 쿠키와 같은 클라이언트의 스토리지에 저장되지 않습니다. 또한 토큰은 특정 서버에서만 적용될 수 있기 때문에 다른 사이트에서 다시 사용될 수 없습니다.

인가 (Authorization)

HTTP는 Stateless 한데, 서버에서 요청을 받으면 사용자가 로그인한 상태인지 어떻게 확인할 수 있을까요?

매 HTTP 요청마다 headers를 활용하여 사용자가 인증 절차를 거친 사용자임을 증명하는 정보를 담아보냅니다! 인가 역시 JWT(토큰)를 통해 구현될 수 있습니다. 즉, 유저가 요청하는 request를 실행할 수 있는 권한이 있는지 여부를 확인하는 절차를 토큰을 통하여 판단합니다(ex. 로그인된 유저라는 걸 확인, 해당 유저는 고객 정보를 볼 수 있지만 수정할 수 없음 등). access token을 통해 해당 유저 정보를 얻을 수 있음으로 해당 유저가 가지고 있는 권한도 확인할 수 있습니다. 따라서, 프론트엔드(유저) 쪽에서 요청할때 계속하여 토큰을 첨부합니다.

Authorization 절차

  1. 인증 절차를 통해 access token을 생성합니다. access token에는 유저 정보를 확인할 수 있는 정보가 들어가 있어야 합니다. (예를 들어 user id - 인코딩 방식으로 개인정보가 아닌 중간에 캐치하여도 무방한 정보)
  2. 유저가 request를 보낼때 access token을 첨부해서 보낸다.
  3. 서버에서는 유저가 보낸 access token을 복호화 한다.
  4. 복호화된 데이터를 통해 user id를 얻는다.
  5. user id를 사용해서 database에서 해당 유저의 권한을 확인한다(분산된 서버일 경우 서버가 시크릿 키만 공유하면 인증으로 간주).
  6. 유저가 충분한 권한을 가지고 있으면 해당 요청을 처리한다.
  7. 유저가 권한을 가지고 있지 않으면 Unauthorized Response(401) 혹은 다른 에러 코드를 보낸다.
profile
소신있게 정진합니다.

0개의 댓글