WIL #10 인증&인가
🤷 기간 : 2021.05.03 ~ 2021.05.03
🤷 자료 : https://www.notion.so/wecode/Django-C-R-U-D-2-98d0ec4c3de844338e769096aee13537
🤷 내용: ORM 과제 리뷰
인증 & 인가
- 인증이란?
- 비밀번호 암호화는 어떻게 이루어지는가?
What You Will Learn
- 단방향 해쉬함수 그리고 레인보우 테이블 어택
- 설팅과 키스트레칭 그리고 bcrypt
- 인가란?
- JWT에 대해 배워봅시다.
인증(Authentication) & 인가(Authorization)
- 인증과 인가는 API에서 가장 자주 구현되는 기능 가운데 하나입니다.
- Private한 API는 물론이고 Public한 API도 기본적인 인증과 인가를 요구합니다.
인증(Authentication)
- Authentication은 유저의 identification을 확인하는 절차
- 즉, 유저의 아이디와 비번을 확인하는 절차
로그인 절차
- 유저 아이디와 비번 생성
- 유저 비번 암호화 해서 DB에 저장.
- 유저 로그인 -> 아이디와 비밀번호 입력
- 유저가 입력한 비밀번호 암호화 한후 암호화되서 DB에 저정된 유저 비밀번호와 비교.
- 일치하면 로그인 성공
- 로그인 성공하면
access token
을 클라이언트에게 전송.(JWT)
- 유저는 로그인 성공후 다음부터는
access token
을 첨부해서 request를 서버에 전송함으로서 매번 로그인 해도 되지 않도록 한다.
유저 비밀번호 암호화
왜 비밀번호를 암호화 하는가 ?
- 유저의 비밀번호는 그대로 database에 저장하면 안돼 !
- database해킹당하면 비밀번호도 그대로 노출되고,
- 내부 개발자나 유저들도 비밀번호를 볼 수 있기 떄문
-> 그렇기 때문에 비밀번호는 암호화해서 저장해야한다!!!!!!!!!!!!
암호화를 하는 방법
- 비밀번호 암호를 위해 일반적으로
단방향 해쉬 함수(one-way hash function)
를 쓴다.
단방향 해시 함수
는 들어온 원본 메세지를 암호화된 메세지(다이제스트(digest)
)로 변환시킨다
- 예를 들어,
"test password"를 hash256이라는 해쉬 함수를 사용용시
->
b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e 값 출력
"test password2"를 hash256 해쉬 함수를 사용시'
-> d34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb 값출력
- 실제 비밀번호는 비슷 but
해쉬 함수값
은 완전히 다름
- 이러한 효과를
avalance
라고 부른다.
- 비밀번호 해쉬 값을 해킹을 어렵게 만드는 하나의 요소
- ex
In [21]: import hashlib
In [22]: m = hashlib.sha256()
In [23]: m.update(b"test password")
In [24]: m.hexdigest()
Out[24]: '0b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e'
In [25]: m = hashlib.sha256()
In [26]: m.update(b"test password2")
In [27]: m.hexdigest()
Out[27]: 'd34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb'
Bcrypt
단방향 해쉬 함수의 취약점
Rainbow table
attack
Rainbow table
: 미리 해쉬값들을 계산해 놓은 테이블
해시 함수
는 짧은 시간에 데이터를 검색하기 위해 설계된 것
- 원래 패스워드를 저장하기 위해서 설계된 것은 본래 목적이 아님
해시 함수
는 본래 처리 속도가 최대한 빠르도록 설계 이러한 속성 때문에, 공격자는 매우 빠른 속도로 임의의 문자열의 다이제스트
와 해킹할 대상의 다이제스트
비교할 수 있다.
- 이런 방식으로 공격하는데 패스워드가 그냥 쉽게 그렇게 되어있으면 걍 뚤리지
그에 따른, 보완점
- 일반적으로 2가지 보완점 사용
- Salting
- 실제 비밀번호 이외 추가적으로 데이터를 랜덤으로 더해서
해시값
계산
- Key Stretching
- 단방향 해쉬값
을 계산 한 후, 그 해쉬값
에 반복하는 해서 해쉬하는 것
- Salting과 Key Stretching을 구현한 해쉬 함수중 가장 널리 사용되는 것이 bcrypt이다. bcrypt는 처음부터 비밀번호를 단방향 암호화 하기 위해 만들이전 해쉬함수 이다.
In [40]: import bcrypt
In [41]: bcrypt.hashpw(b"secrete password", bcrypt.gensalt())
Out[41]: b'$2b$12$.XIJKgAepSrI5ghrJUaJa.ogLHJHLyY8ikIC.7gDoUMkaMfzNhGo6'
In [42]: bcrypt.hashpw(b"secrete password", bcrypt.gensalt()).hex()
Out[42]: '243262243132242e6b426f39757a69666e344f563852694a43666b5165445469397448446c4d366635613542396847366d5132446d62744b70357353'
JWT(JSON Web Tokens)
-
유저가 로그인에 성공한 후에는 access token
(암호화된 유저 정보)를 첨부해서 request
를 보내게 된다.
- 유저 로그인:
POST /auth HTTP/1.1
Host: localhost:5000
Content-Type: application/json
{
"username": "joe",
"password": "pass"
}
- access token:
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
}
-
그러면 서버에서는 암호화 되어있는 access token
을 복호화(<->암호화) 해서 기존 정보를 얻을 수 있다 !
-
예를들어 access token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E
를 복호화 하면 다음과 같은 정보를 얻는다:
{
user_id = 1
}
-
위와 같이 복호화해서 얻은 유저 아이디를 통해 해당 유저가 누군지 알 수 있다.
-> 이런 절차의 목적은 해당 유저가 매번 로그인 해도 되지 않도록 하는 것이다.
JWT(JSON Web Tokens)
access token
을 생성하는 방법은 여러가지가 있는데, 그 중 가장 널리 사용되는 기술중 하가 바로 JWT(JSON Web Tokens)이다.
JWT(JSON Web Tokens)
:
1. 유저 정보를 담음다음
2. JSON 데이터를 암호화하고,
3. 클라이언트와 서버간에 주고 받는 것이다.
Why Use Access Token VS ID and Password?
- Performance
- 완전 심플한
해쉬
임
- 사용자 사이드의 저장소
- 실제 ID와 비밀번호가 저장되는게 아님
- 다른 사이트에서 절대 재사용 노노
인가(Authorization)
- Authorization은 유저가 요청하는 request를 실행할 수 있는 권한이 있는 유저인가를 확인하는 절차
- 해당 유저는 고객 정보를 볼 수 있는 있지만 수정 할 수는 없다 등.
- Authroization도
JWT
를 통해서 구현 될 수 있다.
access token
을 통해 해당 유저 정보를 얻을 수 있음으로 해당 유저가 가지고 있는 권한(permission)도 확인 할 수 있다.
Authorization 절차
- Authentication 절차를 통해
access token
을 생성한다. access token
에는 유저 정보를 확인할 수 있는 정보가 들어가 있어야 한다 (예를 들어 user id).
- 유저가 request를 보낼때
access token
을 첨부해서 보낸다.
- 서버에서는 유저가 보낸
access token
을 복호화 한다.
- 복호화된 데이터를 통해 user id를 얻는다.
- user id를 사용해서 database에서 해당 유저의 권한(permission)을 확인하다.
- 유저가 충분한 권한을 가지고 있으면 해당 요청을 처리한다.
- 유저가 권한을 가지고 있지 않으면 Unauthorized Response(401) 혹은 다른 에러 코드를 보낸다.
Backend Auth
백엔드 개발자가 인증 $ 인가를 구현하기 위한 필수요건 및 코드
1. bcrypt
설치 및 import
pip install bcrypt # 암호화를 위한 "Bcrypt" 라이브러리 설치
import bcrypt # 설치된 "Bcrpyt" import/ python 들어가서 해야해
bcrypt
의 암호화 방법!
- bcrypt는
Bytes
(이진화) 데이터를 암호화(str
아님)해야함
- 그렇기 때문에, 먼저
str
로 들어온 걸 bytes
화를 해야 암호화를 진행 할 수 있다.
str
-> encode
-> bytes
되고,
bytes
-> decode
-> str
화 합니다.
****여기서, encode
& decode
시 에는 우리가 인식할 수 있는 형태로 변환하기 위해 'UTF-8' 유니코드 문자 규격을 사용해야함
2. 비밀번호 암호화
bcrypt.hashpw(입력받은 패스워드.encode('utf-8'),bcrypt.gensalt())
사용
password = '1234'
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) # 암호화 코드 확인해봐
print(hashed_password)
b'$2b$12$YFs9rh.1LgJwZuf9ibyjpuLvBoCaGX0MzedFWF2Jo0zU3lMZurZ4a'
- 암호화 코드의 타입 확인
type(hashed_password)
<class 'bytes'> # 바이트 나왔지 ?
- 이렇게 암호화된 방식은 일방향 암호화이며,
- 즉, 복호화 할 수 없도록 암호화하는 방식입니다.
- 비밀번호 확인
bcrypt.checkpw(입력받은 패스워드.encode(utf-8), 저장된 암호화된 패스워드)
사용
- 추가적으로
입력받은 패스워드.encode(utf-8)
와 저장된 암호화된 배스워드
는 bytes
여야함
new_password = '1234'
bcrypt.checkpw(new_password.encode('utf-8'),hashed_password)
True
3. JWT(JSON Web Token)
구현
pyjwt
설치
pip install pyjwt # jwt구현을 위한 pyjwt 설치
- 인증을 위한 매개체(
access_token
) 생성
access_token = jwt.encode(헤더값, SECRET, algorithm = 'HS256')
을 통한 암호화
import jwt # 패키지명은 pyjwt이지만 임포트할때의 이름은 jwt입니다.
SECRET = 'secret' #'랜덤한 조합의 키' 예제이므로 단순하게 'secret'이라고 하겠습니다.
access_token = jwt.encode({'id' : 1}, SECRET, algorithm = 'HS256') # "header값"- {'id' : 1}
print(access_token)
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MX0.-xXA0iKB4mVNvWLYFtt2xNiYkFpObF54J9lj2RwduAI'
이렇게 발급된 토큰은 어떻게 사용할 수 있을까요?
- 바로 프론트에 전달하세요 ! - 어떻게 .. ? ?/
- 로그인이 성공 시, 위 같이 발행한 토큰을 프론트에 전달합시다 !
- **이제 인증을 위한 기본 요건이 달성 되었고, 인증을 통과한 사용자만 접근하려면 토큰을 받아서 다시 우리가 발행한 토큰이 맞는지 확인 해야겠져 ?
jwt.decode(access_token, SECRET, algorithm = 'HS256')
를 통한 복호화
header = jwt.decode(access_token, SECRET, algorithm = 'HS256')
print(header)
{'id': 1} # 아까 encode한거의 헤더값인 "{'id': 1}"이다 ! !!
이제 ,인증하는 코드는 어디에 구현해야 할까요?
- 바로 엔드포인트에 데코레이터를 구현함돠 !~ !
- 데코레이터 구현은 보통 user app에 utils.py를 만들어서 작성
Author And Source
이 문제에 관하여(WIL #10 인증&인가), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@shinisgood/WIL-10
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
- 단방향 해쉬함수 그리고 레인보우 테이블 어택
- 설팅과 키스트레칭 그리고 bcrypt
- 인가란?
- JWT에 대해 배워봅시다.
인증(Authentication) & 인가(Authorization)
- 인증과 인가는 API에서 가장 자주 구현되는 기능 가운데 하나입니다.
- Private한 API는 물론이고 Public한 API도 기본적인 인증과 인가를 요구합니다.
인증(Authentication)
- Authentication은 유저의 identification을 확인하는 절차
- 즉, 유저의 아이디와 비번을 확인하는 절차
로그인 절차
- 유저 아이디와 비번 생성
- 유저 비번 암호화 해서 DB에 저장.
- 유저 로그인 -> 아이디와 비밀번호 입력
- 유저가 입력한 비밀번호 암호화 한후 암호화되서 DB에 저정된 유저 비밀번호와 비교.
- 일치하면 로그인 성공
- 로그인 성공하면
access token
을 클라이언트에게 전송.(JWT)
- 유저는 로그인 성공후 다음부터는
access token
을 첨부해서 request를 서버에 전송함으로서 매번 로그인 해도 되지 않도록 한다.
유저 비밀번호 암호화
왜 비밀번호를 암호화 하는가 ?
- 유저의 비밀번호는 그대로 database에 저장하면 안돼 !
- database해킹당하면 비밀번호도 그대로 노출되고,
- 내부 개발자나 유저들도 비밀번호를 볼 수 있기 떄문
-> 그렇기 때문에 비밀번호는 암호화해서 저장해야한다!!!!!!!!!!!!
암호화를 하는 방법
- 비밀번호 암호를 위해 일반적으로
단방향 해쉬 함수(one-way hash function)
를 쓴다.
단방향 해시 함수
는 들어온 원본 메세지를 암호화된 메세지(다이제스트(digest)
)로 변환시킨다
- 예를 들어,
"test password"를 hash256이라는 해쉬 함수를 사용용시
->
b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e 값 출력
"test password2"를 hash256 해쉬 함수를 사용시'
-> d34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb 값출력
- 실제 비밀번호는 비슷 but
해쉬 함수값
은 완전히 다름
- 이러한 효과를
avalance
라고 부른다.
- 비밀번호 해쉬 값을 해킹을 어렵게 만드는 하나의 요소
- ex
In [21]: import hashlib
In [22]: m = hashlib.sha256()
In [23]: m.update(b"test password")
In [24]: m.hexdigest()
Out[24]: '0b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e'
In [25]: m = hashlib.sha256()
In [26]: m.update(b"test password2")
In [27]: m.hexdigest()
Out[27]: 'd34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb'
Bcrypt
단방향 해쉬 함수의 취약점
Rainbow table
attack
Rainbow table
: 미리 해쉬값들을 계산해 놓은 테이블
해시 함수
는 짧은 시간에 데이터를 검색하기 위해 설계된 것
- 원래 패스워드를 저장하기 위해서 설계된 것은 본래 목적이 아님
해시 함수
는 본래 처리 속도가 최대한 빠르도록 설계 이러한 속성 때문에, 공격자는 매우 빠른 속도로 임의의 문자열의 다이제스트
와 해킹할 대상의 다이제스트
비교할 수 있다.
- 이런 방식으로 공격하는데 패스워드가 그냥 쉽게 그렇게 되어있으면 걍 뚤리지
그에 따른, 보완점
- 일반적으로 2가지 보완점 사용
- Salting
- 실제 비밀번호 이외 추가적으로 데이터를 랜덤으로 더해서
해시값
계산
- Key Stretching
- 단방향 해쉬값
을 계산 한 후, 그 해쉬값
에 반복하는 해서 해쉬하는 것
- Salting과 Key Stretching을 구현한 해쉬 함수중 가장 널리 사용되는 것이 bcrypt이다. bcrypt는 처음부터 비밀번호를 단방향 암호화 하기 위해 만들이전 해쉬함수 이다.
In [40]: import bcrypt
In [41]: bcrypt.hashpw(b"secrete password", bcrypt.gensalt())
Out[41]: b'$2b$12$.XIJKgAepSrI5ghrJUaJa.ogLHJHLyY8ikIC.7gDoUMkaMfzNhGo6'
In [42]: bcrypt.hashpw(b"secrete password", bcrypt.gensalt()).hex()
Out[42]: '243262243132242e6b426f39757a69666e344f563852694a43666b5165445469397448446c4d366635613542396847366d5132446d62744b70357353'
JWT(JSON Web Tokens)
-
유저가 로그인에 성공한 후에는 access token
(암호화된 유저 정보)를 첨부해서 request
를 보내게 된다.
- 유저 로그인:
POST /auth HTTP/1.1
Host: localhost:5000
Content-Type: application/json
{
"username": "joe",
"password": "pass"
}
- access token:
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
}
-
그러면 서버에서는 암호화 되어있는 access token
을 복호화(<->암호화) 해서 기존 정보를 얻을 수 있다 !
-
예를들어 access token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E
를 복호화 하면 다음과 같은 정보를 얻는다:
{
user_id = 1
}
-
위와 같이 복호화해서 얻은 유저 아이디를 통해 해당 유저가 누군지 알 수 있다.
-> 이런 절차의 목적은 해당 유저가 매번 로그인 해도 되지 않도록 하는 것이다.
JWT(JSON Web Tokens)
access token
을 생성하는 방법은 여러가지가 있는데, 그 중 가장 널리 사용되는 기술중 하가 바로 JWT(JSON Web Tokens)이다.
JWT(JSON Web Tokens)
:
1. 유저 정보를 담음다음
2. JSON 데이터를 암호화하고,
3. 클라이언트와 서버간에 주고 받는 것이다.
Why Use Access Token VS ID and Password?
- Performance
- 완전 심플한
해쉬
임
- 사용자 사이드의 저장소
- 실제 ID와 비밀번호가 저장되는게 아님
- 다른 사이트에서 절대 재사용 노노
인가(Authorization)
- Authorization은 유저가 요청하는 request를 실행할 수 있는 권한이 있는 유저인가를 확인하는 절차
- 해당 유저는 고객 정보를 볼 수 있는 있지만 수정 할 수는 없다 등.
- Authroization도
JWT
를 통해서 구현 될 수 있다.
access token
을 통해 해당 유저 정보를 얻을 수 있음으로 해당 유저가 가지고 있는 권한(permission)도 확인 할 수 있다.
Authorization 절차
- Authentication 절차를 통해
access token
을 생성한다. access token
에는 유저 정보를 확인할 수 있는 정보가 들어가 있어야 한다 (예를 들어 user id).
- 유저가 request를 보낼때
access token
을 첨부해서 보낸다.
- 서버에서는 유저가 보낸
access token
을 복호화 한다.
- 복호화된 데이터를 통해 user id를 얻는다.
- user id를 사용해서 database에서 해당 유저의 권한(permission)을 확인하다.
- 유저가 충분한 권한을 가지고 있으면 해당 요청을 처리한다.
- 유저가 권한을 가지고 있지 않으면 Unauthorized Response(401) 혹은 다른 에러 코드를 보낸다.
Backend Auth
백엔드 개발자가 인증 $ 인가를 구현하기 위한 필수요건 및 코드
1. bcrypt
설치 및 import
pip install bcrypt # 암호화를 위한 "Bcrypt" 라이브러리 설치
import bcrypt # 설치된 "Bcrpyt" import/ python 들어가서 해야해
bcrypt
의 암호화 방법!
- bcrypt는
Bytes
(이진화) 데이터를 암호화(str
아님)해야함
- 그렇기 때문에, 먼저
str
로 들어온 걸 bytes
화를 해야 암호화를 진행 할 수 있다.
str
-> encode
-> bytes
되고,
bytes
-> decode
-> str
화 합니다.
****여기서, encode
& decode
시 에는 우리가 인식할 수 있는 형태로 변환하기 위해 'UTF-8' 유니코드 문자 규격을 사용해야함
2. 비밀번호 암호화
bcrypt.hashpw(입력받은 패스워드.encode('utf-8'),bcrypt.gensalt())
사용
password = '1234'
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) # 암호화 코드 확인해봐
print(hashed_password)
b'$2b$12$YFs9rh.1LgJwZuf9ibyjpuLvBoCaGX0MzedFWF2Jo0zU3lMZurZ4a'
- 암호화 코드의 타입 확인
type(hashed_password)
<class 'bytes'> # 바이트 나왔지 ?
- 이렇게 암호화된 방식은 일방향 암호화이며,
- 즉, 복호화 할 수 없도록 암호화하는 방식입니다.
- 비밀번호 확인
bcrypt.checkpw(입력받은 패스워드.encode(utf-8), 저장된 암호화된 패스워드)
사용
- 추가적으로
입력받은 패스워드.encode(utf-8)
와 저장된 암호화된 배스워드
는 bytes
여야함
new_password = '1234'
bcrypt.checkpw(new_password.encode('utf-8'),hashed_password)
True
3. JWT(JSON Web Token)
구현
pyjwt
설치
pip install pyjwt # jwt구현을 위한 pyjwt 설치
- 인증을 위한 매개체(
access_token
) 생성
access_token = jwt.encode(헤더값, SECRET, algorithm = 'HS256')
을 통한 암호화
import jwt # 패키지명은 pyjwt이지만 임포트할때의 이름은 jwt입니다.
SECRET = 'secret' #'랜덤한 조합의 키' 예제이므로 단순하게 'secret'이라고 하겠습니다.
access_token = jwt.encode({'id' : 1}, SECRET, algorithm = 'HS256') # "header값"- {'id' : 1}
print(access_token)
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MX0.-xXA0iKB4mVNvWLYFtt2xNiYkFpObF54J9lj2RwduAI'
이렇게 발급된 토큰은 어떻게 사용할 수 있을까요?
- 바로 프론트에 전달하세요 ! - 어떻게 .. ? ?/
- 로그인이 성공 시, 위 같이 발행한 토큰을 프론트에 전달합시다 !
- **이제 인증을 위한 기본 요건이 달성 되었고, 인증을 통과한 사용자만 접근하려면 토큰을 받아서 다시 우리가 발행한 토큰이 맞는지 확인 해야겠져 ?
jwt.decode(access_token, SECRET, algorithm = 'HS256')
를 통한 복호화
header = jwt.decode(access_token, SECRET, algorithm = 'HS256')
print(header)
{'id': 1} # 아까 encode한거의 헤더값인 "{'id': 1}"이다 ! !!
이제 ,인증하는 코드는 어디에 구현해야 할까요?
- 바로 엔드포인트에 데코레이터를 구현함돠 !~ !
- 데코레이터 구현은 보통 user app에 utils.py를 만들어서 작성
Author And Source
이 문제에 관하여(WIL #10 인증&인가), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@shinisgood/WIL-10
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
- 즉, 유저의 아이디와 비번을 확인하는 절차
access token
을 클라이언트에게 전송.(JWT)access token
을 첨부해서 request를 서버에 전송함으로서 매번 로그인 해도 되지 않도록 한다.- database해킹당하면 비밀번호도 그대로 노출되고,
- 내부 개발자나 유저들도 비밀번호를 볼 수 있기 떄문
-> 그렇기 때문에 비밀번호는 암호화해서 저장해야한다!!!!!!!!!!!!
단방향 해쉬 함수(one-way hash function)
를 쓴다.단방향 해시 함수
는 들어온 원본 메세지를 암호화된 메세지(다이제스트(digest)
)로 변환시킨다- 예를 들어,
"test password"를 hash256이라는 해쉬 함수를 사용용시 -> b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e 값 출력
"test password2"를 hash256 해쉬 함수를 사용시' -> d34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb 값출력
- 실제 비밀번호는 비슷 but
해쉬 함수값
은 완전히 다름 - 이러한 효과를
avalance
라고 부른다.- 비밀번호 해쉬 값을 해킹을 어렵게 만드는 하나의 요소
- ex
In [21]: import hashlib In [22]: m = hashlib.sha256() In [23]: m.update(b"test password") In [24]: m.hexdigest() Out[24]: '0b47c69b1033498d5f33f5f7d97bb6a3126134751629f4d0185c115db44c094e'
In [25]: m = hashlib.sha256() In [26]: m.update(b"test password2") In [27]: m.hexdigest() Out[27]: 'd34b32af5c7bc7f54153e2fdddf251550e7011e846b465e64207e8ccda4c1aeb'
Rainbow table
attackRainbow table
: 미리 해쉬값들을 계산해 놓은 테이블해시 함수
는 짧은 시간에 데이터를 검색하기 위해 설계된 것- 원래 패스워드를 저장하기 위해서 설계된 것은 본래 목적이 아님
해시 함수
는 본래 처리 속도가 최대한 빠르도록 설계 이러한 속성 때문에, 공격자는 매우 빠른 속도로임의의 문자열의 다이제스트
와해킹할 대상의 다이제스트
비교할 수 있다.- 이런 방식으로 공격하는데 패스워드가 그냥 쉽게 그렇게 되어있으면 걍 뚤리지
- Salting
- 실제 비밀번호 이외 추가적으로 데이터를 랜덤으로 더해서
해시값
계산
- 실제 비밀번호 이외 추가적으로 데이터를 랜덤으로 더해서
- Key Stretching
-단방향 해쉬값
을 계산 한 후, 그해쉬값
에 반복하는 해서 해쉬하는 것
In [40]: import bcrypt
In [41]: bcrypt.hashpw(b"secrete password", bcrypt.gensalt())
Out[41]: b'$2b$12$.XIJKgAepSrI5ghrJUaJa.ogLHJHLyY8ikIC.7gDoUMkaMfzNhGo6'
In [42]: bcrypt.hashpw(b"secrete password", bcrypt.gensalt()).hex()
Out[42]: '243262243132242e6b426f39757a69666e344f563852694a43666b5165445469397448446c4d366635613542396847366d5132446d62744b70357353'
유저가 로그인에 성공한 후에는 access token
(암호화된 유저 정보)를 첨부해서 request
를 보내게 된다.
- 유저 로그인:
POST /auth HTTP/1.1
Host: localhost:5000
Content-Type: application/json
{
"username": "joe",
"password": "pass"
}
- access token:
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
}
그러면 서버에서는 암호화 되어있는 access token
을 복호화(<->암호화) 해서 기존 정보를 얻을 수 있다 !
-
예를들어 access token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E
를 복호화 하면 다음과 같은 정보를 얻는다:{ user_id = 1 }
-
위와 같이 복호화해서 얻은 유저 아이디를 통해 해당 유저가 누군지 알 수 있다.
-> 이런 절차의 목적은 해당 유저가 매번 로그인 해도 되지 않도록 하는 것이다.
access token
을 생성하는 방법은 여러가지가 있는데, 그 중 가장 널리 사용되는 기술중 하가 바로 JWT(JSON Web Tokens)이다.JWT(JSON Web Tokens)
:
1. 유저 정보를 담음다음
2. JSON 데이터를 암호화하고,
3. 클라이언트와 서버간에 주고 받는 것이다.
- 완전 심플한
해쉬
임
- 실제 ID와 비밀번호가 저장되는게 아님
- 다른 사이트에서 절대 재사용 노노
- 해당 유저는 고객 정보를 볼 수 있는 있지만 수정 할 수는 없다 등.
JWT
를 통해서 구현 될 수 있다.access token
을 통해 해당 유저 정보를 얻을 수 있음으로 해당 유저가 가지고 있는 권한(permission)도 확인 할 수 있다.
access token
을 생성한다. access token
에는 유저 정보를 확인할 수 있는 정보가 들어가 있어야 한다 (예를 들어 user id).access token
을 첨부해서 보낸다.access token
을 복호화 한다.bcrypt
설치 및 import
pip install bcrypt # 암호화를 위한 "Bcrypt" 라이브러리 설치
import bcrypt # 설치된 "Bcrpyt" import/ python 들어가서 해야해
bcrypt
의 암호화 방법!- bcrypt는
Bytes
(이진화) 데이터를 암호화(str
아님)해야함 - 그렇기 때문에, 먼저
str
로 들어온 걸bytes
화를 해야 암호화를 진행 할 수 있다.str
->encode
->bytes
되고,bytes
->decode
->str
화 합니다.
encode
& decode
시 에는 우리가 인식할 수 있는 형태로 변환하기 위해 'UTF-8' 유니코드 문자 규격을 사용해야함bcrypt.hashpw(입력받은 패스워드.encode('utf-8'),bcrypt.gensalt())
사용password = '1234'
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) # 암호화 코드 확인해봐
print(hashed_password)
b'$2b$12$YFs9rh.1LgJwZuf9ibyjpuLvBoCaGX0MzedFWF2Jo0zU3lMZurZ4a'
type(hashed_password)
<class 'bytes'> # 바이트 나왔지 ?
- 이렇게 암호화된 방식은 일방향 암호화이며,
- 즉, 복호화 할 수 없도록 암호화하는 방식입니다.
bcrypt.checkpw(입력받은 패스워드.encode(utf-8), 저장된 암호화된 패스워드)
사용- 추가적으로
입력받은 패스워드.encode(utf-8)
와저장된 암호화된 배스워드
는bytes
여야함
- 추가적으로
new_password = '1234'
bcrypt.checkpw(new_password.encode('utf-8'),hashed_password)
True
JWT(JSON Web Token)
구현pyjwt
설치pip install pyjwt # jwt구현을 위한 pyjwt 설치
access_token
) 생성access_token = jwt.encode(헤더값, SECRET, algorithm = 'HS256')
을 통한 암호화
import jwt # 패키지명은 pyjwt이지만 임포트할때의 이름은 jwt입니다.
SECRET = 'secret' #'랜덤한 조합의 키' 예제이므로 단순하게 'secret'이라고 하겠습니다.
access_token = jwt.encode({'id' : 1}, SECRET, algorithm = 'HS256') # "header값"- {'id' : 1}
print(access_token)
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MX0.-xXA0iKB4mVNvWLYFtt2xNiYkFpObF54J9lj2RwduAI'
이렇게 발급된 토큰은 어떻게 사용할 수 있을까요?
- 바로 프론트에 전달하세요 ! - 어떻게 .. ? ?/
- 로그인이 성공 시, 위 같이 발행한 토큰을 프론트에 전달합시다 !
jwt.decode(access_token, SECRET, algorithm = 'HS256')
를 통한 복호화
header = jwt.decode(access_token, SECRET, algorithm = 'HS256')
print(header)
{'id': 1} # 아까 encode한거의 헤더값인 "{'id': 1}"이다 ! !!
이제 ,인증하는 코드는 어디에 구현해야 할까요?
- 바로 엔드포인트에 데코레이터를 구현함돠 !~ !
- 데코레이터 구현은 보통 user app에 utils.py를 만들어서 작성
Author And Source
이 문제에 관하여(WIL #10 인증&인가), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@shinisgood/WIL-10저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)