连接到具有加密连接 Azure Database for MySQL - 灵活服务器

适用于:Azure Database for MySQL - 灵活服务器

Azure Database for MySQL 灵活服务器支持使用安全套接字层 (SSL) 和传输层安全性 (TLS) 加密将客户端应用程序连接到 Azure Database for MySQL 灵活服务器实例。 TLS 是一种行业标准协议,可确保在数据库服务器与客户端应用程序之间实现加密的网络连接,使你能够满足合规性要求。

默认情况下,Azure Database for MySQL 灵活服务器支持使用传输层安全性 (TLS 1.2) 的加密连接,并且会拒绝所有使用 TLS 1.0 和 TLS 1.1 的传入连接。 你的灵活服务器上的加密连接强制要求或 TLS 版本配置可以按照本文中的说明进行更改。

下面是适用于 Azure Database for MySQL 灵活服务器实例的 SSL 和 TLS 设置的不同配置:

场景 服务器参数设置 说明
禁用 SSL 强制要求 require_secure_transport 设置为 OFF 如果旧版应用程序不支持与 Azure Database for MySQL 灵活服务器建立加密连接,则可以通过将 require_secure_transport 设置为 OFF,来禁用与 Azure Database for MySQL 灵活服务器实例建立加密连接的强制要求。
强制使用 SSL 和低于 TLS 版本 1.2 的版本 require_secure_transport 设置为 ON,且 tls_version 设置为 TLS 1.0 或 TLS 1.1 如果旧版应用程序支持加密连接,但需要低于 TLS 版本 1.2 的版本,你可以启用加密连接,但将 Azure Database for MySQL 灵活服务器实例配置为允许连接使用应用程序支持的 TLS 版本(v1.0 或 v1.1)。 仅在 Azure Database for MySQL 灵活服务器版本 v5.7 中受支持
强制使用 SSL 和 TLS 版本 1.2(默认配置) require_secure_transport 设置为 ON,且 tls_version 设置为 TLS 1.2 这是为 Azure Database for MySQL 灵活服务器建议的配置,同时也是默认配置。
强制使用 SSL 和 TLS 版本 1.3 require_secure_transport 设置为 ON,且 tls_version 设置为 TLS 1.3 这是为新应用程序开发建议的有用配置。 仅在 Azure Database for MySQL 灵活服务器版本 v8.0 中受支持

注意

  • 不支持对 Azure Database for MySQL 灵活服务器上的 SSL 密码进行更改。 将 tls_version 设置为 TLS 版本 1.2 时,默认强制使用 FIPS 密码套件。 对于版本 1.2 以外的其他 TLS 版本,SSL 密码将设为 MySQL 社区安装附带的默认设置。
  • 自 MySQL 版本 8.0.26 和 5.7.35 后的 MySQL 开源社区版本,TLS 1.0 和 TLS 1.1 协议已弃用。 这些协议分别发布于 1996 年和 2006 年,用于加密动态数据,现在被认为脆弱、过时且容易受到安全威胁。 有关详细信息,请参阅取消对 TLS 1.0 和 TLS 1.1 协议的支持。 社区停止对该协议的支持时,Azure Database for MySQL 灵活服务器也停止支持 TLS 版本,以满足新式安全标准。

在本文中,学习如何:

  • 配置 Azure Database for MySQL 灵活服务器实例
    • 禁用 SSL
    • 强制使用 SSL 和 TLS 版本
  • 使用 mysql 命令行连接到 Azure Database for MySQL 灵活服务器实例
    • 禁用加密连接
    • 启用加密连接
  • 验证连接的加密状态
  • 使用各种应用程序框架连接到具有加密连接的 Azure Database for MySQL 灵活服务器实例

在 Azure Database for MySQL 灵活服务器实例上禁用 SSL 强制

如果客户端应用程序不支持加密连接,则需要在 Azure Database for MySQL 灵活服务器实例上禁用加密连接强制。 若要禁用加密连接强制要求,需要将 require_secure_transport 服务器参数设置为“OFF”(如屏幕截图所示),并保存服务器参数配置,以使其生效。 require_secure_transport 是一个动态服务器参数,它会立即生效,无需重启服务器。

Screenshot showing how to disable SSL with Azure Database for MySQL flexible server.

在禁用 SSL 的情况下使用 mysql 命令行客户端进行连接

以下示例演示如何使用 mysql 命令行界面连接到服务器。 使用 --ssl-mode=DISABLED 连接字符串设置来禁用来自 mysql 客户端的 TLS/SSL 连接。 将值替换为实际的服务器名称和密码。

 mysql.exe -h mydemoserver.mysql.database.chinacloudapi.cn -u myadmin -p --ssl-mode=DISABLED 

重要

将 require_secure_transport 设置为 OFF 并不意味着服务器端不支持加密连接。 如果在 Azure Database for MySQL 灵活服务器实例上将 require_secure_transport 设置为 OFF,则在客户端连接到加密连接时,它仍将被接受。 使用 mysql 客户端连接到配置为 require_secure_transport=OFF 的 Azure Database for MySQL 灵活服务器实例这一操作也将成功,如下所示。

 mysql.exe -h mydemoserver.mysql.database.chinacloudapi.cn -u myadmin -p --ssl-mode=REQUIRED
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 17
Server version: 5.7.29-log MySQL Community Server (GPL)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show global variables like '%require_secure_transport%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| require_secure_transport | OFF |
+--------------------------+-------+
1 row in set (0.02 sec)

总之,require_secure_transport=OFF 设置会放宽与 Azure Database for MySQL 灵活服务器建立加密连接的强制要求,除了加密连接之外,还允许从客户端到服务器的未加密连接。

强制使用 SSL 和 TLS 版本

若要在 Azure Database for MySQL 灵活服务器实例上设置 TLS 版本,需要设置 *tls_version- 服务器参数。 TLS 协议的默认设置是 TLS 1.2。 如果应用程序支持使用 SSL 连接到 MySQL 服务器,但需要使用除 TLS 1.2 以外的任意协议,则需要在服务器参数中设置 TLS 版本。 *tls_version- 是静态服务器参数,需要重启服务器才能使该参数生效。 以下是 Azure Database for MySQL 灵活服务器的可用版本所支持的协议。

Azure Database for MySQL 灵活服务器版本 支持的 tls_version 值 默认设置
MySQL 5.7 TLS 1.0、TLS 1.1、TLS 1.2 TLS 1.2
MySQL 8.0 TLS 1.2、TLS 1.3 TLS 1.2

使用 mysql 命令行客户端通过 TLS/SSL 进行连接

下载公共 SSL 证书

若要对客户端应用程序使用加密连接,需要下载公共 SSL 证书,该证书也在 Azure 门户“网络”窗格中提供,如以下屏幕截图中所示。

Screenshot showing how to download public SSL certificate from Azure portal.

将证书文件保存到首选位置。 例如,本教程在本地环境或托管应用程序的客户端环境中使用 c:\ssl\var\www\html\bin。 这允许应用程序通过 SSL 安全连接到数据库。

如果使用“专用访问(VNet 集成)”创建了 Azure Database for MySQL 灵活服务器实例,需要从与服务器相同的 VNet 中的资源连接到服务器。 可以创建虚拟机并将其添加到使用 Azure Database for MySQL 灵活服务器实例创建的 VNet 中。

如果使用“公共访问(允许的 IP 地址)”创建了 Azure Database for MySQL 灵活服务器实例,可以将本地 IP 地址添加到服务器上的防火墙规则列表中

可以选择 mysql.exeMySQL Workbench,以从本地环境连接到服务器。

以下示例演示如何使用 mysql 命令行界面连接到服务器。 使用 --ssl-mode=REQUIRED 连接字符串设置强制实施 TLS/SSL 证书验证。 将本地证书文件路径传递给 --ssl-ca 参数。 将值替换为实际的服务器名称和密码。

sudo apt-get install mysql-client
wget --no-check-certificate https://dl.cacerts.digicert.com/DigiCertGlobalRootCA.crt.pem
mysql -h mydemoserver.mysql.database.chinacloudapi.cn -u mydemouser -p --ssl-mode=REQUIRED --ssl-ca=DigiCertGlobalRootCA.crt.pem

注意

确认传递给 --ssl-ca 的值与你保存的证书的文件路径匹配。 如果要使用 SSL 连接到 Azure Database for MySQL - 灵活,并通过一个选项使用证书主体名称执行完整验证 (sslmode=VERTIFY_IDENTITY),请在连接字符串中使用 <servername>.mysql.database.chinacloudapi.cn。

如果你尝试以未加密的连接方式连接到你的服务器,将会出现错误,指示禁止使用不安全传输的连接,类似于以下内容:

ERROR 3159 (HY000): Connections using insecure transport are prohibited while --require_secure_transport=ON.

验证 TLS/SSL 连接

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

mysql> status

查看输出,确认连接是否已加密,如果已加密,输出应显示为:“SSL: 使用的密码为”。 此密码套件显示了一个示例。你可能会看到不同的密码套件,具体取决于客户端。

如何标识服务器上配置的 TLS 协议?

你可以运行命令 SHOW GLOBAL VARIABLES LIKE 'tls_version';然后查看该值以了解所有协议的配置。

mysql> SHOW GLOBAL VARIABLES LIKE 'tls_version';

如何查找客户端正在使用哪个 TLS 协议连接到服务器?

你可以运行以下命令并查看会话的 tls_version 以确定用于连接的 TLS 版本。

SELECT sbt.variable_value AS tls_version,  t2.variable_value AS cipher,
processlist_user AS user, processlist_host AS host
FROM performance_schema.status_by_thread  AS sbt
JOIN performance_schema.threads AS t ON t.thread_id = sbt.thread_id
JOIN performance_schema.status_by_thread AS t2 ON t2.thread_id = t.thread_id
WHERE sbt.variable_name = 'Ssl_version' and t2.variable_name = 'Ssl_cipher' ORDER BY tls_version;

使用各种应用程序框架连接到具有加密连接的 Azure Database for MySQL 灵活服务器实例

在 Azure 门户中,你的服务器的“连接字符串”页面中预定义了连接字符串。该字符串中包含以通用语言使用 TLS/SSL 连接到数据库服务器所需的参数。 TLS/SSL 参数因连接器而异。 例如,“useSSL=true”、“sslmode=required”或“ssl_verify_cert=true”以及其他变体。

若要从应用程序通过 TLS/SSL 与 Azure Database for MySQL 灵活服务器实例建立加密连接,请参阅以下代码示例:

WordPress

下载 SSL 公共证书,在 wp-config.php 中的 // **MySQL settings - You can get this info from your web host** // 行之后添加以下几行。

//** Connect with SSL ** //
define('MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_SSL);
//** SSL CERT **//
define('MYSQL_SSL_CERT','/FULLPATH/on-client/to/DigiCertGlobalRootCA.crt.pem');

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', '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', 'myadmin', 'yourpassword', $options);

Python (MySQLConnector Python)

try:
    conn = mysql.connector.connect(user='myadmin',
                                   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',
                       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',
        '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',
        :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' , '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');
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');
properties.setProperty("password", 'yourpassword');
conn = DriverManager.getConnection(url, properties);

.NET (MySqlConnector)

var builder = new MySqlConnectionStringBuilder
{
    Server = "mydemoserver.mysql.database.chinacloudapi.cn",
    UserID = "myadmin",
    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",
    password:"yourpassword",
    database:"quickstartdb",
    port:3306,
    ssl: {
        rejectUnauthorized: true,
        ca: serverCa
    }
});
conn.connect(function(err) {
  if (err) throw err;
});

后续步骤