[Django] 암호화/로그인을 구현 및 배경지식 스터디

코지클래식·2021년 9월 24일
0

알고리즘

목록 보기
1/1

1. 들어가면서

  1. 3일에 걸쳐서 Django 서버에서 암호화/로그인 기능을 구현했습니다.
  2. bcrypt, JWT 모듈을 사용했습니다.
  3. Django에서 기본으로 제공하는 admin, auth 앱은 사용하지 않았습니다.
  4. 비전공자로써 처음보는, 모르는 내용이 많았습니다.
  5. 구현한 기능 그 자체보다는, 구현하면서 찾아본 몰랐던 내용이 많습니다.

2. 회원가입 기능

구현 방법

  1. 이메일을 ID값(Unique)으로 사용하고
  2. password는 bcrypt를 사용하여 암호화를 구현 했습니다.
  3. 실제로 작성한 코드는 아래정도입니다.
import bcrypt

class 회원가입View :
    def post(self,request) :
        data                = json.loads(request.body)
        data_pw             = data["password"]
        #각종 유효성 검사....
        
        #bcrypt로 암호화하여 DB에 저장
        password_bcrypt     = bcrypt.hashpw(bytes(data_pw,"utf-8"),bcrypt.gensalt())
        
        Users.objects.create(
            ....
            password    =password_bcrypt,
        )
        

헤멘 부분

  1. bcrypt() 작업을 하려면 bytes로 타입을 변경해줘야 하는데,
    a = b'HELLO WORLD!'로 선언하는 방법밖에 몰라 방법을 찾는데 약간 시간이 걸렸습니다.
  2. 미리 암호화를 생각하고 DB의 패스워드 길이를 많이 늘려놔서, 이에 대한 시간낭비는 없었습니다.

암호화?

이 작업을 하면서 암호화를 해야하는 당위성은 이해가 되었습니다.
(서버,DB가 털렸을 때 사용자의 개인정보/비밀번호가 털리면 큰 문제, 책임이 발생하므로 비밀번호는 암호화를 해야함)

그러나
1. 암호화라는게 어떻게 유출을 막는 것인지?
2. 왜 bcrypt 라는 모듈을 사용하는 것인지?
3. 다른 것과는 무슨 차이가 있는지?
등 암호화 자체에 대해 이해가 가지 않아 공부를 하게 되었습니다.



3. 암호화 - 주변 내용

공부한 내용 전체를 적지 않고, 개요만 적습니다.

암호화 - 알고리즘의 종류, 분류

  1. 암호화가 양방향/단방향으로 나뉘고, 대칭키/ 비대칭키가 있고 그 세부 분류

  2. 양방향, 단방향, 대칭키, 비대칭키는은 어떻게 암호화가 이루어지는지에 대한 개요
    ->이를 통해, 왜 암호를 저장할 때 단방향(해시)암호화를 사용하는지 알게 되었습니다.
    (암호화된 비밀번호를 복호화(평문으로 되돌리는것)을 할필요가 없음)

  3. 각 분류에 대해 각각 현재 사용되는 알고리즘

  4. 현재 사용되는 알고리즘의 세부 내용 (Bcrypt)
    그런데 AES를 보려다보니... 디피-헬만 키교환, SSL/TLS, HTTPS에 대한 내용도 보게 되었습니다.

해시, 해시함수

  1. 이전에는 해시라는게 데이터에 주소를 지정해서 input하는 것인줄만 알았는데 이제는 의미를 알았습니다. (데이터배열(head,data)의 전체 길이 및 포인트의 크기를 줄이려고 사용)
  2. "HASH는, 임의의 크기의 데이터를 고정된 크기의 데이터로 변경하는것"의 진짜 의미.

HTTPS, TLS, SSL

  1. 키 분배방색/공유 방식에 대해 공부하다 보니 디피-헬만 키교환 알고리즘,
  2. SSL/ TLS가 작동 방식의 개요를 알게 되었습니다.
  3. 그러나 SSL/TLS에 대해, 인증서의 유효성검사를 어떻게 하는지에 대해서는 아직 알지 못합니다.



4. 로그인 기능

  1. 로그인 성공 시 JWT 모듈로, user_id를 암호화하여 access token을 끼워 응답합니다.
  2. 사용자는 access token을 header에 끼워 응답합니다.
  3. 실제로 작성한 코드는 아래 정도 입니다.
import jwt

    def post(self, request):
        data                = json.loads(request.body)
        data_email          = data["email"]
        jwt_token           = self.make_jwt(data_email)

        return JsonResponse({
            "MESSAGE": "SUCCESS",
            "access_token": jwt_token
            }, status=200
        )
    def get(self, request):     
        if "Access-Token" in request.headers : 
            access_token = request.headers["Access-Token"]
            if self.check_jwt(access_token) : 
                return HttpResponse("You are Logined!")
        return HttpResponse("YOU ARE NOT Logined!")

헤더로 전달?

로그인(인증) 기능을 구현하면서, access token을 헤더로 전달하고 헤더에서 데이터를 확인할 방법을 몰라 많이 헤맸습니다. jwt 공식문서에는 애초에 encode, decode에 대한 방법만 나와 있고, 이걸 응답에 포함하는 부분은 금방 작업했습니다.
그러나, 이 access token을 브라우저에 저장시키는 방법은 무엇인지? 또 access token을 다시 서버에서 input값으로 받으려면 어떻게 해야 하는지? 에 대한 설명이 전혀 없었습니다. (로그인 상태 유지)

현재 프론트엔드/HTML 부분을 아예 작업하지 않고 있습니다.
이에 따라 일단 브라우저에 저장시키는 방법은 넘어가고, (브라우저로 작업하지 않을 거니까)
form 형태로 post 하는 법 이외에 header에 데이터를 포함해 전달 받는 방법을 찾아야 했습니다.

5. 로그인 기능 - 주변 내용

access token, OAuth

데이터를 전달하는 방법을 찾기 전에, 대체 이 access token이 무엇인지 알아 봤습니다.
어렴풋이 알고 있던 쿠키가 이제 로그인 기능엔 사용되지 않는다는 점,
캐시/쿠키/세션/토큰의 차이에 대해 알게 되었습니다.

이에 따라 token이 주로 OAuth라는 데에 사용된다는 것도 알게 되어, OAuth에 대해 또 확인하고 넘어갔습니다. (생활코딩을 보니 실제로 구글계정에 대해 등록/인증 받는 법이 나와 있어서 다 봤음)

그러고 나니, OAuth에서 사용하는 Token이라는게, 3자간 통신에 사용하는 것이라,
제가 구현하고 있는 내용과는 다른 것을 깨달았습니다.

HTTPie

token을 헤더에 포함시켜서 request를 발생시키기 위해 HTTPie의 각종 메서드를 찾아 봤습니다. (기존에 회원가입 할 때부터 이미 사용하고 있었지만, 어렴풋이 쓰던 것만 쓰고 있었음)
이제 원하는 데이터를 원하는 위치에 집어넣을 수 있습니다.
좀 헤맨 부분이 있었는데, header에는 언더바( _ )가 들어가지 못하는데, 이를 몰라 시간을 좀 헤맸습니다.

유효성 검사

사실상 실패한 부분입니다. 시간을 기준으로 유효성을 만들어야 했는데, shell에서 데이터를 하나하나 만들고 붙여넣기를 해야하는 작업이 너무 번거로워서 시간에 따라 유효성 검사를 하는 것은 완성하지 못했습니다.
일단 구현한 유효성 검사 방식은 다음과 같습니다.

  1. JWT로 암호화된 토큰을 서버에서 받아 decode한 후, 다시 encode
  2. 추출된 id를 기준으로 DB의 데이터를 다시 JWT로 암호화
  3. 1,2의 값이 동일한지 비교

그런데 이는 매번 ID/PW를 받는 것과 별로 차이가 없지 않나? 싶어 사실상 실패했다고 생각됩니다.

또, 토큰에 오류가 있어서 decode에 실패했을 때, 그리고 데이터의 id값이 DB에 존재하지 않을 때 발생하는 오류를 server status = 500이 아닌 다른 값으로 만드는 데까지는 실패했습니다. JWT 모듈에 대해 더 공부가 필요한 것으로 보입니다. (이후에 시간에 따른 유효성을 넣을 때 같이 첨부할 것)

6. 마치며

느낀점 1

이전까지는 Django에서 기본으로 제공하던 ID/PW 기능만 사용했었는데, 이를 직접 구현하려니 처음보는 내용이 많고 막막했습니다. 특히 암호화/알고리즘을 공부할 때는 "내가 어디까지 알아야하지?"라는 생각이 머리속에 끊이질 않았습니다.

다만 이런 암호화 알고리즘들을 직접 구현하거나 달달 외우지는 못하더라도, 개요 정도는 떠올릴 수 있는 상태가 되어, 어떤 과정으로, 어떤 input이 있으면 어떤 output이 나오는지 정도는 알게 된 것 같아 의미 있는 시간이었다고 생각합니다. (금방 까먹을 수 도 있겠지만!)

따지고 보면 10줄~20줄의 코드를 작성한 것 뿐인데 대체 뭐가 이렇게 찾아볼 내용이 많은지 ... 라는 기분도 있지만, 이번 한 번 뿐이고, 대신 다음에 비슷한 암호화/로그인 기능을 구현할 때에는 훨씬 빠르게 작업이 가능할 거라는 자신감이 생깁니다.

느낀점 2

코드 한줄을 치더라도, "왜?" 라는 생각을 하며 작성하자는 생각이 있습니다. (지금은)
다만 지금처럼 공부하는 과정이 아니라 업무를 하게 되면 시간에 쫓기고, 결국 복사+붙여넣기를 하게 되지 않을까... 하는데 결국 어떤 방식으로 나가는것이 결과적으로 효율성이 높을지 생각만 많습니다.

profile
코지베어

0개의 댓글