在数据库应用开发中,安全防护是避免数据泄露、篡改的关键(如防止 SQL 注入攻击、控制非法访问),而异常处理是保障应用稳定运行的基础(如应对数据库连接失败、SQL 语法错误)。本章基于python_db数据库,系统讲解 Python 数据库编程中的核心安全措施(SQL 注入防范、权限管理、数据加密)和全面的异常处理方案,通过规整案例和实操演示,帮助你构建安全、健壮的数据库应用。
9.1 数据库安全的核心威胁与防护原则
9.1.1 常见安全威胁
数据库应用面临的安全风险主要包括以下几类,需针对性防护:
威胁类型 | 核心危害 | 典型场景 |
SQL 注入攻击 | 非法执行 SQL 语句(如删表、窃取数据) | 用户登录时输入' OR '1'='1,构造永真条件绕过验证,甚至执行DROP TABLE |
权限滥用 | 未授权访问或修改数据(如普通用户删表) | 应用使用 root 账号连接数据库,被攻击者利用后可操作所有表 |
数据泄露 | 敏感数据(如密码、手机号)被窃取 | 数据库备份文件未加密,或查询结果直接暴露敏感字段 |
连接信息泄露 | 数据库账号密码被窃取,导致非法连接 | 代码中硬编码数据库密码,或配置文件未加密存储 |
SQL 语法错误注入 | 通过输入特殊字符触发语法错误,暴露数据库信息 | 用户输入含'的字符串(如O'Neil),导致 SQL 语句语法错误,泄露表结构 |
9.1.2 安全防护核心原则
- 最小权限原则:应用使用的数据库账号仅授予必要权限(如仅SELECT/INSERT,不授予DROP/ALTER)。
- 参数化查询原则:所有用户输入均通过参数化方式传递,禁止直接拼接 SQL 字符串。
- 敏感数据加密原则:敏感字段(如密码)存储时需加密,避免明文存储。
- 异常信息隐藏原则:生产环境中不暴露原始数据库错误信息(如 SQL 语法错误详情),防止攻击者利用。
9.2 防范 SQL 注入攻击(核心安全措施)
SQL 注入是最常见且危害最大的数据库安全威胁,其本质是 “攻击者通过用户输入篡改 SQL 语句结构”。Python 中防范 SQL 注入的核心手段是参数化查询(使用%s占位符,而非字符串拼接),以下为详细演示。
9.2.1 SQL 注入攻击演示(危险写法)
先通过 “用户登录” 场景演示未防范 SQL 注入的危险:
import mysql.connector
from mysql.connector import Error
def unsafe_login(username, password):
"""未防范SQL注入的登录函数(危险!)"""
connection = None
try:
connection = mysql.connector.connect(
host='localhost',
user='root',
password='your_password',
database='python_db'
)
cursor = connection.cursor()
# 危险写法:直接拼接用户输入到SQL语句
unsafe_sql = f"SELECT * FROM users WHERE name = '{username}' AND password = '{password}'"
print(f"执行的SQL(危险,存在注入风险):{unsafe_sql}")
cursor.execute(unsafe_sql)
user = cursor.fetchone()
if user:
print(f"登录成功!欢迎您,{user[1]}")
else:
print("用户名或密码错误")
except Error as e:
print(f"登录出错:{e}")
finally:
if connection and connection.is_connected():
cursor.close()
connection.close()
# 正常测试:输入正确用户名和密码
print("=== 正常测试 ===")
unsafe_login(username="张三更新", password="123456") # 假设密码是123456(实际应加密)
# SQL注入测试:输入恶意字符串,绕过登录验证
print("\n=== SQL注入测试(危险)===")
# 输入密码为 "' OR '1'='1",拼接后SQL变为:
# SELECT * FROM users WHERE name = '任意用户名' AND password = '' OR '1'='1'
# '1'='1'是永真条件,将返回所有用户,实现非法登录
unsafe_login(username="任意用户名", password="' OR '1'='1")
运行结果(危险场景)
=== 正常测试 ===
执行的SQL(危险,存在注入风险):SELECT * FROM users WHERE name = '张三更新' AND password = '123456'
登录成功!欢迎您,张三更新
=== SQL注入测试(危险)===
执行的SQL(危险,存在注入风险):SELECT * FROM users WHERE name = '任意用户名' AND password = '' OR '1'='1'
登录成功!欢迎您,张三更新 # 未验证密码,直接登录成功,存在严重安全漏洞
9.2.2 防范 SQL 注入:参数化查询(安全写法)
使用%s作为占位符,将用户输入作为参数传递给execute()方法,禁止直接拼接字符串,可彻底防范 SQL 注入:
def safe_login(username, password):
"""防范SQL注入的登录函数(安全写法)"""
connection = None
try:
connection = mysql.connector.connect(
host='localhost',
user='root',
password='your_password',
database='python_db'
)
cursor = connection.cursor()
# 安全写法:使用%s占位符,用户输入作为参数传递
safe_sql = "SELECT * FROM users WHERE name = %s AND password = %s"
print(f"执行的SQL模板:{safe_sql}")
print(f"传递的参数:(username={username}, password={password})")
# 第二个参数必须是元组,即使只有一个参数也需加逗号
cursor.execute(safe_sql, (username, password))
user = cursor.fetchone()
if user:
print(f"登录成功!欢迎您,{user[1]}")
else:
print("用户名或密码错误")
except Error as e:
print(f"登录出错:{e}")
finally:
if connection and connection.is_connected():
cursor.close()
connection.close()
# 正常测试:正确用户名和密码
print("=== 正常测试 ===")
safe_login(username="张三更新", password="123456")
# SQL注入测试:输入恶意字符串(参数化查询会自动转义特殊字符,注入失效)
print("\n=== SQL注入测试(安全)===")
safe_login(username="任意用户名", password="' OR '1'='1")
运行结果(安全场景)
=== 正常测试 ===
执行的SQL模板:SELECT * FROM users WHERE name = %s AND password = %s
传递的参数:(username=张三更新, password=123456)
登录成功!欢迎您,张三更新
=== SQL注入测试(安全)==="
执行的SQL模板:SELECT * FROM users WHERE name = %s AND password = %s
传递的参数:(username=任意用户名, password=' OR '1'='1)
用户名或密码错误 # 注入失效,无法绕过验证,安全防护生效
原理说明
参数化查询中,MySQL 驱动会自动对用户输入的特殊字符(如'、;、OR)进行转义(如将'转换为\'),使恶意输入无法篡改 SQL 语句结构,从而彻底防范 SQL 注入。
9.3 数据库权限管理(最小权限原则)
默认的root账号拥有数据库的所有权限(如删库、改表),若应用使用root账号连接数据库,一旦被攻击,后果严重。正确做法是创建专用应用账号,仅授予必要权限(如SELECT/INSERT/UPDATE),遵循 “最小权限原则”。
9.3.1 创建应用专用账号(Python 实现)
以下示例创建一个名为app_user的账号,仅授予python_db数据库的SELECT、INSERT、UPDATE权限(无DELETE、DROP权限):
def create_app_user():
"""创建应用专用账号并授予最小权限"""
connection = None
try:
# 需使用root账号连接(只有root有权限创建新账号)
connection = mysql.connector.connect(
host='localhost',
user='root',
password='your_password',
database='python_db'
)
cursor = connection.cursor()
# 1. 创建账号(用户名:app_user,密码:App@123456,仅允许本地连接)
create_user_sql = "CREATE USER IF NOT EXISTS 'app_user'@'localhost' IDENTIFIED BY 'App@123456'"
cursor.execute(create_user_sql)
# 2. 授予权限:仅允许操作python_db数据库的SELECT/INSERT/UPDATE
grant_sql = """
GRANT SELECT, INSERT, UPDATE
ON python_db.* # 仅对python_db数据库的所有表生效
TO 'app_user'@'localhost'
"""
cursor.execute(grant_sql)
# 3. 撤销危险权限(确保无DROP/ALTER等权限)
revoke_sql = "REVOKE DROP, ALTER, DELETE ON python_db.* FROM 'app_user'@'localhost'"
cursor.execute(revoke_sql)
connection.commit()
print("应用专用账号'app_user'创建成功,已授予最小权限(SELECT/INSERT/UPDATE)")
# 验证权限
print("\n=== 验证app_user账号权限 ===")
cursor.execute("SHOW GRANTS FOR 'app_user'@'localhost'")
grants = cursor.fetchall()
for grant in grants:
print(grant[0])
except Error as e:
print(f"创建账号出错:{e}")
if connection:
connection.rollback()
finally:
if connection and connection.is_connected():
cursor.close()
connection.close()
if __name__ == "__main__":
create_app_user()
运行结果(规整对齐)
应用专用账号'app_user'创建成功,已授予最小权限(SELECT/INSERT/UPDATE)
=== 验证app_user账号权限 ===
GRANT USAGE ON *.* TO `app_user`@`localhost`
GRANT SELECT, INSERT, UPDATE ON `python_db`.* TO `app_user`@`localhost`
9.3.2 使用应用账号连接数据库(安全实践)
应用开发中,应使用app_user等专用账号连接数据库,而非root,即使账号泄露,攻击者也无法执行删表、改结构等危险操作:
def connect_with_app_user():
"""使用应用专用账号app_user连接数据库"""
connection = None
try:
# 使用app_user账号连接(仅拥有SELECT/INSERT/UPDATE权限)
connection = mysql.connector.connect(
host='localhost',
user='app_user', # 应用专用账号
password='App@123456', # 账号密码
database='python_db'
)
if connection.is_connected():
cursor = connection.cursor()
print("使用app_user账号连接数据库成功")
# 测试允许的操作(SELECT)
print("\n=== 测试允许的操作(SELECT)===")
cursor.execute("SELECT name, email FROM users LIMIT 2")
result = cursor.fetchall()
print("查询结果:")
for row in result:
print(row)
# 测试禁止的操作(DELETE,会报错)
print("\n=== 测试禁止的操作(DELETE)===")
cursor.execute("DELETE FROM users WHERE id = 1")
connection.commit()
except Error as e:
print(f"操作出错:{e}")
finally:
if connection and connection.is_connected():
cursor.close()
connection.close()
if __name__ == "__main__":
connect_with_app_user()
运行结果(权限控制生效)
使用app_user账号连接数据库成功
=== 测试允许的操作(SELECT)===
查询结果:
('张三更新', 'zhangsan@new-example.com')
('李四', 'lisi@new-example.com')
=== 测试禁止的操作(DELETE)===
操作出错:1142 (42000): DELETE command denied to user 'app_user'@'localhost' for table 'users'
结果分析
- app_user账号可正常执行SELECT操作(允许的权限);
- 执行DELETE操作时,MySQL 返回权限拒绝错误,说明最小权限原则生效,即使账号泄露,也无法删除数据。
9.4 敏感数据加密(密码加密存储)
用户密码等敏感数据若明文存储,一旦数据库泄露,攻击者可直接获取账号密码。正确做法是加密存储:将密码通过哈希算法(如 SHA-256)加盐(Salt)后存储,验证时比对哈希值而非明文。
9.4.1 密码加密存储实现(Python+hashlib)
使用hashlib库实现密码加盐哈希,示例如下:
import hashlib
import uuid # 用于生成随机盐值
def generate_salt():
"""生成随机盐值(16字节,确保每次加密结果不同)"""
return uuid.uuid4().hex # 生成32位随机字符串
def hash_password(password, salt):
"""密码加盐哈希:password + salt → SHA-256哈希"""
# 拼接密码和盐值,转换为UTF-8编码
password_salt = f"{password}{salt}".encode('utf-8')
# 使用SHA-256计算哈希值
hash_obj = hashlib.sha256(password_salt)
# 返回哈希值的十六进制字符串
return hash_obj.hexdigest()
def register_user(username, password):
"""用户注册:加密存储密码(含盐值)"""
connection = None
try:
connection = mysql.connector.connect(
host='localhost',
user='root',
password='your_password',
database='python_db'
)
# 先为users表新增salt和hashed_password字段(存储盐值和哈希后的密码)
cursor = connection.cursor()
cursor.execute("ALTER TABLE users ADD COLUMN salt VARCHAR(32), ADD COLUMN hashed_password VARCHAR(64)")
connection.commit()
# 生成盐值和哈希密码
salt = generate_salt()
hashed_pwd = hash_password(password, salt)
# 插入用户数据(存储盐值和哈希密码,不存储明文)
insert_sql = """
INSERT INTO users (name, email, salt, hashed_password)
VALUES (%s, %s, %s, %s)
"""
cursor.execute(insert_sql, (username, f"{username}@example.com", salt, hashed_pwd))
connection.commit()
print(f"用户'{username}'注册成功,密码已加密存储(盐值:{salt},哈希密码:{hashed_pwd[:20]}...)")
except Error as e:
if "Duplicate column name" in str(e):
# 字段已存在,直接插入数据
cursor = connection.cursor()
salt = generate_salt()
hashed_pwd = hash_password(password, salt)
insert_sql = "INSERT INTO users (name, email, salt, hashed_password) VALUES (%s, %s, %s, %s)"
cursor.execute(insert_sql, (username, f"{username}@example.com", salt, hashed_pwd))
connection.commit()
print(f"用户'{username}'注册成功,密码已加密存储(盐值:{salt},哈希密码:{hashed_pwd[:20]}...)")
else:
print(f"注册出错:{e}")
finally:
if connection and connection.is_connected():
cursor.close()
connection.close()
def login_with_encrypted_password(username, password):
"""用户登录:验证加密后的密码"""
connection = None
try:
connection = mysql.connector.connect(
host='localhost',
user='root',
password='your_password',
database='python_db'
)
cursor = connection.cursor()
# 查询用户的盐值和哈希密码
select_sql = "SELECT salt, hashed_password FROM users WHERE name = %s"
cursor.execute(select_sql, (username,))
user = cursor.fetchone()
if not user:
print("用户名不存在")
return
salt, stored_hash = user
# 使用相同的盐值对输入密码重新哈希</doubaocanvas>
9.4.1 密码加密存储实现(完整代码)
input_hash = hash_password(password, salt)
# 比对输入密码的哈希值与存储的哈希值
if input_hash == stored_hash:
print(f"登录成功!欢迎您,{username}")
else:
print("用户名或密码错误")
except Error as e:
print(f"登录出错:{e}")
finally:
if connection and connection.is_connected():
cursor.close()
connection.close()
# 测试注册与加密登录
if __name__ == "__main__":
# 注册新用户(密码明文为"User@123",存储为哈希值)
print("=== 测试用户注册(密码加密存储)===")
register_user(username="安全测试用户", password="User@123")
# 测试正确密码登录
print("\n=== 测试正确密码登录 ===")
login_with_encrypted_password(username="安全测试用户", password="User@123")
# 测试错误密码登录
print("\n=== 测试错误密码登录 ===")
login_with_encrypted_password(username="安全测试用户", password="WrongPass123")
运行结果(规整对齐)
=== 测试用户注册(密码加密存储)===
用户'安全测试用户'注册成功,密码已加密存储(盐值:
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6,哈希密码:
f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c...)
=== 测试正确密码登录 ===
登录成功!欢迎您,安全测试用户
=== 测试错误密码登录 ===
用户名或密码错误
安全优势
- 即使数据库泄露,攻击者获取的是salt(盐值)和hashed_password(哈希密码),无法通过哈希值反推明文密码;
- 每个用户的盐值随机生成,即使两个用户密码相同,存储的哈希值也不同,避免 “彩虹表” 破解(一种通过预计算哈希值匹配密码的攻击方式)。
9.5 全面的异常处理机制
数据库操作过程中可能出现多种异常(如连接超时、SQL 语法错误、权限不足),若未处理,会导致应用崩溃或暴露敏感信息。Python 中需通过try-except-else-finally捕获异常,并分场景处理,同时在生产环境中隐藏原始错误详情。
9.5.1 常见数据库异常类型
MySQL 数据库操作中常见的异常及处理方式如下表所示:
异常类型(Error 代码) | 异常描述 | 处理建议 | 示例场景 |
2003 (HY000) | 无法连接数据库(如主机地址错误、服务未启动) | 检查数据库服务状态、主机地址和端口 | host='192.168.1.100'实际应为localhost |
1045 (28000) | 账号密码错误(Access denied) | 验证数据库用户名和密码 | password='12345'实际应为App@123456 |
1049 (42000) | 数据库不存在(Unknown database) | 检查数据库名称是否正确,或先创建数据库 | database='python_db_test'实际应为python_db |
1064 (42000) | SQL 语法错误(You have an error in your SQL syntax) | 检查 SQL 语句语法(如关键字拼写错误、括号不匹配) | SELEC * FROM users(缺少T) |
1142 (42000) | 权限不足(如无 DELETE 权限) | 验证数据库账号权限,或申请必要权限 | app_user账号执行DELETE操作 |
2013 (HY000) | 连接超时(Lost connection to MySQL server) | 检查网络稳定性,或增加连接超时参数 | 远程数据库网络波动导致连接中断 |
9.5.2 分级异常处理实现(生产级)
以下示例实现分级异常处理:捕获特定异常并给出友好提示,未捕获的异常统一处理,同时在生产环境中隐藏原始错误信息:
import mysql.connector
from mysql.connector import Error
import logging
# 配置日志(生产环境中记录错误到日志文件,而非直接打印)
logging.basicConfig(
filename='db_error.log',
level=logging.ERROR,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def safe_db_operation(sql, params=None, operation_type="read"):
"""
安全的数据库操作函数(支持读写操作,分级异常处理)
:param sql: SQL语句
:param params: SQL参数(元组,用于参数化查询)
:param operation_type: 操作类型(read:读操作,write:写操作)
:return: 查询结果(读操作)或影响行数(写操作),失败返回None
"""
connection = None
cursor = None
try:
# 1. 建立数据库连接(增加连接超时参数)
connection = mysql.connector.connect(
host='localhost',
user='app_user',
password='App@123456',
database='python_db',
connect_timeout=10 # 连接超时时间(10秒)
)
cursor = connection.cursor()
# 2. 执行SQL操作
cursor.execute(sql, params or ())
# 3. 区分读写操作,返回结果
if operation_type == "read":
result = cursor.fetchall()
logging.info(f"读操作成功,SQL:{sql},返回记录数:{len(result)}")
return result
else: # write操作(INSERT/UPDATE/DELETE)
connection.commit()
affected_rows = cursor.rowcount
logging.info(f"写操作成功,SQL:{sql},影响行数:{affected_rows}")
return affected_rows
except Error as e:
# 4. 分级处理特定异常
error_code = e.errno
error_msg = str(e)
# 记录原始错误到日志(生产环境排查用)
logging.error(f"数据库操作失败:SQL={sql},参数={params},错误代码={error_code},错误信息={error_msg}")
# 生产环境友好提示(隐藏敏感信息)
friendly_msg = "数据库操作失败,请稍后重试"
if error_code == 2003:
friendly_msg = "数据库服务暂时不可用,请检查服务状态"
elif error_code == 1045:
friendly_msg = "数据库认证失败,请联系管理员"
elif error_code == 1049:
friendly_msg = "目标数据库不存在,请确认配置"
elif error_code == 1064:
friendly_msg = "数据请求格式错误,请检查输入"
elif error_code == 1142:
friendly_msg = "当前操作权限不足,请联系管理员"
elif error_code == 2013:
friendly_msg = "数据库连接超时,请检查网络"
print(f"操作提示:{friendly_msg}")
# 写操作失败时回滚事务
if connection and operation_type == "write":
connection.rollback()
logging.warning("写操作失败,已执行事务回滚")
return None
except Exception as e:
# 5. 处理其他未捕获的异常(如代码逻辑错误)
unexpected_msg = f"意外错误:{str(e)}"
logging.error(unexpected_msg)
print("系统繁忙,请稍后重试")
return None
finally:
# 6. 确保资源释放(无论成功或失败,都关闭游标和连接)
if cursor:
cursor.close()
logging.debug("数据库游标已关闭")
if connection and connection.is_connected():
connection.close()
logging.debug("数据库连接已关闭")
# 测试分级异常处理
if __name__ == "__main__":
# 测试1:正常读操作(查询用户列表)
print("=== 测试1:正常读操作 ===")
select_sql = "SELECT name, email FROM users LIMIT 2"
result = safe_db_operation(sql=select_sql, operation_type="read")
if result:
print("查询结果:")
for row in result:
print(row)
# 测试2:权限不足异常(执行DELETE操作,app_user无权限)
print("\n=== 测试2:权限不足异常 ===")
delete_sql = "DELETE FROM users WHERE id = %s"
safe_db_operation(sql=delete_sql, params=(1,), operation_type="write")
# 测试3:SQL语法错误异常(SELEC拼写错误)
print("\n=== 测试3:SQL语法错误异常 ===")
wrong_sql = "SELEC name FROM users" # 错误:缺少T
safe_db_operation(sql=wrong_sql, operation_type="read")
运行结果(规整对齐)
=== 测试1:正常读操作 ===
查询结果:
('张三更新', 'zhangsan@new-example.com')
('李四', 'lisi@new-example.com')
=== 测试2:权限不足异常 ===
操作提示:当前操作权限不足,请联系管理员
=== 测试3:SQL语法错误异常 ===
操作提示:数据请求格式错误,请检查输入
日志文件(db_error.log)内容示例
2025-08-23 15:30:00,123 - INFO - 读操作成功,SQL:SELECT name, email FROM users LIMIT 2,返回记录数:2
2025-08-23 15:30:05,456 - ERROR - 数据库操作失败:SQL=DELETE FROM users WHERE id = %s,参数=(1,),错误代码=1142,错误信息=1142 (42000): DELETE command denied to user 'app_user'@'localhost' for table 'users'
2025-08-23 15:30:05,457 - WARNING - 写操作失败,已执行事务回滚
2025-08-23 15:30:10,789 - ERROR - 数据库操作失败:SQL=SELEC name FROM users,参数=(),错误代码=1064,错误信息=1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELEC name FROM users' at line 1
9.6 安全配置最佳实践
除上述措施外,还需通过以下配置进一步提升数据库安全性,避免常见安全漏洞:
9.6.1 避免硬编码连接信息
代码中硬编码数据库账号密码(如password='your_password'),若代码泄露,会直接导致连接信息泄露。正确做法是使用配置文件或环境变量存储连接信息,示例如下:
1. 使用配置文件(config.ini)存储连接信息
创建config.ini文件:
[mysql]
host = localhost
user = app_user
password = App@123456
database = python_db
port = 3306
connect_timeout = 10
2. Python 读取配置文件
import configparser
def get_db_config():
"""从配置文件读取数据库连接信息"""
config = configparser.ConfigParser()
config.read('config.ini') # 读取配置文件
return {
'host': config.get('mysql', 'host'),
'user': config.get('mysql', 'user'),
'password': config.get('mysql', 'user'),
'database': config.get('mysql', 'database'),
'port': int(config.get('mysql', 'port')),
'connect_timeout': int(config.get('mysql', 'connect_timeout'))
}
# 使用配置连接数据库
def connect_with_config():
connection = None
try:
db_config = get_db_config()
connection = mysql.connector.connect(**db_config)
print("使用配置文件连接数据库成功")
except Error as e:
print(f"连接出错:{e}")
finally:
if connection and connection.is_connected():
connection.close()
# 测试
connect_with_config()
安全注意事项
- 配置文件需设置权限(如 Linux 下chmod 600 config.ini,仅所有者可读写);
- 生产环境中,配置文件需通过加密工具加密(如cryptography库),避免明文存储。
9.6.2 限制数据库访问 IP
默认情况下,MySQL 允许所有 IP 连接(%通配符),存在远程攻击风险。正确做法是仅允许应用服务器 IP 访问数据库,示例如下:
-- 修改app_user账号,仅允许192.168.1.100(应用服务器IP)连接
UPDATE mysql.user SET Host = '192.168.1.100' WHERE User = 'app_user' AND Host = 'localhost';
FLUSH PRIVILEGES; -- 刷新权限
9.6.3 定期备份与日志审计
- 定期备份:通过第 6 章的备份方法,定期导出数据库数据(如每日凌晨备份),避免数据丢失;
- 日志审计:开启 MySQL 的查询日志和错误日志,记录所有数据库操作,便于事后排查安全事件:
# my.cnf(MySQL配置文件)中开启日志
general_log = 1
general_log_file = /var/log/mysql/mysql-general.log
log_error = /var/log/mysql/mysql-error.log
9.7 本章小结
本章系统讲解了 Python 数据库编程中的安全防护与异常处理核心技能:
- SQL 注入防范:通过参数化查询(%s占位符)彻底避免注入风险,禁止字符串拼接 SQL;
- 权限管理:创建应用专用账号,遵循最小权限原则,限制危险操作;
- 敏感数据加密:密码通过加盐哈希存储,避免明文泄露;
- 分级异常处理:捕获特定数据库异常,生产环境隐藏敏感错误信息,同时记录日志便于排查;
- 安全配置:使用配置文件存储连接信息、限制访问 IP、定期备份与审计。
下一章将学习 Python 数据库编程的高级应用 ——ORM 框架(如 SQLAlchemy),通过封装 SQL 操作,进一步简化数据库开发,提升代码可维护性。