데이터베이스(db)

파이썬에서 DB에 비밀번호 암호화(hash)해서 저장하기(flask,mongodb)

끄적끄적아무거나 2021. 6. 19. 13:33
반응형

hash 암호화 해서 DB에 저장하는 법

 

파이썬에서 웹페이지를 만들때 사용자의 암호를 평문으로 데이터베이스에 저장하면 안된다. 암호화 방법 중에 가장 많이 사용하는 방법으로 hash를 사용하는 방법이 있다. 나는 hash를 사용해서 암호화를 사용하는방법에 대해서 예제를 통해 구현하려고 하기 때문에 hash에 대한 자세한 설명은 생략하고 자 한다. 


hash 란 간단한 의미?

 

hash에는 SHA-1, SHA-256, SHA-512 등 다양한 기법이 있는데 간단하게 말하면 입력으로 일정한 값이 있으면 출력은 입력의 사이즈에 상관없이 일정한 크기로 나온다. 그리고 입력에 1비트만 바뀌어도 출력은 완전 다른 값이 나온다. 물론 길이는 동일하다. 앞서 말한 hash 기법에 따라 출력 길이나 출력이 나오는 값이 달라진다. hash를 사용하면 출력으로 다시 입력값을 되돌릴수는 없지만 해당 입력 값이 동일한지 검증이 가능하다. 

 


로그인페이지에서 검증하기 (파이썬 flask 예제)

 

이번 예제는 앞서 회원 가입으로 mongodb에 email정보와 password 정보를 넣는 예제에서 hash만 추가 할 것이다. hash 기능 자체는 mysql과 mongodb 등 모든 데이터베이스에서 사용할 수 있으니 염두하길 바란다. 

 

앞서 말한 예제는 괄호안에 있으니 참조하길 바란다. 예제 실행은 간단한 예제를 사용했다. (https://scribblinganything.tistory.com/196)

 

이번 예제는 werkzeug 라이브러리를 import 해서 사용할 것이다. 회원 가입에서 이메일과 비밀번호를 db에 저장하고 바로 다시 db에서 읽어서 비밀번호가 일치하는지 확인할 것이다. 그리고 hash 값도 출력할 것이다.

 

코드 flask.py>> 

from flask import *
from flask_pymongo import PyMongo
from werkzeug.security import generate_password_hash, check_password_hash

#########################################################
# Flask 선언, mongodb와 연결
web_bulletin = Flask(__name__, template_folder="templates")
web_bulletin.config["MONGO_URI"] = "mongodb://localhost:27017/bulletin" 
web_bulletin.config['SECRET_KEY'] = 'psswrd'

mongo = PyMongo(web_bulletin)
#########################################################

web_bulletin.secret_key = '사용자지정비밀번호'

@web_bulletin.route("/login", methods=["GET", "POST"])
def bulletin_write():
    if request.method == "POST":
        email = request.form.get("email", type=str)
        pw = request.form.get("pw", type=str)

        if email == "":
            flash("Please Input EMAIL")
            return render_template("login.html")
        elif pw == "":
            flash("Please Input PW")
            return render_template("login.html") 

        signup = mongo.db.signup
        check_cnt = signup.find({"email": email}).count()
        if check_cnt > 0:
            flash("It is a registered email")
            return render_template("login.html") 

        to_db = {
            "email": email,
            "pw": generate_password_hash(pw),
        }
        to_db_signup = signup.insert_one(to_db)
        last_signup = signup.find_one({"email":email})  
        if check_password_hash(last_signup.get("pw"),"1234") :
            print("password is correct")
        else:
            print("password is not correct")
        for _ in last_signup:
            print(_)

        print("hash : "+ generate_password_hash(pw))
        flash("Thanks for your signup")
        return render_template("login.html")
    else:
        return render_template("login.html")

if __name__ == "__main__":
    web_bulletin.run(host='0.0.0.0', debug=True, port=9999)

 

코드-login.html>>

{% with messages = get_flashed_messages() %}
    {% if messages %}
        <script>
            alert("{{messages[-1]}}")
        </script>
    {% endif %}
{% endwith %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document1</title>
</head>
<body>
    <form action="/login" method="post"> 
        <p>EMAIL : <input type="text" name="email" /></p> 
        <p>PW : <input type="password" name="pw" /></p> 
        <p><input type="submit" value="submit" /></p> 
    </form>  
</body>
</html>

 

결과>>

password is correct
_id
email
pw
hash : pbkdf2:sha256:150000$PKh148SC$072fa8b5369b98239a9847bda41c2ed1710050cfb2f2fdb992c8d5b45009398a

 

 

주석>>

비밀번호는 1234 로 입력하였다. 하지만 결과에서 볼수 있듯이 hash 값이 길게 들어갔다. 방법은 sha256을 사용한 hash 값이다. 그리고 결과를 비교했고 password is correct를 얻을 수 있다.

 

이전 예제 코드에서 추가 된 부분은 이렇다.

 

from werkzeug.security import generate_password_hashcheck_password_hash

 

위처럼 hash 발생을 위한 모듈과 hash값과 입력값 비교를 위한 모듈을 import 하였다. 

 

        to_db = {

            "email"email,

            "pw"generate_password_hash(pw),

        }

 

db에 넣을 비밀번호를 위처럼 hash 값으로 넣었다.

 

        if check_password_hash(last_signup.get("pw"),"1234") :

            print("password is correct")

        else:

            print("password is not correct")

 

db에서 값을 다시 읽어서 1234 가 맞는지 확인하였다.

 

 

반응형