5

我正在玩一个基于 python 后端的项目。我将 Django 用于“核心”内容,FastAPI 用于一些爬虫。Fernet我正在使用模块和自定义的 Django 将一些数据加密到数据库中Field

class EncryptedField(models.CharField):
    description = "Save encrypted data to DB an read as string on application level."

    def __init__(self, *args, **kwargs):
        kwargs["max_length"] = 1000
        super().__init__(*args, **kwargs)

    @cached_property
    def fernet(self) -> Fernet:
        return Fernet(key=settings.FERNET_KEY)

    def get_internal_type(self) -> str:
        return "BinaryField"

    def get_db_prep_save(
        self, value: Any, connection: BaseDatabaseWrapper
    ) -> Union[memoryview, None]:
        value = super().get_db_prep_save(value, connection)
        if value is not None:
            encrypted_value = self.fernet.encrypt(data=force_bytes(s=value))
            return connection.Database.Binary(encrypted_value)

    def from_db_value(self, value: bytes, *args) -> Union[str, None]:
        if value is not None:
            decrypted_value = self.fernet.decrypt(token=force_bytes(s=value))
            return self.to_python(value=force_str(s=decrypted_value))

一切都按预期工作,问题是当我尝试解密 FastAPI 端的值时:

def decrypt(value: bytes):
    return Fernet(FERNET_KEY).decrypt(token=value)

一些重要信息:

  • 我仔细检查settings.FERNET_KEY == FERNET_KEY,即,我在两边都使用相同的键。
  • 两个服务共享同一个数据库,并且函数在读取时接收不同的值。
    • Django -> from_db_value-> value->b"gAAAAABhSm94ADjyQES3JL-EiEX4pH2odwJnJe2qsuGk_K685vseoVNN6kuoF9CRdf2GxiIViOgiKVcZMk5olg7FrJL2cmMFvg=="
    • 快速API -> user.encrypted_field-> value-> b"pbkdf2_sha256$260000$RzIJ5Vg3Yx8JTz4y5ZHttZ$0z9CuQiPCJrBZqc/5DvxiEcbNHZpu8hAZgmibAe7nrQ="。我实际上进入了数据库并检查了这是存储在那里的值。user来自这里:
      • from sqlmodel import Session, select
        
        from .models import User
        
        
        async def get_user(db: Session, username: str) -> str:
           statement = select(User).where(User.username == username)
           return db.exec(statement).first()
        

所以我想知道在from_db_value以某种方式转换价值之前有什么东西?!

最后一种选择是解密 Django 上的值并将其直接发送到 FastAPI,但我不希望这样做。

如何解密 FastAPI 上的值?

4

2 回答 2

1

解码值就足够了:

def decrypt(value: bytes):
    return Fernet(FERNET_KEY).decrypt(token=value)

您确定要解密相同的数据吗?对我来说,这看起来像是一个加密的密码字段和其他一些字段。

mysql> select first_name, password from users_user where login='test'
+------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------+
| first_name                                                                                           | password                                                                                 |
| gAAAAABhSm94ADjyQES3JL-EiEX4pH2odwJnJe2qsuGk_K685vseoVNN6kuoF9CRdf2GxiIViOgiKVcZMk5olg7FrJL2cmMFvg== | pbkdf2_sha256$260000$RzIJ5Vg3Yx8JTz4y5ZHttZ$0z9CuQiPCJrBZqc/5DvxiEcbNHZpu8hAZgmibAe7nrQ= |
于 2021-10-01T12:25:03.847 回答
0

在 FastAPI 中,您不强制使用字节。

def decrypt(value: bytes):
    return Fernet(FERNET_KEY).decrypt(token=value)

#instead do
def decrypt(value: bytes):
    return Fernet(FERNET_KEY).decrypt(token=force_bytes(s=value))

那么 Django 和 FastAPI 上的解密函数看起来是一样的。force_bytes 可能是数据被更改的地方。

我建议您检查强制字节功能。如果可能,请向我们展示强制字节函数中的代码。

于 2021-10-01T11:59:32.190 回答