密码哈希在python中使用bcrypt
#python #安全 #password #bcrypt

嘿,有技术爱好者!

我正在通过Flatiron School训练营进行软件工程。很难相信我现在在课程中的80%,并且正在接近我的最终顶峰项目。到目前为止,我已经学习了JavaScript,React,Python和Flask,并且刚刚完成了我的第一个填充堆栈项目。我的最终项目将成为学生在数学课上使用的工具,以使图形作业更容易在计算机上进行。我知道我想允许用户拥有一个帐户来保存他们的工作,因此我将使用BCRypt实施密码。这将为用户增加一定级别的安全性,因为他们的密码将在将其保存到我的用户表之前进行编码。由于许多人对不同帐户的密码重复使用密码,因此我必须尽我所能确保他们的密码不会被其用于不道德目的的人发现。

无论您是编程的新手还是经验丰富的开发人员,了解如何在Python中实施BCrypt可能是在工具箱中拥有的宝贵技能。因此,让我们开始使用Python中的bcrypt探索密码的来源和输出!

一旦您对使用bcrypt有很好的了解,我强烈鼓励您在哈希岛上加盐。稍稍回来,我将添加一篇有关用盐提高密码存储安全性的其他博客文章!


*目标:
*
- 将密码添加到sqlalchemy桌子中,以烧瓶(Python)运行

*以前的知识:
*
- 在sqlalchemy中创建表(提供提醒)

  • 使用Postman
  • 导入库
  • 设置应用程序的服务器端

*第1部分)安装:
*

BCRypt是一个安装程序包,您可以通过命令行安装。如果您使用的是Python,请使用以下命令行:
$ pipenv install bcrypt

我正在使用烧瓶框架,因此我将安装Bcryt的烧瓶版本:

$ pipenv install flask-bcrypt

现在,您的pipfile中已经有bcrypt,通过在命令行中传递以下内容来生成秘密密钥:

$ python -c 'import os; print(os.urandom(16))

这将是您程序用来编码密码时使用的关键。同样,秘密键将在下一次尝试登录时解码密码。您将需要尽快访问此随机字符字符串!

*第2部分)配置文件
*

我个人喜欢拥有一个config.py文件,以便在我的型号中降低混乱。这是处理所有导入和元数据样板文本的空间。这是我在config.py中拥有的:

from flask import Flask
from flask_bcrypt import Bcrypt
from flask_migrate import Migrate
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
from flask_cors import CORS


app = Flask(__name__)
app.secret_key = b'<<This is where your secret key string goes>>'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.json.compact = False

metadata = MetaData(naming_convention={
    "ix": "ix_%(column_0_label)s",
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_`%(constraint_name)s`",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
    })
db = SQLAlchemy(metadata=metadata)

migrate = Migrate(app, db)
db.init_app(app)

bcrypt = Bcrypt(app)

api = Api(app)
CORS(app)

您将将秘密键插入指示的空间。

请注意,其中一些进口是为了创建我的SQLalchemy表。对您的项目进行所需的调整。

*第3部分)模型
*

我一直喜欢将模型视为我正在建模数据的内容。这是我们要构成表的结构的地方。为了进行此步行,我只会显示一个非常基本的用户表,只有一个用户名和密码。

在文件的顶部,处理您的导入。

from sqlalchemy.ext.hybrid import hybrid_property

from config import db, bcrypt

创建您的用户表。您不会在用户输入该密码时存储密码。相反,您正在存储其密码的编码版本。要在表中确认这一点,请使用列名“ _password_hash”。

class User(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String, unique = True, nullable = False)
    _password_hash = db.Column(db.String)

现在是时候开始使用密码了。以下样板文本正在编码用户的密码,因此您的表将存储一些与用户注册网站时键入内容的内容。当用户试图重新登录时,秘密键用于检查密码输入是否与表中存储的groarbildy goop相同的字符串。

class User(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String, unique = True, nullable = False)
    _password_hash = db.Column(db.String)

    @hybrid_property
    def password_hash(self):
        raise AttributeError('Password hashes may not be viewed.')

    @password_hash.setter
    def password_hash(self, password):
        password_hash = bcrypt.generate_password_hash(
            password.encode('utf-8')
        )
        self._password_hash = password_hash.decode('utf-8')

    def authenticate(self, password):
        return bcrypt.check_password_hash(
            self._password_hash, password.encode('utf-8')

*第4部分)应用
*

app.py文件是我们在路由中添加功能的地方。让我们专注于为注册类创建“帖子”,并为登录类创建“帖子”。我们将使用Postman检查工作的功能。

开始(与往常一样!)进行所需的导入:

#!/usr/bin/env python3

from flask import request, session, make_response
from flask_restful import Resource
from sqlalchemy.exc import IntegrityError


from config import app, db, api
from models import User

在您走得太远之前,请跳回型号。提醒您,如果您在烧瓶中,则是命令行。

# export FLASK_APP=app.py
# export FLASK_RUN_PORT=5555
# flask db init
# flask db revision --autogenerate -m 'Create tables' 
# flask db upgrade 

在转到下一步之前,请确保您的用户表显示在数据库中。

让我们创建一个可以将新用户发布到我们数据库的注册类。


class Signup(Resource):
    def post(self):

        request_json = request.get_json()

        username = request_json.get('username')
        password = request_json.get('password')

        user = User(
            username = username
        )

        user.password_hash = password

        try:
            db.session.add(user)
            db.session.commit()

            session ['user_id']=user.id

            print (user.to_dict(), 201)

        except IntegrityError:
            print ('nope')

            return {'error': '422 Unprocessable Entity'}, 422

api.add_resource(Signup, '/signup', endpoint='signup')

if __name__ == '__main__':
    app.run(port=5555, debug=True)

*第5部分)使魔术实现!
*

您现在应该可以去邮递员并运行http://127.0.0.1:5555/signup帖子。输入用户名和密码进行测试。如果您在运行帖子后收到“零”消息,请恭喜!你做到了!!如果不是,请仔细检查您的表设置。一个小的错别字可能会阻碍你的背。

Image description

要检查您是否成功,请转到数据库中的表格。您应该看到带有用户名的新行,作为您输入的任何内容和一个胡说八道。这是哈希密码。

要检查使用Hashed密码登录的功能,请在app.py中添加新的登录类:

class Login(Resource):

    def post(self):

        request_json = request.get_json()

        username = request_json.get('username')
        password = request_json.get('password')

        user = User.query.filter(User.username == username).first()

        if user:
            if user.authenticate(password):
                print("authenticate")
                session['user_id'] = user.id
                return user.to_dict(), 200

        return make_response({'error': '401 Unauthorized'},401) 

api.add_resource(Login, '/login', endpoint='login')

回到邮递员。更改通往http://127.0.0.1:5555/login的路径,然后输入您在注册中使用的相同用户名和密码信息。您应该用用户名和哈希密码恢复对象。


路要走!您只是通过使数据库中的密码更加安全来帮助您的用户。如果您能够做到这一点,我建议您考虑将盐添加到密码哈希方法中,以提供额外的安全性。我会很快就会在盐上进行博客文章!