【Flask】Flask实现密码存储安全性的两种方式

密码存储安全性


互联网上的大多用户都会在不同的网站使用相同的密码,如果某个网站把密码以明文方式存储在数据库里,又不幸地被攻击者获取了数据库的访问权限,那后果不堪设想(比如号称中国最大IT社区的某DN脱裤门事件,搞得我要单独记一个密码)

要想保护用户的密码,就不能明文存储密码,也不能用可从密文恢复原文的加密方式。那就要使用哈希算法的单向加密方法对密码进行加密。单向加密意味着数据被加密之后,就不可能通过密文反向计算原文。但是哈希算法只是生成数据的摘要,所以相同的数据会生成相同的密文,版本控制工具Git就是通过SHA-1对文件生成快照来进行内容变化追踪

我们可以把密码的哈希值存储起来,然后在用户登录的时候,使用相同的哈希算法对输入的密码进行计算,并比较计算出的哈希值与存储在数据库中的哈希值是否相同。这样就算攻击者获得了数据库的访问权限,他们也得不到用户的原密码,不过可能会有其他隐私的泄露问题,这个只能靠相关网站的良心了,大家注意不要把自己的隐私存储在网站上,永远记得不要相信互联网(的安全性)

哈希算法有很多种,但是大多数不安全,常用的比如MD5和SHA1。现在MD5已经不推荐使用了,随便在网上搜一下就有各种“MD5在线破解”,如果还有网站用MD5加密,那这个网站已经没人管了,死翘翘了。SHA1虽然被Google破解了,但是一般人还是别想了,所以SHA-1已经可以满足需求了

给一个2017年2月23日Google发表的一篇破解SHA-1的论文给出的数据

  • md5:只需要一个智能手机30秒就破解了
  • sha-1 shattered:110GPU 需要一年
  • sha-1 bruteforce:12000000GPU 需要一年

使用Werkzeug


Werkzeug中的security模块可以很方便的实现哈希值的计算,只需要两个函数,分别用于用户注册和用户验证阶段

  • generate_password_hash(password,method=pbkdf2:sha1,salt_length=8):这个函数将原始密码作为输入,以字符串形式输出密码的哈希值。method和salt_length的默认值能满足大多数需求

  • check_password_hash(hash,password):这个函数参数是哈希值和用户输入的密码。返回值为True表示密码正确

下面例子是SQLAlchemyUser模型

from werkzeug.security import generate_password_hash, check_password_hash

class User(db.model):
    password_hash = db.Column(db.String())

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

set_password()方法在用户注册的时候使用,会调用generate_password_hash()并将password参数传给它,将它的返回值存储在列属性password_hash

check_password()方法在用户验证的时候使用,会调用check_password_hash()并将数据库存储的哈希值和用户输入的密码传给它,并返回它的返回值,如果是True则表示密码正确

使用Flask-Bcrypt


Bcrypt被故意设计成计算起来低效而缓慢,从而使暴力破解变得更加困难,同样也有两个方法,方法名跟werkzeug.security一样

安装Flask-Bcrypt

pip install Flask-Bcrypt

首先创建Bcrypt对象,并加到app对象中

from flask_bcrypt import Bcrypt

bcrypt = Bcrypt()

def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config_name)

    bcrypt.init_app(app)

然后让User对象使用Bcrypt

from app import bcrypt

class User(db.model):
    password_hash = db.Column(db.String())

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

推荐使用Bcrypt,MD5、SHA的算法速度太快了,那为什么会因为Bcrypt慢就使用它?

因为Bcrypt采用了一系列不同的Blowfish加密算法,并引入了一个work factor,这个工作因子可以让你决定这个算法的代价有多大。所以这个算法不会因为计算机CPU处理速度变快了,而导致算法的时间会缩短了。因为你可以增加work factor来降低其性能

那么Bcrypt到底有多慢?

如果和MD5比较,Bcrypt使用值为12work factor加密“cool”。Bcrypt需要0.3秒,而MD5只需要一微秒(百万分之一秒)。也就是说,如果说MD5加密的口令的只需要40秒就可以穷举完所有的可能的,而使用Bcrypt需要12年

你可能感兴趣的:(后端)