- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个用户表,它有一个支付密码。我决定加密所有这些信息。每个 API 检索或插入新数据,它总是调用一个函数来加密密码,就像这样。
from cryption import encrypt, decrypt
enc_password = encrypt(password)
data = User(id=id, password=enc_password)
db.add(data)
db.commit()
由于我在 API 中对其进行了加密,因此它看起来是多余的。另外,有时我忘记添加加密代码,这会导致严重错误。所以,我想知道我是否可以在模型上做这个而不是这样做。如果我能在插入数据之前加密并在查询级别返回数据时解密,那就太好了。
最佳答案
首先,一个重要的警告:
警告:切勿存储用户密码。 从不。一旦您的服务器受到威胁,黑客不仅会得到您的服务器,还会得到加密 key 和所有密码。
相反,存储密码散列。参见 Why is password hashing considered so important?和 Difference between Hashing a Password and Encrypting it .
在 Python 中,使用 passlib为您处理密码散列。
除此之外,您可以自动将密码哈希值存储在数据库中,或者通过使用属性进行转换来进行任何其他数据转换。我在我的用户模型中使用它。
在下面的示例模型中,password
属性实际上将 password_hash
列设置为散列值:
from passlib.context import CryptContext
PASSLIB_CONTEXT = CryptContext(
# in a new application with no previous schemes, start with pbkdf2 SHA512
schemes=["pbkdf2_sha512"],
deprecated="auto",
)
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
# site-specific fields, like name, email, etc.
# password hash handling
# pbkdf2-sha512 is 130 characters short, but it never hurts to
# leave space for future growth of hash lengths.
password_hash = db.Column(db.String(256), nullable=False)
def __init__(self, password=None, password_hash=None, **kwargs):
if password_hash is None and password is not None:
password_hash = self.generate_hash(password)
super().__init__(password_hash=password_hash, **kwargs)
@property
def password(self):
raise AttributeError("User.password is write-only")
@password.setter
def password(self, password):
self.password_hash = self.generate_hash(password)
def verify_password(self, password):
return PASSLIB_CONTEXT.verify(password, self.password_hash)
@staticmethod
def generate_hash(password):
"""Generate a secure password hash from a new password"""
return PASSLIB_CONTEXT.hash(password.encode("utf8"))
这让我可以使用 User(..., password=password)
,它会自动为我散列密码。或者使用 if new_password == new_password_again and some_user.verify_password(old_password): some_user.password = new_password
更新密码,而无需记住如何再次散列密码。
您还可以使用“隐藏”列来存储您需要在存储时加密、在检索时解密的任何其他数据。使用前导 _
下划线命名您的模型属性以将它们标记为 API 私有(private),然后将实际列名作为第一个参数传递给 Column()
对象。然后使用一个属性对象来处理加密和解密:
class Foo(db.Model):
__tablename__ = "foo"
id = db.Column(db.Integer, primary_key=True)
# encrypted column, named "bar" in the "foo" table
_bar = db.Column("bar", db.String(256), nullable=False)
@property
def bar(self):
"""The bar value, decrypted automatically"""
return decrypt(self._bar)
@bar.setter
def bar(self, value):
"""Set the bar value, encrypting it before storing"""
self._bar = encrypt(bar)
这在 Using Descriptors and Hybrids 下的 SQLAlchemy 手册中有所介绍.请注意,在这种情况下使用 hybrid_property
没有意义,因为您的数据库无法在服务器端加密和解密。
如果您进行加密,将您的 key 与您的源代码分开,并确保轮换您的 key (保留旧 key 以解密尚未重新加密的旧数据),以便如果 key 遭到泄露,您至少可以更换它。
选择一个好的、值得信赖的加密方法。 cryptography
包包括 Fernet 配方,参见 another answer of mine有关如何使用它的建议,然后升级到 MultiFernet()
class管理 key 轮换。
此外,请继续阅读 key management best practices .密码学很容易出错。
关于python-3.x - SQLAlchemy:调用函数并始终将返回值保存在表中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56738384/
我正在尝试创建一个使用 UUID 作为主键的用户模型: from src.db import db # SQLAlchemy instance import sqlalchemy_utils impo
在 sqlalchemy 中,我试图合并表,然后使用 WHERE 和 ORDER_BY 创建别名 有点像 SELECT * FROM ( SELECT [TABLE_ONE].[SOME_ID]
我正在使用 SQL Alchemy(通过 Flask_sqlalchemy)将 Python 字典列表插入到 Postgres 数据库中。 其中一个表是所有唯一项目的列表(表 1),而第二个是与某个项
This source详细说明如何使用关联代理创建具有 ORM 对象值的 View 和对象。 但是,当我附加一个与数据库中现有对象匹配的值(并且所述值是唯一的或主键)时,它会创建一个冲突的对象,因此我
SQLAlchemy Core和SQLAlchemy ORM的目的有什么区别? 最佳答案 顾名思义,ORM是一个对象关系映射器:其目的是将数据库关系表示为Python对象。 核心是查询构建器。其目的是
带有ForeignKey的Column是否自动创建索引? 还是我需要手动添加index=True? some_field = Column(Integer, ForeignKey(SomeModel.
我有一个主数据库,每个客户自己的数据库连接存储在其中。 因此,每个客户端都使用2个db:main和它自己的db,必须确定其连接 对于每个http调用。我如何使用flask-sqlalchemy扩展名执
当我仅对类进行继承时,它才起作用 class User(Base): __tablename__ = ’users’ id = Column(Integer, primary_key=
从用户的角度来看,SQLAlchemy 的查询日志似乎有点过于冗长,有时甚至有点神秘: 2015-10-02 13:51:39,500 INFO sqlalchemy.engine.base.Engi
我正在尝试使用 wtforms.ext.sqlalchemy QuerySelectMultipleField 显示复选框列表,但我无法在 GET 的表单上显示模型数据。 这是我的models.py
我想为查询返回一个中继连接。使用标准的 graphene-sqlalchemy 你可以这样做: class Query(graphene.ObjectType): node = relay.N
我在 centos 7.5 虚拟机上部署了最新的 Airflow ,并将 sql_alchemy_conn 和 result_backend 更新到 postgresql 实例上的 postgres
我想将多个项目插入到一个表中,并在发生冲突时更新该表。这是我想出的以下内容 from sqlalchemy.dialects.postgresql import insert meta = MetaD
我有以下模型: class Item(Base): a = relationship() b = relationship() c = relationship() d
我有 presto 和 superset 设置。 presto 运行良好,可以通过命令访问: ./app/hadoop/setjdk8.sh;bin/presto-cli --server http:
我一直在寻找一种在 sqlalchemy 中使用 tsvector 的方法(就像 INTEGER 等其他方法一样),但到目前为止我还不清楚如何做到这一点。我读过可以使用 UserDefinedType
我正在使用 sqlalchemy(现在使用 sqlite,但稍后可能会改变)来构建一个数据库,其中插入的顺序和 rowids 很重要。我基本上有以下几点: class Message(Base):
给定一个对象,我想知道如何知道它是否是 sqlalchemy 映射模型的实例。 通常,我会使用 isinstance(obj, DeclarativeBase)。但是,在这种情况下,我没有可用的 De
我已经通读了查询文档,如果有办法从查询中获取表名,就看不到任何地方 - 例如如果我有 q = query(Users) ,我可以得到Users从 q 退出? 最佳答案 请注意,像您这样的事件简单查询可
我不确定如何定义create schema foo迁移?我的模型如下所示(我正在使用Flask-Migrate): class MyTable(db.Model): __tablename__
我是一名优秀的程序员,十分优秀!