TIL-15. westagram 회원가입 비밀번호 암호화

solarrrrr·2021년 10월 26일
0

Today I Learned

목록 보기
15/74

위스타그램 회원가입 비밀번호 암호화하기에 앞서
인증과 인가에 대한 세션을 들었다.

인증(Authentication)은 아이디와 비밀번호 확인 같은
유저의 정보를 확인하는 절차이다.

그런데 개인 정보를, 특히 비밀번호 같은 값을
암호화 없이 그대로 전송하거나 db에 저장한다거나 하면
외부로부터든 내부 관리자로부터든 해킹의 위험에 노출될 수 있다.

사이트 이용자의 정보는 관리자도 알 수 없도록 관리되어야 하며
그러기 위해서는 암호화 과정이 필수이다.

비밀번호 암호화에는 단방향 해쉬 함수가 많이 쓰인다.
단방향 해쉬 함수에 대한 설명은 아래 사진을 보자.

하지만 해쉬 함수도 몇 가지 취약점이 있는데
애초에 패스워드를 저장하기 위해 설계된 것이 아니라
짧은 시간에 많은 데이터를 검색하기 위해 설계되다 보니
해킹 시 악용될 우려가 있었다.
임의의 문자열로 이루어진 다이제스트와 해킹 대상의 다이제스트
비교가 용이해지므로 복잡하지 않은 비밀번호의 경우
길지 않은 시간에 뚫릴 위험이 있다.

또 Rainbow table attack이라는 공격법도 있는데
해쉬값들을 미리 계산해 놓은 테이블을 말한다.

이런 취약점들이 있어서 실무에서 많이 쓰이는 기술이 바로
Bcrypt이다.

Bcrypt에는 일반적으로 2가지 보완점이 존재하는데
SaltingKey Stretching이 그것이다.

Salting은 추가적으로 랜덤 데이터를 비밀번호에 더해서
해시값을 계산하는 방법인데 복잡도가 올라가는 장점이 있다.

Key Stretching은 단방향 해쉬값을 계산한 후,
그 해쉬값을 또 해쉬하고 또 하고, 이렇게 반복하는 것을 말한다.

이번 위스타그램 회원가입 비밀번호 암호화는
Bcrypt에 소금 치는 작업으로 진행했다.

Bcrypt를 pip install을 이용해 장고 내에 설치하고
import 해 준다.
Bcrypt는 빌트인 모듈로서 import 위치는
가장 상단으로 해 주면 된다.

회원가입 시 post로 날아온 자료 중 password 부분을
아래와 같이 암호화한다.

password    = (bcrypt.hashpw(data.get("password").encode('utf-8'), bcrypt.gensalt())).decode('utf-8'),

bcrypt의 hashpw 메서드를 이용하는데 중요한 점은
str 형태로 날아온 값을 bytes로 변경해야 한다는 것이다.
그래서 utf-8로 encode 해 주어야 한다.

이렇게 하면 추측할 수 없는 많은 bytes 값으로 비밀번호가 변경된다.
이후 db에 저장할 때는 문자열로만 넣을 수 있기 때문에
다시 decode 작업을 거쳐야 한다.

decode를 한다고 복호화되는 것은 아니고 db가 인식할 수 있는
문자열의 type으로 변경된다는 점에 주의하자.

이제 로그인 시 들어온 비밀번호와 db에 저장된 비밀번호를
비교하는 코드를 짜야 하는데 나는 아래와 같이 작성했다.

        if User.objects.filter(email=email).exists():
            user = User.objects.get(email=email)
            if bcrypt.checkpw(password.encode('utf-8'), user.password.encode('utf-8')):
                return JsonResponse({"message" : "SUCCESS"}, status=200)

일단 post로 들어온 값에서 이메일 정보를 먼저 확인한다.
db에 해당 유저가 있다면 해당 접속 시도 유저의 패스워드 입력값을
위에서 설명한 Bcrypt로 암호화->encode 하고
db에 저장된 해당 유저의 비밀번호를 가져와서 encode를 해 준 뒤
값을 비교하여 일치하면 통과시킨다.

여기서 중요한 건 값을 비교할 때는 bytes 형태여야 한다는 것이다.
db에는 str 형태로 decode 해서 값을 넣었기 때문에
다시 가져올 때는 반대로 encode 해서
지금 들어온 값의 타입과 맞춰주어야 한다.

그리고 접속 시도한 유저의 패스워드에 접근하는 방법은
일단 테이블이 한 개이므로 손쉽게 가져올 수 있는데,
처음 filter를 사용해 해당 이메일이 존재하는지 여부를 먼저 알아보고 존재한다면 db에서 그 이메일 값을 가져온다.
그리고 그 값에 dot notation으로 password에 접근할 수 있다.


Bcrypt Salting을 할 때 궁금한 부분이 생겼다.
분명 처음 db에 비밀번호를 저장할 때는 암호화 과정에서
Salting을 이용했는데
로그인할 때 비밀번호 확인하는 과정에서는 Salting을 사용하지 않았다.

내 생각엔 로그인 시 post로 들어온 password 값도
최초 회원가입할 때처럼 Salting 과정을 거쳐야
기존에 db에 저장된 값과 비교가 가능해지는 것 아닌가 싶었는데
한편으로 생각하면 어차피 임의의 값이 생성되어 합쳐지는데
로그인 시 Salting 과정을 거친다 해서 값이 비교될 것 같진 않았다.
같은 백엔드(지만 넘사벽 실력) 동기인 지은님도 궁금해했고
멘토님께 상담을 받아봤는데,
Bcrypt가 처리하는 걸로 보인다라는 답변을 받았다고 했다.

음.....
로그인 값은 별도 Salting 없이 암호화가 되고
db 값은 Salting이 가미된 암호화 파일인데
Bcrypt가 알아서 Salting을 걷어내고 비밀번호 부분만
판별한다는 것인가?
아니면 비교 대상이 Salting 값을 가지고 있는지 여부만
판별하는 것일까?
혹은 암호화된 패스워드에 특정한 패턴이 심겨 있어서
이걸 통해 마치 딕셔너리의 key와 value처럼
짝을 찾을 수가 있는 것일까?
패스워드의 암호화 코드에 이러이러한 패턴이 있다면
이러이러한 Salt 값을 가지고 있어야 해.
뭐 이런 건가 싶기도 한데
이 부분은 좀더 검색을 통해 보완해 아래에 남겨놓아야겠다.

profile
몰입

0개의 댓글