Django使用mysql数据库后端时,如何实现MySQL服务器SSL认证的VERIFY_IDENTITY模式?
Django使用mysql数据库后端时,如何实现MySQL服务器SSL认证的VERIFY_IDENTITY模式?
嘿,我之前也碰到过这个问题!确实Django官方的MySQL后端文档里没明确提到如何开启VERIFY_IDENTITY模式,不过咱们可以通过驱动参数或者自定义后端两种方式解决,我给你详细拆解下:
首先得明确:你当前的配置已经启用了SSL加密通道(通过ca参数开启了VERIFY_CA模式),但VERIFY_IDENTITY还多了一步——验证服务器证书中的主机名(CN/SAN字段)是否和你配置的DB_HOST完全匹配,这能防止中间人攻击,安全性更高。
方法一:直接通过驱动参数配置(推荐)
Django的MySQL后端会把OPTIONS里的参数传递给底层的数据库驱动(比如mysqlclient或pymysql),咱们可以直接添加对应参数开启VERIFY_IDENTITY:
如果你用的是Django推荐的mysqlclient驱动:
直接在OPTIONS里新增ssl_mode参数,同时保留原有的ssl字典配置:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': env('DB_NAME'), 'USER': env('DB_USER'), 'PASSWORD': env('DB_PASSWORD'), 'HOST': env('DB_HOST'), 'PORT': env('DB_PORT'), 'CONN_MAX_AGE': 600, 'OPTIONS':{ 'ssl':{ 'ca': env('CA_CERT'), 'cert': env('CERT'), 'key': env('KEY') }, 'ssl_mode': 'VERIFY_IDENTITY' # 新增这一行 } } }
如果你用的是pymysql驱动:
需要把mode参数放到ssl字典里:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': env('DB_NAME'), 'USER': env('DB_USER'), 'PASSWORD': env('DB_PASSWORD'), 'HOST': env('DB_HOST'), 'PORT': env('DB_PORT'), 'CONN_MAX_AGE': 600, 'OPTIONS':{ 'ssl':{ 'ca': env('CA_CERT'), 'cert': env('CERT'), 'key': env('KEY'), 'mode': 'VERIFY_IDENTITY' # 把mode放到ssl字典里 } } } }
方法二:自定义数据库后端(兼容旧版本)
如果上面的方法因为驱动/Django版本太旧不生效,可以自定义一个MySQL后端,手动注入ssl_mode参数:
- 在你的Django项目里创建一个
backends目录,新建mysql.py文件,内容如下:
from django.db.backends.mysql.base import DatabaseWrapper class CustomMySQLBackend(DatabaseWrapper): def get_new_connection(self, conn_params): # 强制添加VERIFY_IDENTITY模式 conn_params['ssl_mode'] = 'VERIFY_IDENTITY' return super().get_new_connection(conn_params)
- 修改
DATABASES的ENGINE指向这个自定义后端:
DATABASES = { 'default': { 'ENGINE': 'your_app_name.backends.mysql.CustomMySQLBackend', # 替换成你的app名 # 其他配置和你原来的一样... 'OPTIONS':{ 'ssl':{ 'ca': env('CA_CERT'), 'cert': env('CERT'), 'key': env('KEY') } } } }
关键注意点
- 确保你的MySQL服务器证书里的CN字段或者SAN扩展包含你配置的
DB_HOST值(如果是IP,证书里要加IP的SAN;如果是域名,要加域名的SAN/CN),否则验证会失败! - 测试验证:你可以故意把
DB_HOST改成一个和证书不匹配的值,比如用服务器的IP但证书里只有域名,此时连接应该报错,说明VERIFY_IDENTITY已经生效了。
这样应该就能满足你的需求啦,我之前用第一种方法在多个项目里都跑通了,没问题的!




