安全会议

默认情况下,连接器为TCP连接使用SSL/TLS创建一个新的会话。

Const mysqlx = require('@mysql/xdevapi');//使用连接字符串mysqlx. getsession ('mysqlx://localhost') .then(session => {console.log(session.inspect());// {host: 'localhost', tls: true}});//使用配置对象mysqlx。getSession({host: 'localhost'}) .then(session => {console.log(session.inspect());// {host: 'localhost', tls: true}});

如果服务器不支持安全的TCP连接,操作将失败。

Const mysqlx = require('@mysql/xdevapi');mysqlx. getsession ('mysqlx://localhost') .catch(err => {console.log(err.message);//将打印错误信息});

注意:SSL/TLS不用于本地Unix套接字。

禁用安全连接

用户可以很容易地显式禁用此功能(从而避免在使用不支持SSL/TLS连接的服务器时出现故障):

Const mysqlx = require('@mysql/xdevapi');mysqlx. getsession ('mysqlx://localhost?ssl-mode=DISABLED') .then(session => {console.log(session.inspect());// {host: 'localhost', tls: false}});//或使用简单的JavaScript配置对象const options = {host: 'localhost', tls: {enabled: false}};mysqlx.getSession(options) .then(session => {console.log(session.inspect());// {host: 'localhost', tls: false}});

额外的安全选项

为了获得额外的安全性,用户可以自定义设置并执行其他操作,例如提供一个手工选择的TLS协议版本列表,验证服务器证书已签名和/或未被给定的证书颁发机构撤销(每个证书都独立工作)。为了启用这个额外的安全步骤,应该提供到每个PEM文件(CA和CRL)的链接(证书链接和排序应该由用户事先完成)。所有这些选项都是可互换和解耦的,尽管在没有关联CA的情况下,CRL是没有用的。

TLS版本

可以定义一个精心挑选的允许TLS版本列表。或者,客户端将依赖于它所支持的默认版本列表,其中包括TLSv1TLSv1.1而且TLSv1.2而且TLSv1.3(取决于Node.js版本)。

Const mysqlx = require('@mysql/xdevapi');mysqlx. getsession ('mysqlx://localhost?tls-versions=[TLSv1.2,TLSv1.3]') .catch(err => {console.log(err.message);// {host: 'localhost', tls: true}});const options = {host: 'localhost', tls: {enabled: true, versions: ['TLSv1.2', 'TLSv1.3']}};mysqlx.getSession(options) .then(session => {console.log(session.inspect());// {host: 'localhost', tls: true}});

使用Node.js v10.0.0(或更高版本),其中TLS协商支持一系列版本,只要MySQL服务器支持列表中最老的TLS版本,连接就会成功。然而,在较旧的Node.js版本上,不支持范围协商,因为客户端在默认情况下从列表中获取最新的TLS版本,如果服务器不支持该特定版本,则连接将失败。

Const mysqlx = require('@mysql/xdevapi');//使用较旧的Node.js版本,如果服务器不支持TLSv1.2 mysqlx. getsession ('mysqlx://localhost?tls-versions=[TLSv1.1,TLSv1.2]') .catch(err => {console.log(err.message);// OpenSSL版本号错误});//对于Node.js >=v10.0.0,支持基于范围的协商,TLSv1.1将使用mysqlx. getsession ('mysqlx://localhost?tls-versions=[TLSv1.1,TLSv1.2]') .then(session => {console.log(session.inspect());// {host: 'localhost', tls: true}});

如果服务器支持的TLS的最老版本比客户端使用的版本新,那么无论使用的Node.js引擎版本是什么,套接字都将在协商期间挂起。

Const mysqlx = require('@mysql/xdevapi');//服务器只支持TLSv1.2或更高版本mysqlx. getsession ('mysqlx://localhost?tls-versions=[TLSv1,TLSv1.1]') .catch(err => {console.log(err.message);// TCP socket挂起});

TLSv1和TLSv1.1均不推荐使用。这意味着,当连接到不支持更高更安全的TLS版本的服务器时,或者当允许的TLS版本列表被限制为这些版本中的一个或两个版本时,客户机将报告deprecation警告消息。

当连接到支持TLSv1.1的旧服务器时,使用默认连接选项,如下所示. js脚本:

Const mysqlx = require('@mysql/xdevapi');mysqlx. getsession ('mysqlx://root@localhost') .then(session => {console.log('done');});

它将产生以下结果:

该连接使用TLSv1.1,现在已弃用,将在MySQL的未来版本中删除。升级时,请准备使用TLSv1.2或TLSv1.3。完成

当连接到只支持TLSv1的旧服务器时,脚本将产生以下结果:

该连接使用TLSv1,现在已弃用,将在MySQL的未来版本中删除。升级时,请准备使用TLSv1.2或TLSv1.3。完成

当连接到任何支持TLSv1.2或TLSv1.3的服务器时,也应该发生同样的情况,但允许的TLS版本列表被限制为一个或多个已弃用的版本。

mysqlx. getsession ('mysqlx://root@localhost?tls-versions=[TLSv1,TLSv1.1]') .then(session => {console.log('done');});

运行该脚本将得到以下结果:

该连接使用TLSv1.1,现在已弃用,将在MySQL的未来版本中删除。升级时,请准备使用TLSv1.2或TLSv1.3。完成

如果我们只将其限制为TLSv1,那么行为应该是相同的,但是消息将提到TLSv1。

mysqlx. getsession ('mysqlx://root@localhost?tls-versions=[TLSv1]') .then(session => {console.log('done');});

在这种情况下,脚本将产生以下结果:

该连接使用TLSv1,现在已弃用,将在MySQL的未来版本中删除。升级时,请准备使用TLSv1.2或TLSv1.3。完成

弃用消息被写入进程stderr流中作为“警告”事件,使用与核心Node.js引擎生成的弃用消息相同的基础结构。

在使用连接池时,只有当连接池创建新连接或重新创建一个同时过期的连接时,才会报告该消息。池重用的空闲连接不会报告弃用消息。

TLS密码套件

Connector/Node.js将以下默认密码套件列表传递给OpenSSL包,该包与可用的Node.js引擎静态链接:

tls_ecdhe_ecdsa_with_aes_256_gcm_sha256 tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_rsa_with_aes_256_gcm_sha384 tls_ecdhe_rsa_with_aes_256_gcm_sha256 tls_aes_128_gcm_sha256 tls_aes_128_cccm_sha256 tls_ecdhe_rsa_with_aes_256_gcm_sha256 tls_ecdhe_rsa_with_aes_256_gcm_sha384 tls_dhe_rsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_ecdsa_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_ecdhe_ecdsa_with_aes_256_gcm_sha384 tls_ecdhe_ecdsa_with_ecdhe_ecdsa_with_aes_256_gcm_sha3_chacha20_poly1305_sha256tls_ecdhe_rsa_with_chachha20_poly1305_sha256 tls_dh_dss_with_aes_128_gcm_sha256 tls_ecdh_ecdsa_with_aes_256_gcm_sha384 tls_ecdh_ecdsa_with_aes_256_gcm_sha256 tls_ecdh_ecdsa_with_aes_256_gcm_sha384 tls_ecdh_rsa_with_aes_256_gcm_sha384 tls_ecdh_rsa_with_aes_256_gcm_sha384 tls_ecdh_rsa_with_aes_256_gcm_sha384 tls_ecdh_rsa_with_aes_256_gcm_sha384 tls_dhe_rsa_with_aes_256_gcm_sha384 tls_dhe_rsa_with_aes_256_gcm_sha384 tls_dhe_rsa_with_aes_256_ccm_sha384 tls_dhe_rsa_with_aes_256_cbc_sha tls_dhe_rsa_with_aes_256_cbc_sha tls_rsa_with_aes_256_cbc_sha tls_rsa_with_aes_256_cbc_sha tls_rsa_with_aes_256_cbc_sha tls_rsa_with_aes_256_cbc_sha tls_rsa_with_aes_256_cbc_sha tls_rsa_with_aes_256_cbc_sha tls_rsa_with_aes_256_cbc_sha tls_rsa_with_aes_256_cbc_sha tls_rsa_with_aes_256_cbc_sha tls_rsa_with_aes_256_cbc_sha

列表中的最后三个密码套件已被弃用,它们的存在只是为了提供与基于WolfSSL/YaSSL的旧MySQL服务器版本的兼容性。

允许应用程序通过提供它们自己的密码套件集来覆盖这个列表,使用各自的IANA名称,如下所示:

Const mysqlx = require('@mysql/xdevapi');mysqlx. getsession ('mysqlx://localhost?tls-ciphersuites=[TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256]') .then(session => {console.log(session.inspect());// {host: 'foobar', tls: true}});const options = {host: 'localhost', tls: {ciphersuites: ['TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256'], enabled: true}};mysqlx.getSession(options) .then(session => {console.log(session.inspect());// {host: 'localhost', tls: true}});

应用程序可以自由使用较老的TLSv1和TLSv1.1兼容的密码套件(就像上面示例中描述的那样),但不建议使用这些。

非tls加密套件,包括MD5SSLv3和其他较旧的集合不受支持,如果应用程序想使用它们,它们将被忽略。如果客户端实际上不支持应用程序提供的任何一个密码,则会抛出一个错误。

证书颁发机构验证

Const mysqlx = require('@mysql/xdevapi');mysqlx. getsession ('mysqlx://localhost?ssl-ca=(/path/to/ca.pem)&ssl-crl=(/path/to/crl.pem)') .then(session => {console.log(session.inspect());// {host: 'localhost', tls: true}});Const options = {host: 'localhost', tls: {ca: '/path/to/ca。Pem ', crl: '/path/to/crl. Pem '。Pem ',启用:true}};mysqlx.getSession(options) .then(session => {console.log(session.inspect());// {host: 'localhost', tls: true}});

注意:文件路径可以是任意一种pct-encoded或未编码但用圆括号括起来(如示例中所示)。

身份验证机制

MySQL X插件目前支持以下认证方式:

  • MYSQL41(适用于任何类型的连接)
  • 平原(需要TLS)
  • SHA256_MEMORY(需要以前缓存的密码)

由于服务器连接在默认情况下是安全的,除非显式禁用TLS支持,否则连接将使用平原身份验证机制。如果通过本地UNIX套接字(尽管不是通过TLS)建立服务器连接,也会发生同样的情况。

另一方面,通过常规的未加密TCP链接建立的连接将尝试通过MYSQL41首先,如果这不起作用,SHA256_MEMORY然后将尝试身份验证,最后,如果这些都不起作用,客户端就会转发服务器错误。

SHA256_MEMORY只有当服务器在身份验证缓存中已经包含了帐户密码时,身份验证机制才会起作用。

允许用户覆盖这个自动选择,并退回到MYSQL41在安全连接上。此方法不适用于不安全的连接,因为平原认证机制需要TLS协议。关于与每个数据库用户帐户关联的客户机身份验证机制和服务器身份验证插件之间的兼容性,还需要考虑一些其他规则。

以下是主要兼容性规则的概述,这些规则不仅在服务器连接使用TLS或unix套接字(secure - S)或使用未加密的TCP通道(insecure - N)时发生变化,而且在服务器版本上也会发生变化。提供的示例适用于MySQL 8.0.11或更高版本。

mysql_native_password

mysql_native_password默认使用认证插件MySQL 5.7MySQL 8.0.11

身份验证机制 5.7(年代) 5.7 (N) 8.0.11 (S) 8.0.11 (N)
MYSQL41 好吧 好吧 好吧 好吧
平原 好吧 没有 好吧 没有
SHA256_MEMORY N/A N/A 好吧 好吧

MYSQL41总是有效的,然而平原只能在TLS上工作。SHA256_MEMORY要求以前缓存的密码(参见下面的示例)。

Const mysqlx = require('@mysql/xdevapi');mysqlx.getSession('root@localhost?auth=MYSQL41') .then(session => {console.log(session.inspect().auth);// 'MYSQL41'})getSession({auth: 'MYSQL41', tls: false, user: 'root'}) .then(session => {console.log(session.inspect().auth);// 'MYSQL41'}) mysqlx.getSession('root@localhost?ssl-mode=DISABLED') .then(session => {console.log(session.inspect().auth);// 'MYSQL41'})getSession({user: 'root'}) .then(session => {console.log(session.inspect().auth);// 'PLAIN'}) mysqlx.getSession('root@localhost?auth=PLAIN&ssl-mode=DISABLED') .catch(err => {console.log(err.message);// '用户名或密码无效'});

caching_sha2_password

caching_sha2_password引入了认证插件MySQL 8.0.11自那时起默认使用。它在较旧的服务器版本上不支持。

身份验证机制 5.7(年代) 5.7 (N) 8.0.11 (S) 8.0.11 (N)
MYSQL41 N/A N/A 没有 没有
平原 N/A N/A 好吧 没有
SHA256_MEMORY N/A N/A 好吧 好吧

要在服务器缓存中保存密码,首先,客户机必须使用平原TLS。任何其他身份验证设置都不能工作。

Const mysqlx = require('@mysql/xdevapi');mysqlx.getSession('root@localhost') .then(session => {console.log(session.inspect().auth);// 'PLAIN'返回mysqlx.getSession('root@localhost?auth=SHA256_MEMORY')}) .then(session => {console.log(session.inspect().auth);// ' sha256_memory '});mysqlx.getSession('root@localhost?ssl-mode=DISABLED') .catch(err => {console.log(err.message);// '使用' MYSQL41 '和' SHA256_MEMORY '验证失败,请检查用户名和密码或尝试安全连接。'});mysqlx.getSession('root@localhost?auth=MYSQL41') .catch(err => {console.log(err.message);// '用户名或密码无效'});