[네트워크] 인증/인가 (2)

EMMA·2022년 3월 22일
0

[http] http와 네트워크

목록 보기
10/14

파면 팔수록 재밌는 http 인증/인가 🔐

django에서 인증/인가 (bcrypt, JWT) 를 구현하는 방법과,
refresh token 그리고 OAuth 소개


0
인증/인가 간단 summary

  • 인증, Authentication: 사용자를 identify하는 과정 (즉, 로그인과 비밀번호를 확인하는 과정)
    • 앞서 계정 생성 (회원가입) > DB에 저장하는 절차가 필요
    • 이 때 비밀번호는 암호화해서 저장 (bcrypt 사용)
    • 로그인 시 bcrypt로 아이디/비밀번호 비교해서 계정 확인
  • 인가, Authorization: 사용자의 접근 권한을 확인하는 과정 (즉, 이 사용자가 request를 요청할 권한이 있는가를 판단)
    • 최초 로그인 시 서버는 JWT를 발행함
    • 클라이언트는 이 JWT를 header에 넣어 request를 함
      (http의 stateless속성을 무시하고 로그인 상태를 유지할 수 있음)

1
How to use bcrypt

제 아무리 서버라 할지라도, 사용자의 비밀번호를 그대~로 저장하면 안된다.
(언제 누구에게 언제 해킹당할 줄 알고?)
(그리고 법적으로도 정해져 있다 - 개인정보 보호법 제 7조)

그래서, django로 API를 구현할 때, 사용자의 비밀번호를 전달 받으면 bcrypt라는 라이브러리를 통해 이를 암호화해야 한다.
bcrypt는 salting, key-stretching까지 포함해서 작업해 준다.

import bcrypt

bcrypt.hashpw(data['password'].encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
>>> DB에 저장할 때는, decode까지 해서 str 형태로 저장한다 (파이썬 버전에 따라 다름)

그리고 비밀번호 확인할 때는 아래와 같이 작성한다.
이 때 둘 다 byte 형태여야 하므로, DB에 있는 암호화된 패스워드도 encode해서 str > byte로 바꿔줘야 한다.

bcrypt.checkpw(사용자로부터 입력 받은 패스워드.encode('utf-8'), DB에 저장된 암호화된 패스워드.encode('utf-8'))

2
How to create JWT in python?

JWT는 header.payload.signature로 구성되어 있고, python으로 작성할 때 payload와 SECRET_KEY, 그리고 알고리즘 정보가 필요하다.

import pyjwt
 
SECRET = SECRET_KEY 
ALGORITHM = 'HS256'

acces_token =jwt.encode({'id':1}, SECRET, algorithm = ALGORITHM)
>>> pyjwt 버전에 따라 결과물이 byte 혹은 str일 수도 있음 

로그인했을 때, 해당 사용자를 위한 token을 위와 같이 생성해 response때 보낸다. 이제 클라이언트는 이 token을 출입증처럼 쓸 수 있다.
암호화하는 것이 아니라 인코딩하는 것이므로, 민감 정보는 절대 사용되지 않고 JWT에도 당연히 들어가지 않는다.

최초 로그인 후 사용자가 다시 API 접근 request를 했을 때, 서버는 token을 아래와 같이 decode 해서 접근 권한을 확인한다.
그리고 decode 시 algorithm =algorithms = 로 입력해야 한다.

jwt.decode(access_token, SECRET, algorithms = ALGORITHM) 
>>> {'id':1}

3
access token은 수명이 있다.

(220423 update)
위에서 서술했듯, JWT의 노출 위험이 존재하다 보니 payload에 민감 정보는 넣을 수 없다. 그러다보니 JWT에 저장할 수 있는 정보도 제한적이고 공격 가능성을 완전히 0%로 만들기도 어렵다.
그래서 유효기간을 설정해 주기적으로 access token을 새로 받을 수 있도록 설정하는 것이다. (토큰 생성 시 exp 설정)

그럼 expired 될 때마다 사용자는 새롭게 받아야 하느냐?
그건 아니고 refresh token을 사용할 수 있다.
https://simpleisbetterthancomplex.com/tutorial/2018/12/19/how-to-use-jwt-authentication-with-django-rest-framework.html
-> 이 글을 보면, 서버는 access token을 전달 할 때 refresh token도 같이 전달한다. 클라이언트는 먼저 access token을 사용하고, 유효기간이 끝나면 refresh token을 사용하는 것. (서버 측의 구체적인 제공 내용은 저마다 다르다)

refresh token의 유효기간까지 끝나면 사용자는 다시 한번 인가 과정을 거쳐야 한다.

(220501 update) 혹은, payload 에 user id 대신 uuid를 넣는 것도 방법이다. 어쨌든 user id도 해당 user의 고유 넘버이기 때문. boto3에서도 쓰이고, 여러모로 유용한 uuid다.

4
OAuth란?

이미지 출처:RFc 5849, https://www.rfc-editor.org/rfc/rfc5849

Google Identity 플랫폼에 가면 구글은 OAuth 2.0 프로토콜을 통해 인증/인가를 진행한다고 나와 있다. OAuth는 인증/인가 표준 프레임워크이며, 구글, 카카오, 네이버 서버를 통해 access token을 받아 제3자 서비스/API에 접근하게 해준다.

자세한 건 다음 편에.

profile
예비 개발자의 기술 블로그 | explore, explore and explore

0개의 댓글