Skip to main content

6.2 客户端命令 - 未认证状态 (Client Commands - Not Authenticated State)

在未认证状态下,AUTHENTICATE 或 LOGIN 命令建立认证并进入已认证状态。AUTHENTICATE 命令为各种认证技术、隐私保护和完整性检查提供了通用机制,而 LOGIN 命令使用传统的用户名和明文密码对,并且没有建立隐私保护或完整性检查的方法。

STARTTLS 命令是建立会话隐私保护和完整性检查的替代形式,但它本身不建立认证或进入已认证状态。

服务器实现可以 (MAY) 允许在不建立认证的情况下访问某些邮箱。这可以通过 [ANONYMOUS] 中描述的 ANONYMOUS [SASL] 认证器来完成。一个较旧的约定是使用用户名 "anonymous" 的 LOGIN 命令;在这种情况下,虽然服务器可以选择接受任何密码,但需要密码。对匿名用户施加的限制取决于实现。

一旦认证 (包括作为匿名),就不可能重新进入未认证状态。

除了通用命令 (CAPABILITY、NOOP 和 LOGOUT) 之外,以下命令在未认证状态下有效:STARTTLS、AUTHENTICATE 和 LOGIN。有关这些命令的重要信息,请参阅安全注意事项 (第 11 节)。

6.2.1 STARTTLS 命令

参数 (Arguments):

响应 (Responses): 此命令没有特定响应

结果 (Result):

  • OK - starttls 完成,开始 TLS 协商
  • NO - 由于服务器配置错误,无法启动 TLS 协商
  • BAD - 在成功的 TLS 协商后收到 STARTTLS 或参数无效

请注意,STARTTLS 命令仅在明文端口上可用。当在隐式 TLS 端口上收到 STARTTLS 命令时,服务器必须 (MUST) 始终以标记的 BAD 响应进行响应。

TLS [TLS-1.3] 协商在来自服务器的标记 OK 响应末尾的 CRLF 之后立即开始。一旦客户端发出 STARTTLS 命令,在看到服务器响应并且 TLS 协商完成之前,它不得 (MUST NOT) 发出进一步的命令。一些过去的服务器实现错误地实现了 STARTTLS 处理,并且已知包含 STARTTLS 明文命令注入漏洞 [CERT-555316]。为了避免此漏洞,如果在启动 STARTTLS 命令的 CRLF 之后在同一 TCP 缓冲区中接收到任何数据,服务器实现必须 (MUST) 执行以下操作之一:

  1. 将来自 TCP 缓冲区的额外数据解释为 TLS 握手的开始。(如果数据是明文,这将导致 TLS 握手失败。)

  2. 丢弃来自 TCP 缓冲区的额外数据。

请注意,第一个选项对于将 STARTTLS 命令的开始与 TLS 握手数据进行流水线处理的客户端更友好。

成功的 TLS 协商后,即使在 TLS 协商期间提供了客户端凭据,服务器也保持在未认证状态。这并不排除诸如 EXTERNAL (在 [SASL] 中定义) 之类的认证机制使用由 TLS 协商确定的客户端身份。

一旦 TLS 已启动,客户端必须 (MUST) 丢弃有关服务器功能的缓存信息,并且应该 (SHOULD) 重新发出 CAPABILITY 命令。这对于防止在 STARTTLS 之前更改功能列表的主动攻击是必要的。服务器可以 (MAY) 通告不同的功能,特别是在成功的 STARTTLS 命令之后不应该 (SHOULD NOT) 通告 STARTTLS 功能。

示例:

C: a001 CAPABILITY
S: * CAPABILITY IMAP4rev2 STARTTLS LOGINDISABLED
S: a001 OK CAPABILITY completed
C: a002 STARTTLS
S: a002 OK Begin TLS negotiation now
<TLS 协商,后续命令在 TLS 层下>
C: a003 CAPABILITY
S: * CAPABILITY IMAP4rev2 AUTH=PLAIN
S: a003 OK CAPABILITY completed
C: a004 AUTHENTICATE PLAIN dGVzdAB0ZXN0AHRlc3Q=
S: a004 OK Success (tls protection)

6.2.2 AUTHENTICATE 命令

参数 (Arguments):

  • SASL 认证机制名称
  • 可选的初始响应

响应 (Responses): 可以请求继续数据

结果 (Result):

  • OK - 认证完成,现在处于已认证状态
  • NO - 认证失败:不支持的认证机制,凭据被拒绝
  • BAD - 命令未知或参数无效,认证交换已取消

AUTHENTICATE 命令向服务器指示 [SASL] 认证机制。如果服务器支持请求的认证机制,它将执行认证协议交换以认证和识别客户端。它还可以 (MAY) 为后续协议交互协商可选的安全层。如果不支持请求的认证机制,服务器应该 (SHOULD) 通过发送标记的 NO 响应来拒绝 AUTHENTICATE 命令。

AUTHENTICATE 命令支持 [SASL] 第 4 节中定义的可选"初始响应"功能。客户端不需要使用它。如果 SASL 机制支持"初始响应",但客户端未指定,则服务器按照 [SASL] 第 3 节中的规定处理它。

此协议的 [SASL] 配置文件指定的服务名称是 "imap"。

认证协议交换由一系列服务器质询和客户端响应组成,这些质询和响应特定于认证机制。服务器质询由命令继续请求响应组成,其中 "+" 令牌后跟 base64 编码 (参见 [RFC4648] 第 4 节) 的字符串。客户端响应由包含 base64 编码字符串的单行组成。如果客户端希望取消认证交换,它会发出由单个 "*" 组成的行。如果服务器接收到此类响应,或者如果它接收到无效的 base64 字符串 (例如,base64 字母表之外的字符或非终端 "="),则必须 (MUST) 通过发送标记的 BAD 响应来拒绝 AUTHENTICATE 命令。

与任何其他客户端响应一样,初始响应必须 (MUST) 编码为 base64。它还必须 (MUST) 在引用字符串或字面量之外传输。要发送零长度初始响应,客户端必须 (MUST) 发送单个填充字符 ("=")。这表示响应存在,但它是零长度字符串。

在解码初始响应中的 base64 数据时,解码错误必须 (MUST) 像在任何正常的 SASL 客户端响应中一样处理,即使用标记的 BAD 响应。特别是,服务器应该检查 base64 字母表未明确允许的任何字符,以及包含填充字符 ('=') 的任何 base64 字符序列,该字符出现在字符串末尾以外的任何位置 (例如,"=AAA" 和 "AAA=BBB" 是不允许的)。

如果客户端对不支持初始响应的 SASL 机制使用初始响应,则服务器必须 (MUST) 使用标记的 BAD 响应拒绝该命令。

如果通过 [SASL] 认证交换协商安全层,则对于客户端,它在结束认证交换的 CRLF 之后立即生效,对于服务器,它在标记的 OK 响应的 CRLF 之后立即生效。

虽然客户端和服务器实现必须 (MUST) 实现 AUTHENTICATE 命令本身,但除了 [PLAIN] 中描述的 PLAIN 机制之外,不需要实现任何认证机制。此外,认证机制不需要支持任何安全层。

注意:服务器实现必须 (MUST) 实现一种配置,在该配置中,除非已协商 STARTTLS 命令、在隐式 TLS 端口上协商了 TLS,或者已提供某些其他保护会话免受密码窃听的机制,否则不允许任何明文密码机制。服务器站点不应该 (SHOULD NOT) 使用任何允许明文密码机制而没有针对密码窃听的此类保护机制的配置。客户端和服务器实现应该 (SHOULD) 实现不使用明文密码的其他 [SASL] 机制,例如 [RFC4752] 中描述的 GSSAPI 机制、SCRAM-SHA-256/SCRAM-SHA-256-PLUS [SCRAM-SHA-256] 机制,和/或用于相互 TLS 认证的 EXTERNAL [SASL] 机制。(请注意,SASL 框架允许创建支持双因素认证 (2FA) 的 SASL 机制;但是,没有一个完全准备好被本文档推荐。)

服务器和客户端可以支持多种认证机制。服务器应该 (SHOULD) 在 CAPABILITY 命令的响应中列出其支持的认证机制,以便客户端知道要使用哪些认证机制。

服务器可以 (MAY) 在成功的 AUTHENTICATE 命令的标记 OK 响应中包含 CAPABILITY 响应代码,以便自动发送功能。如果客户端识别这些自动功能,则无需发送单独的 CAPABILITY 命令。仅当 AUTHENTICATE 命令未协商安全层时才应执行此操作,因为作为 AUTHENTICATE 命令一部分的标记 OK 响应不受加密/完整性检查的保护。[SASL] 要求客户端在这种情况下重新发出 CAPABILITY 命令。服务器可以 (MAY) 在成功的 AUTHENTICATE 命令后通告不同的功能。

如果 AUTHENTICATE 命令失败并返回 NO 响应,则客户端可以 (MAY) 通过发出另一个 AUTHENTICATE 命令来尝试另一种认证机制。它还可以 (MAY) 尝试使用 LOGIN 命令进行认证 (有关更多详细信息,请参阅第 6.2.3 节)。换句话说,客户端可以 (MAY) 按优先级递减的顺序请求认证类型,将 LOGIN 命令作为最后的手段。

在认证交换期间从客户端传递到服务器的授权身份由服务器解释为客户端请求其特权的用户名。

示例:

S: * OK [CAPABILITY IMAP4rev2 STARTTLS AUTH=GSSAPI] Capabilities
C: A001 AUTHENTICATE GSSAPI
S: +
C: YIIB+wYJKoZIhvcSAQICAQBuggHqMIIB5qADAgEFoQMCAQ6iBwMFACAAAACjggEmYYIBIjCCAR6gAwIBBaESGxB1Lndhc2hpbmd0b24uZWR1oi0wK6ADAgEDoSQwIhsEaW1hcBsac2hpdmFtcy5jYWMud2FzaGluZ3Rvbi5lZHWjgdMwgdCgAwIBAaEDAgEDooHDBIHAcS1GSa5b+fXnPZNmXB9SjL8Ollj2SKyb+3S0iXMljen/jNkpJXAleKTz6BQPzj8duz8EtoOuNfKgweViyn/9B9bccy1uuAE2HI0yC/PHXNNU9ZrBziJ8Lm0tTNc98kUpjXnHZhsMcz5Mx2GR6dGknbI0iaGcRerMUsWOuBmKKKRmVMMdR9T3EZdpqsBd7jZCNMWotjhivd5zovQlFqQ2Wjc2+y46vKP/iXxWIuQJuDiisyXF0Y8+5GTpALpHDc1/pIGmMIGjoAMCAQGigZsEgZg2on5mSuxoDHEA1w9bcW9nFdFxDKpdrQhVGVRDIzcCMCTzvUboqb5KjY1NJKJsfjRQiBYBdENKfzK+g5DlV8nrw81uOcP8NOQCLR5XkoMHC0Dr/80ziQzbNqhxO6652Npft0LQwJvenwDI13YxpwOdMXzkWZN/XrEqOWp6GCgXTBvCyLWLlWnbaUkZdEYbKHBPjd8t/1x5Yg==
S: + YGgGCSqGSIb3EgECAgIAb1kwV6ADAgEFoQMCAQ+iSzBJoAMCAQGiQgRAtHTEuOP2BXb9sBYFR4SJlDZxmg39IxmRBOhXRKdDA0uHTCOT9Bq3OsUTXUlk0CsFLoa8j+gvGDlgHuqzWHPSQg==
C:
S: + YDMGCSqGSIb3EgECAgIBAAD/////6jcyG4GE3KkTzBeBiVHeceP2CWY0SR0fAQAgAAQEBAQ=
C: YDMGCSqGSIb3EgECAgIBAAD/////3LQBHXTpFfZgrejpLlLImPwkhbfa2QteAQAgAG1yYwE=
S: A001 OK GSSAPI authentication successful

以下示例演示了初始响应的使用。

示例:

S: * OK [CAPABILITY IMAP4rev2 STARTTLS AUTH=GSSAPI LOGINDISABLED] Server ready
C: A01 STARTTLS
S: A01 OK STARTTLS completed
<TLS 协商,后续命令在 TLS 层下>
C: A02 CAPABILITY
S: * CAPABILITY IMAP4rev2 AUTH=GSSAPI AUTH=PLAIN
S: A02 OK CAPABILITY completed
C: A03 AUTHENTICATE PLAIN dGVzdAB0ZXN0AHRlc3Q=
S: A03 OK Success (tls protection)

请注意,由于初始响应是可选的,因此以下协商 (不使用初始响应) 仍然有效,并且服务器必须 (MUST) 支持:

... 客户端连接到服务器并协商 TLS 保护层 ...
C: C01 CAPABILITY
S: * CAPABILITY IMAP4rev2 AUTH=PLAIN
S: C01 OK Completed
C: A01 AUTHENTICATE PLAIN
S: +
C: dGVzdAB0ZXN0AHRlc3Q=
S: A01 OK Success (tls protection)

请注意,在上面的示例中,来自服务器的 "+" 后面有一个空格。

以下是在 TLS 保护层下使用 SASL EXTERNAL 机制 (在 [SASL] 中定义) 进行认证的示例,并使用空初始响应:

... 客户端连接到服务器并协商 TLS 保护层 ...
C: C01 CAPABILITY
S: * CAPABILITY IMAP4rev2 AUTH=PLAIN AUTH=EXTERNAL
S: C01 OK Completed
C: A01 AUTHENTICATE EXTERNAL =
S: A01 OK Success (tls protection)

注意:为了编辑清晰,服务器质询和客户端响应中的换行符不在真实的认证器中。

6.2.3 LOGIN 命令

参数 (Arguments):

  • 用户名
  • 密码

响应 (Responses): 此命令没有特定响应

结果 (Result):

  • OK - 登录完成,现在处于已认证状态
  • NO - 登录失败:用户名或密码被拒绝
  • BAD - 命令未知或参数无效

LOGIN 命令向服务器标识客户端,并携带认证此用户的明文密码。除非作为最后的手段 (在尝试使用 AUTHENTICATE 命令一次或多次认证失败后),否则不应该 (SHOULD NOT) 使用 LOGIN 命令,建议客户端实现具有禁用 LOGIN 命令的任何自动使用的方法。

服务器可以 (MAY) 在成功的 LOGIN 命令的标记 OK 响应中包含 CAPABILITY 响应代码,以便自动发送功能。如果客户端识别这些自动功能,则无需发送单独的 CAPABILITY 命令。

示例:

C: a001 LOGIN SMITH SESAME
S: a001 OK LOGIN completed

注意:在不安全的网络 (如 Internet) 上使用 LOGIN 命令存在安全风险,因为监控网络流量的任何人都可以获得明文密码。因此,客户端不得 (MUST NOT) 在不安全的网络上使用 LOGIN。

除非客户端在隐式 TLS 端口 [RFC8314] 上访问 IMAP 服务、已协商 STARTTLS 命令,或者已提供某些其他保护会话免受密码窃听的机制,否则服务器实现必须 (MUST) 实现一种配置,在该配置中,它通告 LOGINDISABLED 功能并且不允许 LOGIN 命令。服务器站点不应该 (SHOULD NOT) 使用任何允许 LOGIN 命令而没有针对密码窃听的此类保护机制的配置。如果通告了 LOGINDISABLED 功能,则客户端实现不得 (MUST NOT) 发送 LOGIN 命令。