[wecode TIL] 인증/인가

hyuckhoon.ko·2020년 6월 17일
0

What I learned in wecode

목록 보기
55/109

1. 인증 Authentication

홈페이지 사용자를 인식하고 추적하기 위해 인증이란 절차가 필요하다.

현재, 인스타그램 회원가입, 로그인 관련 프로젝트를 진행중인데

유저의 아이디,
이름,
이메일 주소,
비밀번호 등이 인증에 필요한 것들이 될 수가 있다.
이중에서 가장 중요한 비밀번호에 대해 알아보자.



2. 암호화(a.k.a. 단방향 해쉬 함수)

>>> password
'1q2w3e4r'
>>> encoded_password = password.encode('utf-8')
>>> encoded_password
b'1q2w3e4r'
>>> decoded_password = encoded_password.decode('utf-8')
>>> decoded_password
'1q2w3e4r'

맨 처음 입력된 변수 password가 사용자 입력값 데이터라고 가정하자.
실제로 서버관리자 및 DB관련 일을하여도 사용자의 비밀번호를 알 수가 없다고 한다.
왜냐하면

  • 사용자 입력값 그대로 DB에 저장하지 않기 때문이다.
  • 해킹을 방지하기 위해 salting, key-stretching 등의 비밀번호 가공 작업이 있다.

password = '1q2w3e4r'

우선, 비밀번호를 인코딩하여 '바이트(클래스)타입의 b'1q2w3e4r' 형태로 변환하였다. 이것은 이후 bcrypt 라이브러리를 사용하기 위해 가공하는 과정을 거친 것 뿐이다.


>>> hashed_password = bcrypt.hashpw(encoded_password, bcrypt.gensalt())

그로 인해 레인보우 테이블과 같이, 가능한 모든 경우의 수를 해쉬값으로 만들어 판매하는 사이트도 있다.



3. bcrypt

Salting and Key-stretching

  • 음식의 간을 맞추기 위해 소금을 뿌리듯이 사용자의 비밀번호에 추가적인 양념(?)을 더하는 것을 salting이라고 한다.

  • 기존 단방향 해쉬 함수의 알고리즘 실행속도는 매우 빠르다. 그것이 단점으로 작용하여 해커들이 빠른 시간 안에 해킹을 가능케 한다.
    따라서, 해쉬값을 해쉬하고 또 해쉬하는 등 여러번의 반복작업을 한다.

아이디어는 이렇다.

( 입력한 비밀번호 + 임의의 문자열(Salting ) 을 합쳐서
해싱한 결과값을 데이터베이스 사용자 비밀번호에 저장하는 것이다.

물론, 해커의 무작위 대입방식의 해킹을 막기 위하여
키 스트레칭 또한 추가된다.

(Salting과 해싱) 을 여러번 반복하여 원본값을 유추하기 어렵게 한다.


그러면 서버조차도 모른다는 말일까?

우선 gensalt()를 보자.

bcrypt.gensalt()의 결과는 항상 다르게 나온다.

>>> bcrypt.gensalt()
b'$2b$12$d8gj9He0uvJvTpNvGiusU.'

>>> bcrypt.gensalt()
b'$2b$12$4dSmYsKY0CBQZxAh3eHzce'

>>> bcrypt.gensalt()
b'$2b$12$Sr95Nt2mJvJKYkgtgsK6F.'

>>> bcrypt.gensalt()
b'$2b$12$kUya6n5thw5qPSrKzpLvm.'

>>> bcrypt.gensalt()
b'$2b$12$glnKLJkJNIn7YT.DgTPSm.'

>>> bcrypt.gensalt()
b'$2b$12$odFdLOn88Jpcb2niTyogiu'

그 의문에 대한 검증은 다음과 같이 진행했다.

>>> salt
b'$2b$12$vysVDTyLNnYZYcYgg3KBd.'

>>> salt
b'$2b$12$vysVDTyLNnYZYcYgg3KBd.'

>>> hashed_password = bcrypt.hashpw( encoded_password, salt)
>>> hashed_password
b'$2b$12$vysVDTyLNnYZYcYgg3KBd.0hEhaspkIl625kvPOUE5Zy/VLCPC4iu'

salt에 저장된 값이
hashed_password 앞에 있음을 알 수 있다.



그러면 유저의 비밀번호는 데이터베이스에 어떻게 저장해야 하는걸까?

    password = models.CharField(max_length=300)

비밀번호에 대해서 위와 같이 정의를 내렸었다.
해쉬된 비밀번호의 데이터타입은 바이트이기에
디코딩하여 str타입으로 변환시켜 저장한다.

>>> hashed_password
b'$2b$12$vysVDTyLNnYZYcYgg3KBd.0hEhaspkIl625kvPOUE5Zy/VLCPC4iu'
>>> db_password = hashed_password.decode('utf-8')
>>> db_password
'$2b$12$vysVDTyLNnYZYcYgg3KBd.0hEhaspkIl625kvPOUE5Zy/VLCPC4iu'


한번 더 반복!
>>> password = 'myinhyung'
>>> password
'myinhyung'
>>> password.encode('utf-8')
b'myinhyung'
>>> hashed_password = bcrypt.hashpw( password.encode('utf-8'), bcrypt.gensalt())
>>> hashed_password
b'$2b$12$uwDKjsKq.lJ7CZ/m7GPH5OMiEKCGTgb6bRg.AXK7RDHhwRi052lgy'
>>> hashed_password = hashed_password.decode('utf-8')
>>> hashed_password
'$2b$12$uwDKjsKq.lJ7CZ/m7GPH5OMiEKCGTgb6bRg.AXK7RDHhwRi052lgy'

유저 입력 값이 -> 인코딩되고 -> 해쉬된 비밀번호가 되고
-> 다시 디코딩을 통해 -> 데이터베이스에 저장한다.

정말정말 중요한 것은
복호화의 개념이다.

다음 로그인시, 사용자가 비밀번호를 입력했을때
DB에 저장되어 있는 비밀번호를 복호화(암호해독)해서
사용자 입력값과 동일하느냐의 방식으로
진행하지 않는다는 것이다.

단방향 해쉬함수를 사용하고, 복호화를 방지하는 것이
비밀번호 저장의 지향점이다.



Password hashing function

0개의 댓글