[TIL] 2020.09.10 인가

dev.soo·2020년 9월 10일
0

TIL

목록 보기
6/10

어제 글에서 회원가입, 로그인 할 때 서버에서 비밀번호 일치하는지 확인하는 작업까지 정리했고, 오늘은 비밀번호가 일치하는 경우 그 이후에 일어나는 일에 대해서 정리한다.

Authorization 인가

쿠키-세션 기반의 인증토큰 기반 인증 중, 토큰기반 인증을 사용할 것이다.

토큰기반 인증은 쿠키를 사용하지 않고 웹을 stateless 상태로 사용할 수 있기 때문에 보안성이 높고, 다른 디바이스나 다른 도메인에서도 유효한 토큰으로 계속 인증된 상태를 유지할 수 있다.

인증된 유저에게 토큰을 발행하고, 원하는 만큼의 권한을 허용하는 것.
예를 들어서, 회원권의 금액에 따라 등급별로 사용할 수 있는 서비스가 제한되는 경우, 정회원만 특정 게시글을 확인할 수 있는 경우 등이 있다.



장고에 코드 구현하기

JSON Web Token 를 사용하는 인가 작업도 큰 분류로 나누고 세부 단계를 살펴보고자 한다.

  1. 라이브러리 : 설치하고 view 파일에 import 하기
  2. 프로젝트 세팅 : SECRET_KEY 숨겨주기
  3. 토큰 발행하기

그 전에 우선 사용할 암호화 함수에 대해 살펴보자.

RS256 HS256 두 가지 선택 모두 아이덴티티 공급자가 JWT를 sign 위해 사용하는 알고리즘을 나타냅니다. 서명은 토큰 수신자가 토큰이 변경되지 않았 음을 확인하기 위해 유효성을 검사 할 수있는 "서명"(JWT의 일부)을 생성하는 암호화 작업입니다.

RS256 ( SHA-256 을 사용한 RSA 서명)은 비대칭 알고리즘 이며 공개/개인 키 쌍을 사용합니다. 아이덴티티 공급자는 개인 키 (비밀) 키를 사용합니다. 서명을 생성하면 JWT의 소비자는 서명을 확인하기 위해 공개 키를 얻습니다. 공개 키는 개인 키와 달리 보안을 유지할 필요가 없기 때문에 대부분의 ID 공급자는 소비자가 일반적으로 메타 데이터 URL을 통해 쉽게 구하고 사용할 수 있도록합니다.

반면 HS256 ( HMAC SHA-256)은 해시 함수와 해시를 생성하는 데 사용되는 두 당사자간에 공유되는 하나의 (비밀) 키의 조합을 포함합니다. 서명 역할을합니다. 동일한 키가 서명을 생성하고 유효성을 검증하는 데 사용되므로 키가 손상되지 않도록 주의해야합니다.

JWT를 사용하는 애플리케이션을 개발할 경우 비밀 키를 사용하는 사람을 제어 할 수 있으므로 HS256을 안전하게 사용할 수 있습니다. 반면에 클라이언트를 제어 할 수 없거나 비밀 키를 보호 할 방법이없는 경우 소비자는 공개 (공유) 키만 알면되기 때문에 RS256이 더 적합합니다.

https://www.it-swarm.dev/ko/jwt/rs256-%EB%8C%80-hs256-%EA%B7%B8-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C/826436771/

비밀 키의 조합(SECRET_KEY) 에 아무나 접근할 수 없게 하는 과정을 포함하여 HS256 을 사용할 것아디ㅏ.

1. 라이브러리 import

1) 암호화를 위한 라이브러리 PyJWT 를 설치한다.
pip install pyjwt

2) view.py 에 라이브러리를 import해준다.
import jwt

*pyjwt -> jwt 다르니까 조심

2. SECRET_KEY 숨겨주기

위에서 언급한 비밀 키, 그리고 암호화 방식을 비공개하는 과정이다.

장고 프로젝트를 만들면 settings.py 안에 복잡한 string 인 변수 SECRET_KEY 가 자동으로 생성되어 있다. 알고리즘은 views 나 settings에 직접 선언해주어야 한다.

그런데 github 에 PR 하게되는 경우 settings.py 나 views.py 의 SECRET_KEY ALGORITHM이 그대로 노출되게 된다.

그래서 my_settings.py 파일을 만들고 노출되면 안되는 변수들을 내부에 적어준다. 그리고 github PR 에서 해당 파일을 제외하기 위해 .gitignore.py 에 my_settings.py 파일을 추가해서 결론적으로 view 와 settings 에는 시크릿 키가 노출되지 않도록 한다.

1) my_settings.py 파일 만들고 내부에 SECRET_KEY, ALGORITHM, DATABASES선언

2) settings.py에서 my_settings.py 내부의 변수를 사용하기 위해 불러오기
import my_settings.py

3) .gitignore.py 파일 만들고 *.csv, my_settings.py 추가해주기

.gitignore.py 내부에 들어갈 내용 만드는 사이트 : https://www.toptal.com/developers/gitignore

4) views.py 에서 settings.py 의 변수들을 사용하기 위해 import 해주기
from 프로젝트명.settings import SECRET_KEY, ALGORITHM

3. 토큰 발행하기하고 Response 에 넣어주기

이제 views.py 에서 jwt.encode() 메쏘드를 사용할 준비가 완료되었다. 바로 코드에 적용시켜보자. jwt.encode() 결과인 토큰은 역시 bytes 타입이라, JsonResponse 로 보내기 전에 디코딩을 해주고, 딕셔너리에 넣어서 프론트로 전달한다 (views.py 에 작성된 아래 코드에서 SECRET_KEY 나 ALGORITHM 을 알 수 없다).

access_token = jwt.encode(토큰이 갖게되는 정보(주로 유저아이디), 시크릿키, 알고리즘)

type(access_token) -> bytes

 - 토큰을 http response body 에 넣어서 전달했다.

이렇게 되면 프론트에서는 암호화된 user_id 값을 str으로 전달받게 된다. 이 토큰을 한 번 발행해 주고, 앞으로 사용자는 이 토큰을 가지고 어떤 권한에 접근하게 된다.

이 때 전달된 토큰이 DB에 저장된 토큰과 같은지 비교하고 맞는 토큰일 경우에만 함수를 실행하게 된다. 그래서 여러 함수(기능)에 토큰 비교과정을 거칠 수 있게 하기 위해 토큰 확인 함수를 따로 만들고, 그 함수를 Decorator 로 사용하여 기능마다 우선적으로 토큰을 확인할 수 있도록 한다.

지금까지 단방향 암호화를 통해 비밀번호를 암호화하고 토큰을 발행했다. 이전 포스트에서 설명했듯이 누구에게도 날것으로 보이지 않게 하기 위해서였다.
비밀번호 외에도 외부에 함부로 노출되면 안되는 정보들(주소, 휴대폰번호 등)도 데이터베이스에 저장할 때 암호화해서 저장하지만, 서버에서 그 정보를 복호화하여 전송해줘야 하는 경우도 많다. 예를 들어, 쇼핑몰 사이트에서 배송지 이력을 불러와 이전 주소지를 다시 입력하지 않아도 되게 하고, 병원에서 환자의 주민번호를 불러와서 동명이인의 환자를 구별하기도 한다. 이와 같은 경우에는 양방향 암호화를 사용한다.




참고한 사이트
https://pyjwt.readthedocs.io/en/latest/usage.html
https://velopert.com/about
https://www.letmecompile.com/api-auth-jwt-jwk-explained/

0개의 댓글