인증 암호화

BackEnd_Ash.log·2020년 2월 13일
0

단방향

사용자의 비밀번호를 암호화할 때는 단방향 해시 함수가 일반적으로 쓰인다.

이름에서 알 수 있듯이 단방향 해시 함수는 복호화를 할 수 없는 암호화 알고리즘이다.

사용자의 비밀번호를 데이터베이스에 저장할 때는 복호화할 목적으로 저장하지 않고 , 온전히 본래의 비밀번호 값을 알지 못하도록 방지하는 데에 목적이 있다.

패스워드를 단방향 암호화 방식으로 저장하는 경우 패스워드 DB가 털릴경우에도 패스워드 끼리 비교를하면 되기 때문이다.

password2 = 'pass123' 라는 비밀번호를
hash256 이라는 단방향 해시 함수를 사용하면
암호화된 해시 값은 원본 비밀번호 값인 pass123 로 복호화 될 수 없다.

그러므로 원본 메시지를 알면 암호화된 메시지를 구하기는 쉽지만 ,
암호화된 메시지로는 원본 메시지를 구할 수 없어서
단방향성 이라고 한다.

양방향

암호화 된 암호문을 복호화 할 수 있는 기법을 의미한다.
따라서 암호화 / 복호화 시 필요한 key 가 존재 하는데 ,
암호화와 복호화를 같은 키를 사용하느냐 다른 키를 사용하느냐에 따라서
대칭키 / 비 대칭키로 분류할 수 있다.

hash

해시는 데이터를 다루는 기법중에 하나로 검색과 저장이 아주 빠르게 진행이 된다.

키와 실제 데이터의 값이 value 가 한쌍으로 존재한다.
key 값이 배열의 인덱스로 변환된다.
hash 함수는 복잡하지 않은 알고리즘으로 구현되어 상대적으로 cpu 메모리 같은 시스템 자원을 덜 사용하고 , 또 같은 입력 값에 대해서는 같은 출력값이 보장되어 위에서
말한 비밀번호 자체 검증을 가능하게 한다.

비크립트와 암호

지금 사용해 볼 bcrypt는 현재까지 사용되는 가장 강력한 해시 메커니즘이다.

pip install bcrypt

우선적으로 가상환경을 셋팅을 하고 나서 install bcrypt 설치를 해야한다.

import bcrypt
password = '12345'
bcrypt.hashpw(password , bcrypt.gensalt())

raise TypeError("Unicode-objects must be encoded before hashing")
TypeError: Unicode-objects must be encoded before hashing

만 하면 에러가 발생한다.
에러를 읽어보면 hashing 되기전에 우선적으로 encoded 되어야 한다고 나와있네요 .

그럼 지금 상태 12345 는 string 상태인데 이것을 hashing 을 해서 hashpw 함수에 첫번째 인자로 넣어야합니다.

그런데 왜 ???

bcrypt 로 hashing 하기위해서는 bytes 타입으로 인코딩을 해줘야한다.
왜냐하면 우리가 읽을 수 있는것은 유니코드 형식인데 ,
이게 우리가 읽기 좋게 되어있을 뿐이지 컴퓨터가 빠르게 읽을 수 있는것은
bytes 형식이다

password_encode = password.encode('utf-8') # password를 bytes 타입으로 인코딩 됨
password_encode # bytes 타입으로 인코딩 된 비밀번호
bcrypt.hashpw(password_encode , bcrypt.gensalt())
'$2b$12$8Zc91EZ2VlZjNzU0tPw34ujrWwutG5fGcDjFT8Nl9up3w1IDmma7.'

bcrypt 를 암호화 했으면 이것을 저장을 해야한다.
db에 저장할때는 이상태로 또 저장하면 안된다.
이것을 다시 string 으로 바꿔줘야한다.

어떻게 바꿔주지 ?? == > decode 를 해야함
왜 그렇게 해야하지 ?? == > http 통신에서도 bytes 타입을 못받기 때문이다. json 통신

b = bcrypt.hashpw(password_encode , bcrypt.gensalt())
b.decode('utf-8) # 암호화된 비밀번호를 문자열로 디코딩
'$2b$12$8Zc91EZ2VlZjNzU0tPw34ujrWwutG5fGcDjFT8Nl9up3w1IDmma7.'

이 비밀번호는 이제 db에 저장이 되어진다.

회원가입시 이 비밀번호를 db 에 저장이 되었다면 로그인을 할때는 어떻게 해야할까 ??

login_password = '1234'

이렇게만 입력하면 안된다 왜 ?? db에는 bcrypt 로 해서 그것을 decode 해서 string 값으로 들어있으니깐 다른 값이 된다.

login_password = '1234'
bcrypt.checkpw(login_password.encode('utf-8') , b ) 
# login_password 를 인코딩화 한것이랑 b 랑 비교를 한다.
False 
# False 가 나오게 된다. 비밀번호가 12345 라서..
login_password = '12345'
bcrypt.checkpw(login_password.encode('utf-8') ,b )
True

이렇게 하면 이제 로그인이 된것이다.
우리는 로그인 할때마다 계속 이렇게 확인을 해줘야하는것일까??
라는 생각을 해볼 필요가 있다.
사실우리가 하기전에 기존에 있던 개발자가 먼저 생각을 했을것이다.
그결과 토큰이라는것을 만들었다 .

JWT

우선적으로 토큰이 무엇인지 알 필요가 있을것 같다.

Json Web Token 의 약자로 전자 서명 된 URL-safe 의 JSON 이다.

로그인을 한다고 하면 권한이라는것이 엄청 중요할것이다.
내가 누군인지 정당한 사용자인지 아닌지 구별하는것이 중요할 것이다.

토큰은 본인 확인 수단이다. 로그인 할 때 input 에
id 와 pw 를 넣고 로그인을 하면 서버가 그것을 확인해서 pw 가 맞으면 이 사용자가 유효한 사용자라는 토큰을 발행해준다.

  1. 사용자가 로그인한다.

  2. 서버측에서 로그인을 인증하고 맞을경우 클라이언트 측에 signed 토큰을 발급해 준다. signed 란 ??
    해당 토큰이 서버에서 정상적으로 발급된 토큰임을 증명하는 signature 를 담고있다 secret-key 라고 볼 수있다.

  3. 클라이언트측에서 서버로 부터 전달받은 토큰을 저장하고 서버에 요청할 때마다 해당 토큰을 함께 서버에 전달한다.

  4. 서버는 요청이 올때마다 토큰을 검증한다.

토큰 기반 인증의 장점

  1. 확장성이 뛰어나다. 서버가 늘어나도 토큰을 인증하는 방식만 알고 있다면, 영향이 없다

  2. 클라이언트가 서버로 요청할 때 더이상 쿠키를 전달하지 않기 때문에 쿠키를 사용함으로써 발생하는 취약점이 사라진다.

  3. cors 문제가 해결되나 . 어떤 도메인에서도 토큰만 유효하다면 처리가 가능하다.

Jwt 토큰 생성

pip install pyjwt

이제 파이썬에서 jwt 를 임포트해서 토큰을 발행해보겠습니다.
토큰에는 [유저 정보] 와 [secret key] , [적용하고자 하는 알고리즘]
을 넣어서 발행한다.

import jwt
jwt.encode({<유저정보>} , <시크릿키> , algorithm = '특정 알고리즘') # 명령어 구성

token = jwt.encode({'user_id':1} , 'secretkey' , algorithm = 'HS256') # 실제 명령어 작성
token
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxfQ.B9XWphE_QU5UZAT8jhKg_jYNGmZOfSL1gcl-3kZeuoI'

토큰을 발행하게 되면 , 이것을 프론트앤드 개발에게 전달을 해야한다.
전달을 할땐 또 바이너리 상태로 전달해주는것이 아니라
decode 해서 string 상태로 보내야 한다.

즉 지금현재 타입이 bytes 니깐 이것을 string 으로 바꿔서 보냄

$ token.decode('utf-8')    # 문자열로 디코딩
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxfQ.B9XWphE_QU5UZAT8jhKg_jYNGmZOfSL1gcl-3kZeuoI'

그리고 bcrypt 와 다른점은 토큰을 확인할 때 , 토큰을 jwt 로 디코딩하면
기존에 입력했던 유저정보가 반환된다.

$ jwt.decode(token,'secretkey',algorithm = 'HS256')
{'user_id': 1}             # 기존 유저정보 반환
profile
꾸준함이란 ... ?

0개의 댓글