gpt4 book ai didi

python-3.x - SQLAlchemy:调用函数并始终将返回值保存在表中

转载 作者:行者123 更新时间:2023-12-01 21:56:29 25 4
gpt4 key购买 nike

我有一个用户表,它有一个支付密码。我决定加密所有这些信息。每个 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com