장고에서 유저의 비밀번호를 어떻게 설정해야 할까요? 비밀번호는 평문으로 저장되면 안 됩니다. 그렇기 때문에, set_password 라는 별도의 함수를 제공합니다. 이 글에서는 암호화 방식에 대한 상세한 설명을 다루지 않습니다.

 


 먼저 사용법부터 봅시다.

 

 auth.models에 붙어 있는 User를 쓰는 경우, 비밀번호를 셋팅할 User 계정을 불러옵니다. 저는 "admin"이라는 유저 이름을 가진 유저를 filter와 get을 이용해서 불러왔습니다. 다음에 set_password 함수로 새롭게 설정할 raw_password를 넣습니다. 다음에, 반영하기 위해,  user.save()를 해서 실제 데이터 베이스에 넣습니다. 사용법은 어렵지 않습니다.

 

 이제, 어떤 식으로 동작하는지 간단하게만 보겠습니다. 

 


 메타 정보는 대략적으로 이러합니다. salt 값이랑 iterations, algorithm 등이 눈에 보이네요.

 

 이 salt 값이랑 password, 그리고 기타 메타 정보들을 취합해서 encode를 하는데요. encode를 한 결과는 아래와 같습니다.

 

 앞에 algorithm 정보, 그 다음에 몇 번 iteration을 돌렸는지가 나옵니다. 그 다음에 salt값이 붙는것을 볼 수 있는데요. 이 메타 정보를 가지고 비밀번호가 맞는지 틀린지 match 시켜버릴 수 있습니다.

 

 

  제 계정의 비밀번호가 "ab"로 시작한다는 사실을 알 수 없습니다.

 

 


 반대로 제 어드민 계정을 요래 셋팅하면 어떨까요?

 

 

 그냥 password를 요래 설정해 버렸습니다.

 

 그러면 db의 계정 정보에 password가 "ab"로 시작한다는 정보가 그대로 노출이 되어 버립니다. 그러면 로그인은 잘 될까요?

 

 

 check_password 함수에 break point를 걸어서 확인해 보면 그렇지 않을 것이라고 추론할 수 있습니다. 왜냐면 저는 raw 하게 저장했는데, 실제로 검증하는 단에서는 pdkdf2_sha256으로 decode를 하려고 하기 때문입니다. 이 이상한 상황을 그려보면 아래와 같습니다.

 

 raw password로 "ab"로 시작하는 무언가가 들어갔습니다. 패스워드 hasher 관련 설정을 settings.py에서 아무것도 하지 않았으니, default 로직을 타긴 할 텐데요.

 

 

 hashers.py의 이 부분에서 exception이 걸려버립니다.

 

 

 아무리 눈을 씻고 찾아봐도 "ab"로 시작하는 무언가가 없기 때문입니다.

 

 


 그러면, 보안상 raw한 password가 그대로 노출되는 것 보다는 암호화된 pw가 저장되는 게 보안상으로 안전하니, set_password를 쓰는 게 맞기는 할 겁니다. 추가 질문. 비밀번호가 맞는지는 어떻게 검증할까요? 비밀번호를 decode 해서 검증할까요? 상식적으로 그 편 보다는, 이미 있는 메타 데이터들을 가지고 암호화 해서 비교하는 편이 쉬운 솔루션일 겁니다.

 

 

 검증하는 루틴을 따라가 보면 verify 함수를 호출하는 것을 볼 수 있는데요. 해당 부분을 간략하게 봅시다. encoded_2는 입력한 비밀번호를 encode한 결과입니다. 이 결과와, 실제 저장되어 있던 encoded된 것을 compare함을 알 수 있어요. 그러니까, 기존에 있던 비밀번호를 decode 하지 않고, 대신에 메타 데이터들을 이용해서 입력한 비밀번호를 encode 한 다음에 encode 된 값들끼리 비교하는 셈입니다.