Skip to content

解决 ODBC Driver 18 for SQL Server SSL 证书验证失败错误

问题描述

在使用 ODBC Driver 18 for SQL Server 连接 SQL Server 数据库时,可能会出现以下 SSL 证书验证错误:

[Microsoft][ODBC Driver 18 for SQL Server]SSL Provider: [error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:self signed certificate]

这个错误通常出现在以下环境中:

  • Ubuntu 20.04 或更高版本
  • PHP 7.4 FPM 与 nginx
  • OpenSSL 1.1.1f 或更新版本
  • SQL Server 2012 或更高版本

错误原因是 ODBC Driver 18 默认要求进行严格的 SSL 证书验证,而当服务器使用自签名证书或证书链不完整时,验证会失败。

解决方案

方法一:在连接字符串中添加信任服务器证书选项(推荐)

这是最直接且常用的解决方案,通过在连接字符串中添加 TrustServerCertificate=yes 参数来跳过证书验证。

php
$sql_info = array(
    'UID' => 'your_sql_user',
    'PWD' => 'your_password',
    'Database' => 'your_DB_name',
    'TrustServerCertificate' => 1,
);

sqlsrv_connect('your_host_or_ip', $sql_info);
python
conn_str = f'DRIVER=ODBC Driver 18 for SQL Server;SERVER={server};DATABASE={database};UID={username};PWD={password};TrustServerCertificate=yes'
vbnet
Dim conStr As String = "Driver={ODBC Driver 18 for SQL Server};Server=your_servername;Database=your_databasename;Uid=your_username;Pwd=your_password;TrustServerCertificate=yes;"

安全提示

TrustServerCertificate=yes 会跳过 SSL 证书验证,降低了连接的安全性。仅应在开发环境或可信的内部网络中使用。生产环境应使用有效的 SSL 证书。

方法二:禁用加密连接

如果安全性不是首要考虑因素(如在开发环境),可以完全禁用加密:

python
conn_str = f'DRIVER=ODBC Driver 18 for SQL Server;SERVER={server};DATABASE={database};UID={username};PWD={password};Encrypt=no'
php
'trust_server_certificate' => 'true',
'encrypt' => 'false'

方法三:调整 OpenSSL 安全级别

在某些 Linux 发行版上,可能需要降低 OpenSSL 的安全级别:

bash
sudo nano /etc/ssl/openssl.cnf

找到或添加以下配置:

ini
[system_default_sect]
CipherString = DEFAULT:@SECLEVEL=0

注意

降低安全级别会增加系统安全性风险,请谨慎操作并仅在必要时使用此方法。

方法四:使用 SQLCMD 命令行工具

对于命令行操作,可以使用 -C 参数来信任服务器证书:

bash
sqlcmd -S localhost -U sa -P 'YourPassword' -C

或者尝试使用 IP 地址而非主机名:

bash
sqlcmd -S 127.0.0.1 -U sa -P 'YourPassword' -C

方法五:框架特定配置

php
'sqlsrv' => [
    'driver' => 'sqlsrv',
    'host' => env('DB_HOST', 'localhost'),
    'port' => env('DB_PORT', '1433'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'charset' => 'utf8',
    'prefix' => '',
    'trust_server_certificate' => 'true'
]
python
DATABASES['source'] = {
    'ENGINE': 'mssql',
    'NAME': 'db_name',
    'USER': 'db_user',
    'PASSWORD': 'db_pass',
    'HOST': 'db_host',
    'OPTIONS': {
        'driver': 'ODBC Driver 18 for SQL Server',
        'extra_params': "TrustServerCertificate=yes"
    },
}
python
engine = sqlalchemy.create_engine(
    conn_string,
    connect_args = {
        "TrustServerCertificate": "yes"
    }, echo=False)

根本原因分析

ODBC Driver 18 引入了更严格的 SSL/TLS 安全要求:

  1. 默认启用加密连接
  2. 默认要求验证服务器证书
  3. 对自签名证书和证书链不完整的情况更加敏感

这与早期版本的驱动程序行为不同,早期版本可能默认不验证证书或使用较宽松的安全设置。

最佳实践建议

  1. 生产环境:应使用有效的 SSL 证书而非自签名证书
  2. 开发环境:可使用 TrustServerCertificate=yes 但应意识到安全风险
  3. 连接字符串:始终明确指定加密和证书信任选项,避免依赖默认设置
  4. 驱动程序:确保使用正确版本的 ODBC 驱动程序,Linux 和 Windows 上的驱动程序名称可能不同

环境检查

确认你的环境配置:

bash
# 检查 OpenSSL 版本
openssl version

# 测试与 SQL Server 的 SSL 连接
openssl s_client -connect your_server_ip:1433 -tls1

# 查看已安装的 ODBC 驱动程序
odbcinst -q -d

总结

ODBC Driver 18 的 SSL 证书验证错误通常可通过以下方式解决:

  1. 在连接字符串中添加 TrustServerCertificate=yes
  2. 或禁用加密 Encrypt=no(仅限开发环境)
  3. 根据使用的框架进行相应配置

选择解决方案时应权衡安全需求和开发便利性,生产环境强烈建议使用有效的 SSL 证书而非绕过验证。