[Web] Authentication & Authorization(1) - Authentication(+bcrypt)

Jayson Hwang·2022년 5월 19일
0

Django Basics

목록 보기
9/14
post-thumbnail

1.. Authentication(인증) ??

  • 인증(Authentication)이란 유저의 identification을 확인하는 과정
  • 즉, 아이디와 비밀번호를 확인하는 절차
  • 인증을 하기 위해서는 먼저 유저의 아이디와 비밀번호를 생성(Sign Up)하는 기능,
    그리고 그 유저의 아이디와 비밀번호를 확인(Sign In)하는 기능이 우선적으로 필요
  • 쉽게 말하면, 회원가입과 로그인으로 인증을 구현

1-1.. 로그인 절차

  1. 회원가입이 된 유저가 아이디 & 비밀번호를 입력
  2. 서버에서는 입력한 정보가 DB에 저장된 정보와 일치하는지 확인
  3. 일치하면, 로그인 성공과 함께 클라이언트에 access token을 전송
  4. 로그인에 한번 성공한 유저는 인증된 유저로써 이 서버의 로그인이 필요한 서비스를 이용할 시,
    request에 access token을 첨부하여 서버에 전송해 매번 로그인하지 않도록함


1-2.. 유저 비밀번호 관리

  • 인증에 중요한 것이 바로 비밀번호(password)
  • 비밀번호는 보안을 위해서 반드시 암호화되어서 DB에 저장되어야함
  • 비밀번호가 암호화되지 않은 채로 DB에 저장되있다면, 해킹 시 유저의 정보가 모두에게 노출가능
  • 해킹의 경우가 아니어도 내부 개발자들에게 유저의 정보가 노출될 가능성 있음

1-3.. 비밀번호 암호화 방법

- 해시함수??

  • 임의의 길이의 데이터를고정된 길이의 데이터(Byte열)로 반환시키는 함수
  • 입력값의 길이가 달라도 출력값은 항상 고정된 길이로 반환
  • 동일한 값이 입력되면 언제나 동일한 출력 값을 보장
  • 해시 함수는 암호학적 해시함수와 비 암호학적 해시함수로 구분

- 단방향 암호화

  • 평문을 암호문으로 바꾸는 '암호화'는 가능하지만, 암호문을 평문으로 바꾸는 '복호화'는 불가능한 암호화
  • 비밀번호를 암호화할 때는 주로 단방향 암호화 사용
  • 단방향 암호화에는 주로 해시함수를 사용하는데 이를 단방향 해시 함수(one-way hash function)이라고 함
  • 단방향 해시 함수는 입력값을 문자와 숫자를 임의로 나열한 일정한 길이의 다이제스트(Digest) 형태로 변환 (다이제스트란, 해시함수를 통해 생성된 암호화된 메세지)
  • 단방향 해쉬함수에는 MD5, SHA-1, SHA-256 등이 있음

- 단방향 암호화의 취약점

  • 무차별 대입공격(brute-force attack)에 취약
    - 해시함수는 원래 짧은 시간 안에 데이터를 검색하기 위해 설계
    - 따라서 해시함수는 본래 처리속도가 최대한 빠르도록 설계
    - 이런 속성으로 인해 공격자는 매우 빠른 속도로 임의의 문자열의 다이제스트와 해킹할 대상의 다이제스트를 비교 가능
    - 비밀번호가 충분히 길거나 복잡하지않은 경우 단시간에 알아내는 것이 가능
  • Rainbow table attack에 취약
    - 단방향 해시 함수는 같은 값을 해싱하면 언제나 같은 다이제스트가 나옴
    - 사용자들이 많이 쓰는 패스워드를 미리 해싱하여 결과값을 모아둔 테이블을 Rainbow table이라고 함

- 취약점을 보안하기 위한 기법

1) Salting

  • 소금을 친다는 뜻처럼 실제 비밀번호의 앞, 뒤 아무곳에 랜덤 데이터를 더해서 해시값을 계산하는 방법
  • 사용된 salt 값은 나중에 비밀번호 일치를 확인하기 위해 같이 저장
  • Rainbow table attack을 방지할 수 있는 효과

2) Key Stretching

  • 해시 암호화를 여러 번 반복하는 기법
  • 무차별 대입 공격을 방지하는 효과

1-4.. bcrypt를 이용한 암호화 구현

  • bcrypt는 Salting과 Key Stretching을 구현할 수 있는 라이브러리, 다양한 언어 지원
  • 단방향 암호화하기 위해 만들어진 해쉬함수

1) bcrypt install

$ pip install bcrypt

2) 암호화

::: 한 줄 요약

import bcrypt

# 평문
password = '12345678'

# 암호화하여 저장
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')

# 일치 여부 확인
bcrypt.checkpw('12345678'.encode('utf-8'), hashed_password.encode('utf-8'))

::: bcrypt Method

  • gensalt() : 해시 함수에서 암호화된 비밀번호를 생성할 때 추가 문자열
  • hashpw(password, bcrypt.gensalt()) : 암호화된 비밀번호 생성
  • checkpw(password, hasedpassword) : boolean 타입으로 입력된 값과 암호화된 비밀번호를 비교. 일치할 경우 Ture, 불일치할 경우 False 반환

::: TypeError (encode, decode 문제)

>>> import bcrypt

### password 입력
>>> password = '1234123'

### bcrypt를 이용하여 암호화 (bcrypt.gensalt()는 salt 값을 지정하는 함수)
>>> hased_password = bcrpyt.hashpw(password, bcrypt.gensalt())

:::: 📌 위처럼 평문으로 password값을 지정하면 에러가 뜸

>>> TypeError: Unicode-objects must be encoded berfore hasing

위 에러는 unicode 객체는 반드시 해슁 전에 인코딩하여 넣어야한다는 것을 알려준다.
더 자세히말하면, 현재 password의 타입은 str,
bcrypt를 하기 위해서는 byte 타입으로 만들어(인코딩)줘야함

::: encoding password (str ▶︎ byte)

>> hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())

>>> hashed_password
b'$2b$12$XXdgXRMbmhCcXOwfZsc3XuAEGb6OC2ZrmanIrLWf9on6Z1iGHpWAm'

::: decoding password (byte ▶︎ str)(DB 저장)

# 암호화 된 password를 DB에 저장하기 좋은 형태로 string으로 다시 decode
>>> hashed_password = hashed_password.decode('utf-8')

>>> hashed_password
'$2b$12$XXdgXRMbmhCcXOwfZsc3XuAEGb6OC2ZrmanIrLWf9on6Z1iGHpWAm'

::: checking password

입력받은 값과 DB에 암호화되어 저장되어 있는 비밀번호가 일치하는지 확인하는 과정

>>> bcrypt.checkpw('1234123'.encode('utf-8'), hashed_password.encode('utf-8'))
True

# 일치하면 Ture, 불일치하면 False 반환
# DB에 저장된 암호화된 비밀번호는 byte 타입이 아니므로, checkpw 함수 또한 encode해줘야함
# 참고로, hased_password에는 이미 Salt 값이 저장되어 있으므로, salt값을 가져오는 과정은 필요 없다.

1-5.. Encoding & Decoding

::: Encoding(인코딩)

  • str 타입 ► byte 타입 (utf-8, euc-kr, ascii 형식)
  • 암호화 시 문자열을 byte 타입으로 바꿔줄 때 사용
  • .encode('utf-8')

::: Decoding(디코딩)

  • byte 타입 ► str 타입
  • .decode('utf-8')
profile
"Your goals, Minus your doubts, Equal your reality"

0개의 댓글