配置应用程序的 SSL 连接性以安全连接到 Azure Database for MySQL

适用于: Azure Database for MySQL 单一服务器

重要

Azure Database for MySQL 单一服务器即将停用。 强烈建议升级到 Azure Database for MySQL 灵活服务器。 有关如何迁移到 Azure Database for MySQL 灵活服务器的详细信息,请参阅 Azure Database for MySQL 单一服务器发生了什么情况?

Azure Database for MySQL 支持使用安全套接字层 (SSL) 将 Azure Database for MySQL 服务器连接到客户端应用程序。 通过在数据库服务器与客户端应用程序之间强制实施 SSL 连接,可以加密服务器与应用程序之间的数据流,有助于防止“中间人”攻击。

步骤 1:获取 SSL 证书

https://dl.cacerts.digicert.com/DigiCertGlobalRootCA.crt.pem 下载通过 SSL 与 Azure Database for MySQL 服务器通信所需的证书,再将证书文件保存到本地驱动器(例如,本教程使用 c:\ssl)。

步骤 2:绑定 SSL

对于特定的编程语言连接字符串,请参考下面的示例代码

使用 MySQL Workbench 通过 SSL 连接到服务器

配置 MySQL Workbench,以便安全地通过 SSL 连接。

  1. 从“设置新连接”对话框,导航到“SSL”选项卡 。

  2. 将“使用 SSL” 字段更新为“必需”。

  3. 在“SSL CA 文件:”字段中,输入 DigiCertGlobalRootCA.crt.pem 的文件位置。

    保存 SSL 配置

对于现有连接,可以通过右键单击“连接”图标并选择“编辑”来绑定 SSL。 然后导航到“SSL”选项卡,并绑定证书文件。

使用 MySQL CLI 通过 SSL 连接到服务器

绑定 SSL 证书的另一种方法是使用 MySQL 命令行接口执行以下命令。

mysql.exe -h mydemoserver.mysql.database.chinacloudapi.cn -u Username@mydemoserver -p --ssl-mode=REQUIRED --ssl-ca=c:\ssl\DigiCertGlobalRootCA.crt.pem

注意

在 Windows 上使用 MySQL 命令行接口时,可能会收到错误 SSL connection error: Certificate signature check failed。 如果发生这种情况,请将 --ssl-mode=REQUIRED --ssl-ca={filepath} 参数替换为 --ssl

步骤 3:在 Azure 中强制实施 SSL 连接

使用 Azure 门户

在 Azure 门户中,访问 Azure Database for MySQL 服务器,并单击“连接安全性”。 使用切换按钮来启用或禁用“强制实施 SSL 连接”设置,并单击“保存” 。 Azure 建议你始终启用“强制实施 SSL 连接”设置,以增强安全性。

Azure 门户的屏幕截图,该门户用于在 Azure Database for MySQL 中强制进行 SSL 连接

使用 Azure CLI

可以通过在 Azure CLI 中分别使用“Enabled”或“Disabled”值来启用或禁用“ssl-enforcement”参数。

az mysql server update --resource-group myresource --name mydemoserver --ssl-enforcement Enabled

步骤 4:验证 SSL 连接

执行 mysql status 命令,验证是否已使用 SSL 连接到 MySQL 服务器:

mysql> status

通过查看输出来确认连接是否已加密,如果已加密,输出应显示为:“SSL: 使用中的密码为 AES256-SHA”

代码示例

若要从应用程序通过 SSL 与 Azure Database for MySQL 建立安全连接,请参阅以下代码示例:

请参阅 Azure Database for MySQL 服务支持的兼容驱动程序列表。

PHP

$conn = mysqli_init();
mysqli_ssl_set($conn,NULL,NULL, "/var/www/html/DigiCertGlobalRootCA.crt.pem", NULL, NULL) ; 
mysqli_real_connect($conn, 'mydemoserver.mysql.database.chinacloudapi.cn', 'myadmin@mydemoserver', 'yourpassword', 'quickstartdb', 3306, MYSQLI_CLIENT_SSL);
if (mysqli_connect_errno()) {
die('Failed to connect to MySQL: '.mysqli_connect_error());
}

PHP(使用 PDO)

$options = array(
	PDO::MYSQL_ATTR_SSL_CA => '/var/www/html/DigiCertGlobalRootCA.crt.pem'
);
$db = new PDO('mysql:host=mydemoserver.mysql.database.chinacloudapi.cn;port=3306;dbname=databasename', 'username@mydemoserver', 'yourpassword', $options);

Python (MySQLConnector Python)

try:
    conn = mysql.connector.connect(user='myadmin@mydemoserver',
                                   password='yourpassword',
                                   database='quickstartdb',
                                   host='mydemoserver.mysql.database.chinacloudapi.cn', 
                                   ssl_ca='/var/www/html/DigiCertGlobalRootCA.crt.pem')
except mysql.connector.Error as err:
    print(err)

Python (PyMySQL)

conn = pymysql.connect(user='myadmin@mydemoserver',
                       password='yourpassword',
                       database='quickstartdb',
                       host = 'mydemoserver.mysql.database.chinacloudapi.cn', 
                       ssl={'ca': '/var/www/html/DigiCertGlobalRootCA.crt.pem'})

Django (PyMySQL)

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'quickstartdb',
        'USER': 'myadmin@mydemoserver',
        'PASSWORD': 'yourpassword',
        'HOST': 'mydemoserver.mysql.database.chinacloudapi.cn',
        'PORT': '3306',
        'OPTIONS': {
            'ssl': {'ca': '/var/www/html/DigiCertGlobalRootCA.crt.pem'}
        }
    }
}

Ruby

client = Mysql2::Client.new(
        :host     => 'mydemoserver.mysql.database.chinacloudapi.cn', 
        :username => 'myadmin@mydemoserver',
        :password => 'yourpassword',
        :database => 'quickstartdb',
        :sslca => '/var/www/html/DigiCertGlobalRootCA.crt.pem'
    )

Golang

rootCertPool := x509.NewCertPool()
pem, _ := ioutil.ReadFile("/var/www/html/DigiCertGlobalRootCA.crt.pem")
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
    log.Fatal("Failed to append PEM.")
}
mysql.RegisterTLSConfig("custom", &tls.Config{RootCAs: rootCertPool})
var connectionString string
connectionString = fmt.Sprintf("%s:%s@tcp(%s:3306)/%s?allowNativePasswords=true&tls=custom","myadmin@mydemoserver" , "yourpassword", "mydemoserver.mysql.database.chinacloudapi.cn", 'quickstartdb')	
db, _ := sql.Open("mysql", connectionString)

Java(适用于 Java 的 MySQL 连接器)

# generate truststore and keystore in code

String importCert = " -import "+
    " -alias mysqlServerCACert "+
    " -file " + ssl_ca +
    " -keystore truststore "+
    " -trustcacerts " +
    " -storepass password -noprompt ";
String genKey = " -genkey -keyalg rsa " +
    " -alias mysqlClientCertificate -keystore keystore " +
    " -storepass password123 -keypass password " +
    " -dname CN=MS ";
sun.security.tools.keytool.Main.main(importCert.trim().split("\\s+"));
sun.security.tools.keytool.Main.main(genKey.trim().split("\\s+"));

# use the generated keystore and truststore

System.setProperty("javax.net.ssl.keyStore","path_to_keystore_file");
System.setProperty("javax.net.ssl.keyStorePassword","password");
System.setProperty("javax.net.ssl.trustStore","path_to_truststore_file");
System.setProperty("javax.net.ssl.trustStorePassword","password");

url = String.format("jdbc:mysql://%s/%s?serverTimezone=UTC&useSSL=true", 'mydemoserver.mysql.database.chinacloudapi.cn', 'quickstartdb');
properties.setProperty("user", 'myadmin@mydemoserver');
properties.setProperty("password", 'yourpassword');
conn = DriverManager.getConnection(url, properties);

Java(适用于 Java 的 MariaDB 连接器)

# generate truststore and keystore in code

String importCert = " -import "+
    " -alias mysqlServerCACert "+
    " -file " + ssl_ca +
    " -keystore truststore "+
    " -trustcacerts " +
    " -storepass password -noprompt ";
String genKey = " -genkey -keyalg rsa " +
    " -alias mysqlClientCertificate -keystore keystore " +
    " -storepass password123 -keypass password " +
    " -dname CN=MS ";
sun.security.tools.keytool.Main.main(importCert.trim().split("\\s+"));
sun.security.tools.keytool.Main.main(genKey.trim().split("\\s+"));

# use the generated keystore and truststore


System.setProperty("javax.net.ssl.keyStore","path_to_keystore_file");
System.setProperty("javax.net.ssl.keyStorePassword","password");
System.setProperty("javax.net.ssl.trustStore","path_to_truststore_file");
System.setProperty("javax.net.ssl.trustStorePassword","password");

url = String.format("jdbc:mariadb://%s/%s?useSSL=true&trustServerCertificate=true", 'mydemoserver.mysql.database.chinacloudapi.cn', 'quickstartdb');
properties.setProperty("user", 'myadmin@mydemoserver');
properties.setProperty("password", 'yourpassword');
conn = DriverManager.getConnection(url, properties);

.NET (MySqlConnector)

var builder = new MySqlConnectionStringBuilder
{
    Server = "mydemoserver.mysql.database.chinacloudapi.cn",
    UserID = "myadmin@mydemoserver",
    Password = "yourpassword",
    Database = "quickstartdb",
    SslMode = MySqlSslMode.VerifyCA,
    SslCa = "DigiCertGlobalRootCA.crt.pem",
};
using (var connection = new MySqlConnection(builder.ConnectionString))
{
    connection.Open();
}

Node.js

var fs = require('fs');
var mysql = require('mysql');
const serverCa = [fs.readFileSync("/var/www/html/DigiCertGlobalRootCA.crt.pem", "utf8")];
var conn=mysql.createConnection({
    host:"mydemoserver.mysql.database.chinacloudapi.cn",
    user:"myadmin@mydemoserver",
    password:"yourpassword",
    database:"quickstartdb",
    port:3306,
    ssl: {
        rejectUnauthorized: true,
        ca: serverCa
    }
});
conn.connect(function(err) {
  if (err) throw err;
});

后续步骤

Connection libraries for Azure Database for MySQL(Azure Database for MySQL 的连接库)中查看各种应用程序连接性选项