如何在Flask+SQLAlchemy中安全连接PostgreSQL,避免敏感信息泄露
安全配置SQLAlchemy数据库连接的方案
针对自行托管服务器的场景,以下几种方式既能保证敏感信息不泄露,又能流畅适配Windows开发和Linux部署:
1. 利用操作系统级安全存储读取凭据
直接将数据库敏感信息存储在操作系统的安全凭据管理器中,而非明文环境变量或配置文件,应用启动时通过专门的库读取。
适配方式:
- Windows:使用Windows Credential Manager存储凭据,用
keyring库读取 - Linux:使用GNOME Keyring或KDE Wallet(系统默认的秘密服务),同样用
keyring库读取
代码实现:
首先安装依赖:
pip install keyring
修改config.py,不再直接读环境变量,而是从系统凭据存储读取:
import keyring from sqlalchemy.engine.url import URL class ProductionConfig: # 从系统凭据存储获取数据库信息 DB_USER = keyring.get_password("flask_app_db", "db_user") DB_PASS = keyring.get_password("flask_app_db", "db_pass") DB_HOST = keyring.get_password("flask_app_db", "db_host") DB_PORT = keyring.get_password("flask_app_db", "db_port") DB_NAME = keyring.get_password("flask_app_db", "db_name") # 构建SQLAlchemy连接字符串 SQLALCHEMY_DATABASE_URI = URL.create( "postgresql+psycopg2", username=DB_USER, password=DB_PASS, host=DB_HOST, port=DB_PORT, database=DB_NAME ) SQLALCHEMY_TRACK_MODIFICATIONS = False
凭据存储操作:
- Windows(PowerShell):
# 添加凭据到Windows Credential Manager cmdkey /generic:flask_app_db/db_user /user:your_db_username /pass:your_db_password cmdkey /generic:flask_app_db/db_pass /user:your_db_username /pass:your_db_password # 同理添加db_host、db_port、db_name
- Linux(终端):
# 使用keyring命令行工具添加(先安装python-keyring-cli) pip install keyring-cli keyring set flask_app_db db_user keyring set flask_app_db db_pass # 依次设置其他字段
2. 加密的本地配置文件
将数据库连接信息加密存储在本地文件中,应用启动时使用密钥解密读取,密钥可通过操作系统环境变量传递(仅传递解密密钥,而非数据库凭据)。
实现步骤:
- 安装加密依赖:
pip install cryptography
- 编写加密脚本(一次性生成加密配置文件):
from cryptography.fernet import Fernet import json # 生成密钥(仅需一次,保存到安全位置,部署时通过环境变量传递) key = Fernet.generate_key() with open("secret.key", "wb") as f: f.write(key) # 明文配置信息 db_config = { "DB_USER": "your_db_user", "DB_PASS": "your_db_pass", "DB_HOST": "your_db_host", "DB_PORT": "5432", "DB_NAME": "your_db_name" } # 加密配置 fernet = Fernet(key) encrypted_config = fernet.encrypt(json.dumps(db_config).encode()) with open("encrypted_config.bin", "wb") as f: f.write(encrypted_config)
- 修改
config.py读取加密文件:
from cryptography.fernet import Fernet import json import os class ProductionConfig: # 从环境变量获取解密密钥(仅这个密钥暴露在环境变量,风险远低于数据库凭据) ENCRYPTION_KEY = os.environ.get("FLASK_DB_ENCRYPTION_KEY") if not ENCRYPTION_KEY: raise ValueError("FLASK_DB_ENCRYPTION_KEY environment variable not set") # 读取并解密配置 fernet = Fernet(ENCRYPTION_KEY.encode()) with open("encrypted_config.bin", "rb") as f: encrypted_config = f.read() db_config = json.loads(fernet.decrypt(encrypted_config).decode()) SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{db_config['DB_USER']}:{db_config['DB_PASS']}@{db_config['DB_HOST']}:{db_config['DB_PORT']}/{db_config['DB_NAME']}" SQLALCHEMY_TRACK_MODIFICATIONS = False
部署注意:
- 加密密钥
secret.key仅在生成加密配置时使用,部署时将密钥值设置为Linux/Windows的环境变量(Linux通过export FLASK_DB_ENCRYPTION_KEY="xxx",Windows通过set FLASK_DB_ENCRYPTION_KEY=xxx) encrypted_config.bin可随应用代码部署,因为没有密钥无法解密
3. PostgreSQL操作系统认证(无密码连接)
如果应用运行的操作系统用户与PostgreSQL数据库用户同名,可启用PostgreSQL的peer认证(Linux)或SSPI认证(Windows),无需存储任何密码,直接通过操作系统身份验证连接数据库。
配置步骤:
PostgreSQL端配置:
修改pg_hba.conf文件(Linux通常在/var/lib/postgresql/<version>/main/pg_hba.conf,Windows在C:\Program Files\PostgreSQL\<version>\data\pg_hba.conf),添加或修改对应规则:- Linux:
local your_db_name your_db_user peer host your_db_name your_db_user 127.0.0.1/32 scram-sha-256 # 远程连接仍用密码,本地用peer- Windows:
local your_db_name your_db_user sspi host your_db_name your_db_user 127.0.0.1/32 scram-sha-256修改后重启PostgreSQL服务。
应用端配置:
修改config.py,连接字符串无需密码:class ProductionConfig: SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2:///your_db_name" # 本地连接,自动使用操作系统用户 # 如果是远程连接且用SSPI/peer(仅信任局域网),可写: # SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://@your_db_host/your_db_name" SQLALCHEMY_TRACK_MODIFICATIONS = False
优势:
完全避免存储密码,安全性最高,仅需确保操作系统用户权限严格控制,应用运行用户仅拥有必要的数据库权限。
方案选择建议
- 若追求零凭据存储:优先选方案3(操作系统认证)
- 若需要跨机器远程连接:优先选方案1(系统凭据存储)或方案2(加密配置文件)
- 开发环境(Windows)可先用方案1或方案3,保持与生产环境一致的配置逻辑
内容的提问来源于stack exchange,提问作者user10028792
相关产品推荐
相关产品推荐

