[Django] check_password() 본문

[PL]/Python

[Django] check_password()

객과 함께. 2022. 7. 16. 20:00

아래 두 소스는  로그인한 회원이 개인 정보를 수정 하기 위해서 다시 한 번 비밀번호를 입력 하는 부분 입니다. 

True - 회원 정보를 수정 페이지 넘기고  False - 나오면 계속해서 비밀번호 페이지로 가게끔 할려고 합니다.  

 

[ 첫번째 소스 ]
def user_repw(request) :

    if request.method == "POST" :
    
        uid = request.POST.get('hidden_userid', '') 
        
        upw1 = User.objects.filter(pk=uid).values('password')  
        
        upw2 = request.POST.get('repw')
        
        if check_password(upw2, upw1) :
        
            return redirect('acc:info')
            
        else :
        
            return  render(request, 'acc/userinfo.html')
            
    return render(request, 'acc/userinfo.html')
[ 두번째 소스 ]
def user_repw(request) :

    if request.method == "POST" :
    
        uid = request.POST.get('hidden_userid', '')     
        
        upw2 = request.POST.get('repw')
        
        user1 = User.objects.get(id=uid)
        
        if check_password(upw2, user1.password) :    
        
            return redirect('acc:info')  
            
        else :
        
            return  render(request, 'acc/userinfo.html')
            
    return render(request, 'acc/userinfo.html')

위 소스에서 문제가 되는 부분은 check_password() 부분 입니다. 

첫번째 소스에서는  오류가 나거나 정상적으로 돌아간다 하더라도 BOOL값인  Only False값이 떨어집니다.원인을 찾아 볼려고 수일째 인터넷을 돌아다녀도 이거다 하는 것을 찾지 못했습니다. (블로그, stackoverflow, 등등 )

 

블로그 주소를 기억 하지 못해서 못 올립니다. 

그분이 올린 글을 보고 (두번째 소스)수정 하니 생각한 되로 값이 나오고 있었습니다. 

 

upw1 이라는 변수가 데이터베이스에 저장된 암호이고, upw2 변수는 사용자가 입력한 문자열(암호화 하기전 암호) 암호,  

uid는 로그인 사용자의 인덱스 번호입니다. 

[ result = check_password('문자열 입력한 암호', '데이터베이스 암호화가된 암호') Bool값을 반환 합니다. ]

아시는 분은 답글 부탁드립니다. 

 

 

Google에 Gemini 답변에 의한면 
두 Django 코드 스니펫은 사용자가 입력한 비밀번호와 저장된 비밀번호를 비교하여 유효성을 검사하는 목적은 동일하지만, User 객체에서 비밀번호를 가져오는 방식에서 중요한 차이를 보입니다.

두 소스 코드의 주요 차이점

가장 큰 차이점은 check_password() 함수에 전달되는 두 번째 인자, 즉 저장된 비밀번호를 가져오는 방식입니다.
  • 첫 번째 소스:
    이 코드에서는 User.objects.filter(pk=uid).values('password')를 사용하여 비밀번호를 가져옵니다.
    • filter(pk=uid)는 uid에 해당하는 사용자 객체를 쿼리셋(QuerySet) 형태로 반환합니다.
    • .values('password')는 이 쿼리셋에서 오직 'password' 필드만을 포함하는 사전(dictionary)의 쿼리셋을 반환합니다. 예를 들어, [{'password': 'hashed_password_string'}]과 같은 형태가 됩니다.
    • 문제는 check_password() 함수는 해시된 비밀번호 문자열을 직접 인자로 기대하는데, upw1은 리스트 안에 사전 형태로 비밀번호가 담겨 있다는 점입니다. 따라서 check_password(upw2, upw1)는 예상대로 작동하지 않거나 오류를 발생시킬 가능성이 매우 높습니다. check_password는 두 번째 인자로 직접적인 해시된 비밀번호 문자열을 받아야 합니다.
  • 두 번째 소스:
    이 코드에서는 User.objects.get(id=uid)를 사용하여 사용자 객체를 가져옵니다.
    • get(id=uid)는 id가 uid와 일치하는 단일 User 객체 인스턴스를 반환합니다. filter()와 달리 get()은 정확히 하나의 결과만 반환해야 하며, 여러 개이거나 없으면 오류를 발생시킵니다.
    • user1.password는 해당 User 객체의 password 속성에 직접 접근하여 해시된 비밀번호 문자열을 가져옵니다.
    • 따라서 check_password(upw2, user1.password)는 check_password 함수가 기대하는 형식에 정확히 부합하며, 올바르게 작동할 것입니다.

check_password() 부분 자세히 설명

check_password(password, encoded) 함수는 Django의 django.contrib.auth.hashers 모듈에 있는 유틸리티 함수입니다. 이 함수의 역할은 다음과 같습니다.
  • password (첫 번째 인자): 사용자가 로그인 시 입력한 평문(plain-text) 비밀번호입니다.
  • encoded (두 번째 인자): 데이터베이스에 저장된 해시된 비밀번호입니다.
check_password()는 다음 과정을 수행합니다.
  1. encoded에 사용된 **해싱 알고리즘(예: PBKDF2, bcrypt 등)**을 파악합니다. Django는 비밀번호를 저장할 때 해싱 알고리즘과 솔트(salt) 값을 함께 해시된 문자열에 포함시킵니다.
  2. 사용자가 입력한 password를 encoded에 사용된 동일한 해싱 알고리즘과 솔트 값을 사용하여 해싱합니다.
  3. 새롭게 해싱된 값과 encoded 값을 비교합니다.
  4. 두 값이 일치하면 True를 반환하여 비밀번호가 올바름을 나타내고, 일치하지 않으면 False를 반환합니다.
핵심은 check_password()가 평문 비밀번호를 입력받아 해시한 후, 저장된 해시 값과 비교한다는 점입니다. 평문 비밀번호와 해시된 비밀번호를 직접 비교하는 것이 아니라, 입력받은 평문 비밀번호를 다시 해시하여 저장된 해시 값과 비교하는 것이 보안상 올바른 방식입니다.

결론 및 권장 사항

두 번째 소스 코드가 올바른 접근 방식입니다.
  • User.objects.get(id=uid)를 사용하여 User 객체 인스턴스를 가져온 후, user1.password로 직접 해시된 비밀번호 문자열에 접근하는 것이 check_password() 함수가 의도하는 방식에 부합합니다.
  • 첫 번째 소스 코드의 values('password')는 check_password()가 기대하는 형태의 인자가 아니므로, 해당 코드는 비밀번호 검증에 실패하거나 예기치 않은 오류를 발생시킬 것입니다.
항상 User.objects.get()이나 request.user.password와 같이 해시된 비밀번호 문자열 그 자체를 check_password() 함수의 두 번째 인자로 전달해야 합니다. 라고 하네요..... 그래서 약간은 해소 했습니다. 

 

 

 

 

 

 

 

 

 

'[PL] > Python' 카테고리의 다른 글

Matplotlib 연습  (1) 2022.10.04
python 가상환경 node.js(npm) 설치  (0) 2022.10.03
ipynb -> html, ipynb -> py 변환  (0) 2022.01.26
[Python] for loop관련 예제  (0) 2022.01.25
Django-allauth 설정 및 작성  (0) 2022.01.13