유저의 아이디와 비밀번호가 맞는지 확인하는 작업을 인증이라 한다.
비밀번호와 같은 중요한 정보들은 암호화시켜 데이터베이스에 저장해야 한다.
Hash 함수를 사용하면 해쉬된 알 수 없는 문자열로 전환시켜준다. 이 때 string 타입의 비밀번호를 bytes 타입으로 encoding 하여야 한다. 데이터베이스와 서버를 관리하는 사람조차 원래의 비밀번호를 모르게 된다. 이처럼 해쉬된 비밀번호는 원래 비밀번호에 접근할 수 없고, 원래 비밀번호는 해쉬된 비밀번호에 접근할 수 있는 것을 단방향 해쉬 함수라고 한다. 하지만 Rainbow table attack과 같이 해쉬된 비밀번호들을 미리 계산한 테이블이 있어 여전히 해킹의 위험에 노출되어 있다.
해쉬된 비밀번호에 salting와 key stretching을 더해 보안을 강화시킬 수 있다.
물론 이것 역시 해킹될 위험이 여전히 있지만, 해킹되는 시간을 벌려준다.
(해쉬된 비밀번호 + salting) + key stretching 작업을 거친 해쉬함수 중 bcrypt가 가장 많이 사용된다.
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcyrpt.gensalt())
비밀번호를 bcrypt가 이해할 수 있는 bytes 타입으로 바꿔준다. (encode)
비밀번호에 salting 을 한 후 key stretching을 여러번 해준다.
이제 해쉬된 비밀번호를 데이터베이스에 저장시키면 된다.
유저가 웹사이트의 어떤 기능에 대해 권한이 있는지를 파악하는 작업을 인가라고 한다.
유저가 로그인 시 요청한 비밀번호가 데이터베이스의 해쉬된 비밀번호와 일치하는지 파악해야 한다. 요청된 비밀번호는 string 타입이기 때문에 bytes 타입으로 encoding한 상태에서 비교해야 한다.
bcrypt.checkpw(request_password.encode('utf-8'), hashed_password)
일치한다면 True
를 반환하고, 일치하지 않으면 False
를 반환한다.
유저의 인가가 유지되기 위해 토큰을 사용한다.
데이터베이스에 접근하려면 데이터베이스의 SECRET_KEY를 알아야 한다.
비밀번호가 일치하면 토큰을 생성한다.
access_token = jwt.encode({id:1}, SECRET_KEY, algorithm=HS256)
생성된 토큰은 클라이언트(프론트엔드)에게 전송한다.
로그인 후 유저가 또다른 요청을 할 때 서버는 토큰을 복호화한다.
jwt.decode(access_token, SECRET, algorithm=HS256)
{id:1}
이다. 서버는 토큰 복호화를 통해 데이터베이스에 있는 유저임을 확인할 수 있다.