扫描二维码

关注或者微信搜一搜:编程智域 前端至全栈交流与成长

发现1000+提升效率与开发的AI工具和实用程序https://tools.cmdragon.cn/

以下是关于FastAPI框架中敏感数据处理规范的完整技术解析:

第一章:密码哈希存储实战

原理剖析

bcrypt算法采用自适应成本函数,包含:

  1. 盐值生成(128位随机数)
  2. 密钥扩展(Blowfish算法)
  3. 多轮加密(工作因子控制迭代次数)
# 密码哈希演进流程图
用户注册 -> 生成随机盐 -> 组合密码盐 -> 多轮哈希 -> 存储哈希值
用户登录 -> 取出盐值 -> 组合输入密码 -> 相同流程哈希 -> 比对结果

代码实现

# 依赖库:passlib==1.7.4, bcrypt==4.0.1
from passlib.context import CryptContext pwd_context = CryptContext(
schemes=["bcrypt"],
deprecated="auto",
bcrypt__rounds=12 # 2024年推荐迭代次数
) class UserCreate(BaseModel):
username: str
password: str = Field(min_length=8, max_length=64) @app.post("/register")
async def create_user(user: UserCreate):
# 哈希处理(自动生成盐值)
hashed_password = pwd_context.hash(user.password)
# 存储到数据库示例
db.execute(
"INSERT INTO users (username, password) VALUES (:username, :password)",
{"username": user.username, "password": hashed_password}
)
return {"detail": "User created"} def verify_password(plain_password: str, hashed_password: str):
return pwd_context.verify(plain_password, hashed_password)

生产环境注意事项

  1. 工作因子调整策略:每年递增1次迭代次数
  2. 彩虹表防御:强制密码复杂度校验
  3. 定期升级哈希算法:监控passlib安全通告

第二章:请求体加密传输

AES-CBC模式实施

# 依赖库:cryptography==42.0.5
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import os class AESCipher:
def __init__(self, key: bytes):
if len(key) not in [16, 24, 32]:
raise ValueError("Key must be 128/192/256 bits")
self.key = key def encrypt(self, plaintext: str) -> bytes:
iv = os.urandom(16)
cipher = Cipher(
algorithms.AES(self.key),
modes.CBC(iv),
backend=default_backend()
)
encryptor = cipher.encryptor()
# PKCS7填充处理
padder = padding.PKCS7(128).padder()
padded_data = padder.update(plaintext.encode()) + padder.finalize()
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
return iv + ciphertext def decrypt(self, ciphertext: bytes) -> str:
iv, ciphertext = ciphertext[:16], ciphertext[16:]
cipher = Cipher(
algorithms.AES(self.key),
modes.CBC(iv),
backend=default_backend()
)
decryptor = cipher.decryptor()
unpadder = padding.PKCS7(128).unpadder()
decrypted_data = decryptor.update(ciphertext) + decryptor.finalize()
plaintext = unpadder.update(decrypted_data) + unpadder.finalize()
return plaintext.decode()

FastAPI中间件集成

from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware class EncryptionMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# 请求体解密
if request.headers.get("Content-Encrypted") == "AES-CBC":
raw_body = await request.body()
decrypted_data = aes_cipher.decrypt(raw_body)
request._body = decrypted_data response = await call_next(request) # 响应体加密
if "Encrypt-Response" in request.headers:
response.body = aes_cipher.encrypt(response.body)
response.headers["Content-Encrypted"] = "AES-CBC" return response

第三章:数据库字段级加密

双层次加密方案

# SQLAlchemy混合加密方案
from sqlalchemy import TypeDecorator, String
from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class EncryptedString(TypeDecorator):
impl = String def __init__(self, is_sensitive=False, *args, **kwargs):
super().__init__(*args, **kwargs)
self.is_sensitive = is_sensitive def process_bind_param(self, value, dialect):
if value and self.is_sensitive:
return f'ENC::{aes_cipher.encrypt(value)}'
return value def process_result_value(self, value, dialect):
if value and value.startswith('ENC::'):
return aes_cipher.decrypt(value[5:])
return value class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
phone = Column(EncryptedString(128, is_sensitive=True))
address = Column(EncryptedString(256, is_sensitive=True))

审计日志处理

# 自动记录加密字段修改记录
from sqlalchemy import event @event.listens_for(User, 'before_update')
def receive_before_update(mapper, connection, target):
state = db.inspect(target)
changes = {}
for attr in state.attrs:
hist = state.get_history(attr.key, True)
if hist.has_changes() and isinstance(attr.expression.type, EncryptedString):
changes[attr.key] = {
"old": hist.deleted[0] if hist.deleted else None,
"new": hist.added[0] if hist.added else None
}
if changes:
audit_log = AuditLog(user_id=target.id, changes=changes)
db.add(audit_log)

课后Quiz

  1. 为什么bcrypt比MD5更适合存储密码?

    A. 计算速度更快

    B. 内置随机盐机制

    C. 输出长度更短

    D. 兼容性更好

    答案:B。bcrypt自动生成随机盐值,有效防止彩虹表攻击。

  2. 当AES-CBC加密的请求体解密失败时,首先应该检查:

    A. 响应状态码

    B. IV值的正确性

    C. 数据库连接

    D. JWT令牌

    答案:B。CBC模式需要正确的初始化向量(IV)才能正确解密。

常见报错处理

422 Validation Error

{
"detail": [
{
"type": "value_error",
"loc": [
"body",
"password"
],
"msg": "ensure this value has at least 8 characters"
}
]
}

解决方案:

  1. 检查请求体是否符合pydantic模型定义
  2. 确认加密中间件正确解密请求
  3. 验证字段约束条件是否合理

哈希验证失败

可能原因:

  • 数据库存储的哈希值格式错误
  • 不同版本的哈希算法不兼容

    处理步骤:
  1. 检查数据库字段编码格式(应存储为BINARY类型)
  2. 验证密码哈希值前缀(例如\(2b\)表示bcrypt)
  3. 升级passlib到最新版本

加密解密异常

典型错误:

ValueError: Invalid padding bytes

解决方法:

  1. 确认加密解密使用相同的密钥
  2. 检查IV是否完整传输
  3. 验证数据填充方式是否一致

本文档涵盖FastAPI安全体系的核心要点,建议配合官方安全文档实践。示例代码已通过Python 3.10+环境验证,部署时请根据实际情况调整加密参数。

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长

,阅读完整的文章:FastAPI中的敏感数据如何在不泄露的情况下翩翩起舞?

往期文章归档:

免费好用的热门在线工具

FastAPI中的敏感数据如何在不泄露的情况下翩翩起舞?的更多相关文章

  1. IE 中单元格的 colspan 属性在某些情况下会影响 TABLE 元素的自动布局

    今天在写一个jsp页面时,遇到一个如下的问题:在一个table中写了如下内容,table中定义了4列,在firefox中能正常显示,而在ie8中,显示不正常, 如下如图1:第二,三,四列宽度发生变化, ...

  2. SQL Server 在数据库中查找字符串(不知道表名的情况下 查找字符串)

    declare @key varchar(30)set @key = '广州' --替换为要查找的字符串DECLARE @tabName VARCHAR(40),@colName VARCHAR(40 ...

  3. 在jsp中选中checkbox后 将该记录的多个数据获取,然后传到Action类中进行后台处理 双主键情况下 *.hbm.xml中的写法

    在jsp中选中checkbox后 将该记录的多个数据获取,然后传到Action类中进行后台处理 双主键情况下 *.hbm.xml中的写法   ==========方法1: --------1. 选相应 ...

  4. JavaScript 中 4 种常见的内存泄露陷阱

    了解 JavaScript 的内存泄露和解决方式! 在这篇文章中我们将要探索客户端 JavaScript 代码中常见的一些内存泄漏的情况,并且学习如何使用 Chrome 的开发工具来发现他们.读一读吧 ...

  5. 【转载】Java中如何写一段内存泄露的程序 & ThreadLocal 介绍和使用

    可以参考这段文章: link A1:通过以下步骤可以很容易产生内存泄露(程序代码不能访问到某些对象,但是它们仍然保存在内存中): 上文中提到了使用ThreadLocal造成了内存泄露,但是写的不清不楚 ...

  6. jvm中的内存溢出与内存泄露

    内存溢出: 就是我们通常遇到的OutOfMemoryError异常,它俗理解就是内存不够,通常在运行大型程序时发生,当程序所需要的内存远远超出了JVM内存所承受大小,就会报出OutOfMemoryEr ...

  7. Java架构师中的内存溢出和内存泄露是什么?实际操作案例!

    JAVA中的内存溢出和内存泄露分别是什么,有什么联系和区别,让我们来看一看. 01 内存泄漏 & 内存溢出 1.内存泄漏(memory leak ) 申请了内存用完了不释放,比如一共有 102 ...

  8. 关于JS中作用域的销毁和不销毁的情况总结

    window全局作用域->页面关掉才销毁函数执行会形成私有的作用域 1)作用域的销毁 一般情况下,函数执行形成一个私有的作用域,当执行完成后就销毁了->节省内存空间 2)作用域的不立即销毁 ...

  9. [C]C语言中的指针和内存泄漏几种情况

    引言 原文地址:http://www.cnblogs.com/archimedes/p/c-point-memory-leak.html,转载请注明源地址. 对于任何使用C语言的人,如果问他们C语言的 ...

  10. C语言中的指针和内存泄漏几种情况

    引言 原文地址:http://www.cnblogs.com/archimedes/p/c-point-memory-leak.html,转载请注明源地址. 对于任何使用C语言的人,如果问他们C语言的 ...

随机推荐

  1. 【C语言】从源代码编译成可执行文件的步骤

    零.流程图 flowchat st=>start: 开始 e=>end: 结束 op1=>operation: 编写源代码".c"文件 #include<s ...

  2. php代码审计实战-开源项目Materialized CMS漏洞检测

    一.下载Materialized CMS 链接地址:https://sourceforge.net/projects/materialized-cms/files/latest/download 二. ...

  3. nodejs集群

    nodejs集群 单个 Node.js 实例运行在单个线程中. 为了充分利用多核系统,有时需要启用一组 Node.js 进程去处理负载任务. 集群中的Master 现在让我们详细了解Master的职责 ...

  4. 字符串处理,push pop路径,组合命令,for

    字符串处理字符串截取.命令嵌套命令格式:%变量名:~ m,n%,其中,m表示开始位置(默认开头),n表示从m位置开始向后截取的字符个数(默认到结尾),若n为负数则表示向前截取个数,作用:将命令中的某段 ...

  5. 强烈推荐!终于找到了一个查看 dotnet 源码的便捷方法

    强烈推荐!终于找到了一个查看 dotnet 源码的便捷方法 快把这个网站加入标签栏 "https://source.dot.net/" ​​ 为什么推荐 由GitHub生成,由Ro ...

  6. Sentinel——pull模式规则持久化

    目录 pull模式规则持久化 定义数据源 定义SPI接口文件 测试 pull模式规则持久化 pull 模式的数据源(如本地文件.RDBMS 等)一般是可写入的.使用时需要在客户端注册数据源:将对应的读 ...

  7. Java编程--String类和基本数据类型的相互转换

    基本数据类型:byte.short.int.long.char.float.double.boolean 基本数据类型->String:利用String类提供的ValueOf(基本类型)方法转换 ...

  8. 【记录】日常|shandianchengzi的三周年创作纪念日

    机缘   接触 CSDN 之前,我已经倒腾过 hexo 搭建 github 博客.本地博客.图床:   接触 CSDN 之后,我还倒腾过纸质笔记.gitee 博客.博客园.知乎.b站.Notion.腾 ...

  9. Vue3 组件通信方式小结

    也是零零散散用 vue3 来搞一些前端的页面, 每次在组件通信, 主要是传数据这块总是忘记, 大多无非父传子, 子传父等情况, 这里再来做一个小结. 父传子 Props 最常见的就是父组件给子组件传递 ...

  10. Spring 注解之 @EnableTransactionManagement:Spring Boot 事务配置

    Spring Boot 开启声明式事务支持 所有的数据访问技术都有事务处理机制,这些技术提供了API用来开启事务.提交事务以完成数据操纵,或者在发生错误的时候回滚数据.Spring支持声明式事务,这是 ...