连接阶段

27 阅读11分钟
连接阶段

连接阶段执行以下任务:

  • 交换客户端和服务器的功能
  • 如果需要,设置SSL通信通道
  • 根据服务器验证客户端

客户端通过connect()连接到服务器,服务器可能会发送ERR数据包并完成握手,或者发送初始握手数据包,客户端会用握手响应数据包进行快速。此时,客户端可以请求SSL连接,在这种情况下,SSL通信通道会在客户端发送其身份验证响应建立。

笔记
如果服务器发送了ERR数据包作为第一个数据包,则该数据包将在客户端和服务器协商任何功能之前发生。因此,ERR 数据包将不包含 SQL 状态。

握手后,服务器会通知客户端进行身份验证的方法(除非在握手期间已经建立),并且身份验证交换将持续进行直到服务器通过发送OK\_Packet接受连接或使用ERR\_Packet拒绝连接。

握手

感谢服务器发送Protocol::Handshake数据包。此后,客户端可以选择使用

普通握手

  1. 服务器发送Protocol::Handshake
  2. 客户端使用Protocol::HandshakeResponse回复

SSL握手

  1. 服务器发送协议::握手
  2. 客户端回复Protocol::SSLRequest:
  3. 常规 SSL 交换导致建立 SSL连接
  4. 客户端发送Protocol::HandshakeResponse:

能力协商

为了允许旧客户端连接到较新的服务器,包含

MySQL 服务器版本服务器的功能标志

客户端应该只在Protocol::HandshakeResponse:中声明它与服务器共同拥有的功能。

他们可以就以下方面达成一致:使用状态标志、使用SQL状态作为错误代码、 身份验证方法、 <字体style="vertical-align: inherit;">SSL 支持、 压缩

确定身份验证方法

用于身份验证的方法与用户账户绑定,并存储在mysql.user表的插件列中。客户端在Protocol::HandshakeResponse:数据中告知其想要登录的用户账户。只有这样,才能找到mysql.user表并找到要使用的身份验证方法。

服务器使用其默认身份验证方法default\_auth\_plugin来生成身份验证数据有效负载,并将其与所用方法的名称一起发送到协议::握手内部客户端。

客户端可以在协议::握手响应:数据中包含对服务器发送的身份验证数据的回复。

当在Protocol::HandshakeResponse:中包含身份验证回复时,客户端无需使用服务器在协议::握手数据包中使用的身份验证方法。客户端使用的身份验证方法的名称存储在数据包中。如果客户端或服务器在初始化握手中使用的猜测身份验证方法不正确,服务器将使用Protocol::AuthSwitchRequest:通知客户端应使用哪种身份验证方法。有关更多详细信息,请参见“身份验证方法不匹配”部分。

直到MySQL 4.0版本,MySQL协议仅支持旧密码认证。在MySQL 4.1 原生认证如果客户端或服务器不支持可插入式身份验证(即未设置CLIENT\_PLUGIN\_AUTH功能标志),则使用的身份验证方法客户端和服务器功能继承,如下所示:如果未设置CLIENT\_PROTOCOL\_41CLIENT\_SECURE\_CONNECTION ,则使用旧密码身份验证。如果同时设置了CLIENT\_PROTOCOL\_41CLIENT\_SECURE\_CONNECTION,但未设置CLIENT\_PLUGIN\_AUTH,则使用

身份验证阶段快速路径

模拟客户端想要通过用户账户U登录,并且该用户帐户定义为使用身份验证方法server\_methodserver\_method用于生成协议::握手客户端使用的Protocol::HandshakeResponse:server\_method客户端使用协议::握手响应:server\_method与服务器使用的兼容。

在这种情况下,第一轮身份验证在握手过程中就已经开始了。现在,根据身份验证方法server\_method,可以进行进一步的身份交换,直到服务器接受或拒绝身份验证。

身份验证成功

成功的快速身份验证路径如下图:

  1. 客户端连接到服务器
  2. 服务器发送协议::握手
  3. 客户端使用协议::HandshakeResponse 进行响应:
  4. 客户端和服务器可能会尝试验证的用户帐户的服务器验证方法的要求交换进一步的数据包。
  5. 服务器以OK\_Packet响应

服务器在步骤4中发送的数据包是Protocol::AuthMoreData:数据包,其导出为0x01,以区别于ERR\_PacketOK\_Packet

笔记
许多身份验证方法(包括mysql\_native\_password方法)都包含一次质询响应交互。在这种情况下,步骤4中交换任何额外的数据包,并服务器在收到Protocol::HandshakeResponse:数据包后(假设身份验证成功)会直接发送

身份验证失败

它与身份验证重要性,但如果服务器决定不验证用户身份,它会使用ERR\_Packet而不是OK\_Packet进行回复。

  1. 客户端连接到服务器
  2. 服务器发送协议::握手
  3. 客户端使用Protocol::HandshakeResponse进行响应:
  4. 客户端和服务器可能会根据客户端尝试验证的用户账户的服务器验证方法的要求进一步交换数据包。
  5. 服务器以ERR\_Packet响应

同样,服务器在步骤4中发送的Protocol::AuthMoreData:数据包以0x01字节开头,因此永远不会与ERR\_Packet不一致。

身份验证方法不匹配

客户端以所需用户U为例的登录身份,并且该用户账户使用身份验证方法M。如果:

  1. 用于生成服务器协议::握手身份验证负载的默认方法与M或
  2. 客户端在Protocol::HandshakeResponse:中用于生成身份验证答复的方法与 M不兼容,则存在身份验证方法不匹配,必须使用正确的身份验证方法重新启动身份验证交换。
笔记
  1. 客户端和服务器在网关握手中使用了兼容的身份验证方法,但服务器使用的方法与用户所需的方法不同,也可能发生不匹配的情况。
  2. 在4.1-5.7服务和客户端中,默认的身份验证方法即使是本机身份验证
  3. 在8.0服务器和客户端中默认的身份验证方法是Caching\_sha2\_password信息
  4. 客户端和服务器可以通过该--default-auth选项更改其默认的身份验证方法。
  5. 对于客户端来说,一个明智的做法是查看协议::握手数据包中报表的服务器默认身份验证方法,并推断出身份验证方法,而不是在生成协议::HandshakeResponse:如果身份验证方法不匹配,会服务器向客户端发送Protocol::AuthSwitchRequest:消息,其中包含要使用的客户端身份验证方法的名称以及新方法生成的第一个身份验证负载。客户端应切换到请求的验证方法,并按照该方法的规定继续进行交换。

    如果客户端不知道请求的方法,应该断开连接。

    身份验证方法变更

    1. 客户端连接到服务器
    2. 服务器发送协议::握手
    3. 客户端使用Protocol::HandshakeResponse 进行响应:
    4. 服务器发送Protocol::AuthSwitchRequest:来告诉客户端需要切换到新的身份验证方法。
    5. 客户端和服务器可能会根据客户端尝试验证的用户帐户的服务器验证方法的要求进一步交换的数据包。
    6. 服务器OK\_Packet响应或以

    客户端功能不足

    如果服务器发现客户端有能力完成身份验证,会议室拒绝并返回ERR\_Packet 。以下情况可能会发生这种情况:

    在任何一种情况下,身份验证阶段都将如下所示:

    1. 客户端连接到服务器
    2. 服务器发送Protocol::Handshake
    3. 客户端使用Protocol::HandshakeResponse 进行响应:
    4. 服务器识别出客户端没有足够的能力来处理所需的身份验证方法,发送ERR\_Packet并关闭连接。

    客户端不知道新的身份验证方法

    即使客户端支持外部身份验证(设置了)CLIENT\_PLUGIN\_AUTH 标志),Protocol::AuthSwitchRequest:中指定的新身份验证方法也可能不被客户端识别。在这种情况下,客户端会直接断开连接。

    1. 客户端连接到服务器
    2. 服务器发送协议::握手
    3. 客户端使用Protocol::HandshakeResponse进行响应:
    4. 服务器发送Protocol::AuthSwitchRequest:来告诉客户端需要切换到新的身份验证方法。
    5. 客户端发现它不知道服务器请求的身份验证方法 - 它断开连接。

    非CLIENT\_PLUGIN\_AUTH客户端

    笔记
    这只能发生在8.0之前的服务器上。8.0已删除旧密码验证只有在满足以下条件时,服务器才会向未设置CLIENT\_PLUGIN\_AUTH标志的客户端请求更改身份验证方法:

    1. 客户端对旧密码验证
    2. 客户端支持安全认证(设置了CLIENT\_SECURE\_CONNECTION)
    3. 服务器默认的身份验证方法是在这种情况下,服务器发送Protocol::OldAuthSwitchRequest:此数据包不包含新的身份验证方法名称,因为它被隐式提出机身份验证,并且不包含身份验证数据。客户端回复Protocol::HandshakeResponse320。要生成密码哈希,客户端应该重复使用服务器在

COM\_CHANGE\_USER 命令后的身份验证

命令阶段,客户端可以发送 COM\_CHANGE\_USER 命令,该命令将通过完整的身份验证握手触发对新帐户的身份验证。

连接阶段类似,服务器可能会以OK\_Packet响应(用于常规快速路径),或者以ERR\_PacketOK\_Packet响应(用于常规快速路径),或者以Protocol::AuthSwitchRequest:响应(其中包含新账户要使用的身份验证方法最终以及客户端将使用的第一个身份验证数据有效负载)。后续握手过程将常进行,具体过程由新账户的身份验证方法定义。,服务器将OK\_Packet响应接受新账户,ERR\_Packet响应拒绝更改并断开连接。

  1. 客户端发送COM\_CHANGE\_USER数据包
  2. 服务器以协议::AuthSwitchRequest:进行响应,使用正确的身份验证方法启动身份验证握手
  3. 客户端和服务器根据新账户的身份验证方法的要求交换进一步的数据包
  4. 服务器以OK\_Packet进行响应并返回命令阶段或ERR\_Packet并关闭连接。

COM\_CHANGE\_USER和非CLIENT\_PLUGIN\_AUTH客户端

不支持可插入式身份验证的客户端可以向使用原生身份验证旧密码身份验证账户输入COM\_CHANGE\_USER命令。在这种情况下,服务器会预设已发送身份验证质询(即客户端首次连接时发送的质询),并且客户端质询的回复(即新密码的哈希值)应在auth\_responseCOM\_CHANGE\_USER 字段中发送。

  1. 客户端发送携带身份验证响应(密码哈希值)的COM\_CHANGE\_USER数据包,用于本机身份验证(4.1版本之后的客户端)或旧密码身份验证(4.1版本之前的客户端)方法。
  2. OK\_Packet进行响应并返回到命令阶段或以ERR\_Packet进行响应并关闭连接。

与正常连接一样,不支持可插入式身份验证的4.1后客户端也有可能连接到使用旧密码身份验证的帐号,在这种情况下,服务器将发送协议::OldAuthSwitchRequest:并希望客户端使用Protocol::HandshakeResponse320回复

  1. 客户端发送COM\_CHANGE\_USER数据包,其中包含对本机身份验证的响应
  2. 服务器回复协议::OldAuthSwitchRequest:(0xFE字节)
  3. 再次客户端发送响应,这次采用旧密码认证所需的格式
  4. 服务器以OK\_Packet响应并返回命令阶段ERR\_Packet
参见
group\_cs\_capabilities\_flags
unknown\_accounts连接阶段数据包 身份验证方法 多主体身份验证
继承;">多主体身份验证 继承;">多主体身份验证