跳转到主要内容

于 2025年04月22日 摘录自 Postfix SASL Howto

Postfix 如何使用 SASL 验证

SMTP 服务器需要确定 SMTP 客户端是否有权向远程目的地发送邮件,还是只能向服务器本身负责的目的地发送邮件。 通常,当客户端的 IP 地址与服务器的 IP 地址处于 "同一网络 "时,SMTP 服务器才会接受发往远程目的地的邮件。

SMTP 服务器网络外的 SMTP 客户端需要一种不同的方法来获得 "同一网络 "权限。 为满足这一需求,Postfix 支持 SASL 身份验证(RFC 4954,原RFC 2554)。 有了它,远程 SMTP 客户端可以向 Postfix SMTP 服务器进行身份验证,而 Postfix SMTP 客户端也可以向远程 SMTP 服务器进行身份验证。 一旦客户端通过验证,服务器就可以赋予其 "同一网络 "权限。

Postfix 本身并不实现 SASL,而是使用现有的实现作为构建模块。 这意味着某些与 SASL 相关的配置文件属于 Postfix,而其他配置文件则属于 Postfix 将使用的特定 SASL 实现。 本文档涵盖 Postfix 和非 Postfix 的配置。

注意:费力安装 Postfix 的用户可能会认为 Postfix 比其他邮件程序更安全。 Cyrus SASL 库包含大量代码。 有了它,Postfix 就能像其他使用 Cyrus SASL 库的邮件系统一样安全。 Dovecot 提供了一种值得考虑的替代方案。

您可以阅读以下主题的更多信息:

在 Postfix SMTP 服务器中配置 SASL 身份验证

如前所述,SASL 是与 Postfix 分开实现的。 因此,在 Postfix SMTP 服务器中配置 SASL 身份验证涉及两个不同的步骤:

  • 配置 SASL 实现,以提供适合 SASL 身份验证的机制列表;根据所用的 SASL 实现,配置身份验证后端,以便根据系统密码文件或其他数据库验证远程 SMTP 客户端的身份验证数据。
  • 配置 Postfix SMTP 服务器以启用 SASL 身份验证,并授权客户端转发邮件或控制客户端可使用的信封发件人地址。

要在 Postfix SMTP 服务器中成功进行身份验证,需要一个功能正常的 SASL 框架。 因此,在配置 Postfix 之前,首先应配置 SASL。

您可以阅读以下主题的更多信息:

支持哪些 SASL 实现?

目前,Postfix SMTP 服务器支持 Cyrus SASL 和 Dovecot SASL 实现。

注释

当前 Postfix 版本的插件架构可支持多种 SASL 实现。 在 Postfix 2.3 版之前,Postfix 只支持 Cyrus SASL。

要了解 Postfix 中编译了哪些 SASL 实现,请使用以下命令:

postconf -a
postconf -A

T这些命令仅适用于 Postfix 2.3 及更高版本。

配置 Dovecot SASL

Dovecot 是一个 POP/IMAP 服务器,它有自己的配置来验证 POP/IMAP 客户端。 Postfix SMTP 服务器使用 Dovecot SASL 时,会重复使用该配置的部分内容。 有关如何配置和操作 Dovecot 身份验证服务器,请查阅 Dovecot文档

Postfix 与 Dovecot SASL 之间的通信

Postfix SMTP 服务器与 Dovecot SASL 之间的通信通过 UNIX 域套接字或 TCP 套接字进行。 为了更好地保护隐私,我们将使用 UNIX 域套接字。

以下 Dovecot 版本 2 的片段假定 Postfix 队列位于/var/spool/postfix/ 目录下。

 1 conf.d/10-master.conf:
 2     service auth {
 3       ...
 4       unix_listener /var/spool/postfix/private/auth {
 5         mode = 0660
 6         # 假定使用 Postfix 默认用户和组
 7         user = postfix
 8         group = postfix        
 9       }
10       ...
11     }
12 
13 conf.d/10-auth.conf
14     auth_mechanisms = plain login

第 4 行将 Dovecot SASL 套接字放在/var/spool/postfix/private/auth 中,第 5-8 行将读写权限限制为仅限用户和postfix组,第 14 行为 Postfix SMTP 服务器提供普通登录机制。

继续阅读"在 Postfix SMTP 服务器中启用 SASL 身份验证和授权"一节,在 Postfix SMTP 服务器中开启并使用 SASL。

配置 Cyrus SASL

Cyrus SASL 框架支持多种应用程序(POP、IMAP、SMTP 等)。 不同的应用程序可能需要不同的配置。 因此,每个应用程序都可能有自己的配置文件。

配置 Cyrus SASL 的第一步是确定配置文件的名称和位置,描述 Postfix SMTP 服务器如何使用 SASL 框架。

Cyrus SASL 配置文件名称

配置文件名(默认:smtpd.conf)是可配置的。 它由 Postfix SMTP 服务器发送给 Cyrus SASL 库的值和 Cyrus SASL 添加的后缀.conf 组成。

Postfix 发送的值是将使用 Cyrus SASL 的服务器组件的名称。 默认为smtpd,并通过以下变量之一进行配置:

/etc/postfix/main.cf:
    # Postfix 2.3 and later
    smtpd_sasl_path = smtpd
    # Postfix < 2.3
    smtpd_sasl_application_name = smtpd

Cyrus SASL 配置文件位置

Cyrus SASL 搜索命名文件的位置取决于 Cyrus SASL 版本和使用的操作系统/发行版。

您可以阅读以下内容:

  • Cyrus SASL 2.x 版在/usr/lib/sasl2/ 中搜索配置文件。
  • 2.1.22 及更新版本的 Cyrus SASL 还会在/etc/sasl2/ 中搜索配置文件。
  • 在 Postfix 2.5 及更高版本中,可以通过cyrus_sasl_config_path配置参数明确配置搜索路径。 指定零个或多个以冒号分隔的目录。 如果设置为空(默认值),搜索路径就是编译到 Cyrus SASL 库中的路径。
  • 某些 Postfix 发行版会将cyrus_sasl_config_path的默认值设为非空,以便在/etc/postfix/sasl//var/lib/sasl2/等文件中查找 Cyrus SASL 配置文件。 请参阅postconf cyrus_sasl_config_path和/或特定发行版文档的输出结果,以确定预期位置。
  • 某些基于 Debian 的 Postfix 发行版会忽略"cyrus_sasl_config_ path"参数设置,并强制 Postfix 打开文件/etc/postfix/sasl/smtpd.conf

注意

Cyrus SASL 会首先搜索/usr/lib/sasl2/。 如果在那里找到指定的配置文件,就不会再检查其他位置。

Postfix 与 Cyrus SASL 的通信

由于 Postfix SMTP 服务器与 Cyrus SASL 库libsasl 相链接,因此 Postfix 与 Cyrus SASL 之间的通信是通过调用 SASL 库中的函数实现的。

SASL 库可以使用外部密码验证服务或内部插件连接到验证后端,并根据系统密码文件或其他数据库验证 SMTP 客户端的验证数据。

下表列出了本文讨论的典型组合:

authentication backendpassword verification service / plugin
/etc/shadowsaslauthd
PAMsaslauthd
IMAP serversaslauthd
sasldbsasldb
MySQL, PostgreSQL, SQLitesql
LDAPldapdb

注意事项

请阅读 Cyrus SASL 文档,了解可使用的其他后端。

saslauthd - Cyrus SASL 密码验证服务

Postfix SMTP 服务器(阅读:Cyrus SASL 的libsasl)与saslauthd服务器之间的通信通过 UNIX 域套接字进行。

saslauthd通常在/var/run/saslauthd/ 中建立 UNIX 域套接字,并等待身份验证请求。 Postfix SMTP 服务器必须拥有该目录的读取+执行权限,否则身份验证尝试将失败。

重要提示

某些发行版要求用户postfix必须是一个特殊组(如sasl)的成员,否则将无法访问saslauthdsocket 目录。

下面的示例配置 Cyrus SASL 库将saslauthd作为密码验证服务:

/etc/sasl2/smtpd.conf:
    pwcheck_method: saslauthd
    mech_list: PLAIN LOGIN

重要提示

使用saslauthd 时,请勿在mech_list中指定除PLAINLOGIN之外的其他机制! 它只能处理这两种机制,如果允许客户选择其他机制,身份验证就会失败。

重要事项

纯文本机制(PLAIN,LOGIN)发送的凭证未经加密。 该信息应受到额外安全层的保护,如 TLS 加密 SMTP 会话(参见:TLS_README)。

此外,还必须配置saslauthd服务器本身。 必须告诉它使用哪个身份验证后端来验证密码。 后端通过saslauthd命令行选项选择,并将在下面的示例中显示。

注意

有些发行版使用配置文件提供 saslauthd 命令行选项,以设置身份验证后端等。 典型的位置是/etc/sysconfig/saslauthd/etc/default/saslauthd

通过 /etc/shadow 使用 saslauthd

访问/etc/shadow系统密码文件需要root权限。 Postfix SMTP 服务器(以及链接到该服务器的libsasl)以尽可能小的权限运行。 如果不破坏 Postfix 的安全架构,直接访问/etc/shadow是不可能的。

saslauthd套接字搭建了一座安全桥梁。 以有限用户postfix 身份运行的Postfix 可以访问saslauthd接收命令的 UNIX 域套接字;以特权用户root 身份运行的saslauthd 拥有访问 shadow 文件所需的权限。

如果像这样启动,saslauthd服务器会根据身份验证后台/etc/shadow验证密码:

saslauthd -a shadow

有关测试说明,请参阅"测试 saslauthd 身份验证"一节。

将 saslauthd 与 PAM 结合使用

Cyrus SASL 可以使用 PAM 框架来验证凭证。 saslauthd在启动时使用 PAM 框架:

saslauthd -a pam

注意

Postfix SMTP 服务器的 PAM 配置通常在/etc/pam.d/smtp中给出,不在本文讨论范围之内。

有关测试说明,请参阅"测试 saslauthd 身份验证"部分。

在 IMAP 服务器上使用 saslauthd

saslauthd可以使用 SMTP 客户端凭据登录 IMAP 服务器,从而验证 SMTP 客户端凭据。 如果登录成功,SASL 身份验证也会成功。 这样启动时,saslauthd会联系 IMAP 服务器:

saslauthd -a rimap -O imap.example.com

注意

选项"-O imap.example.com"指定了saslauthd在验证凭证时应联系的 IMAP 服务器。

重要信息

saslauthd未加密发送 IMAP 登录信息。 离开本地主机的任何 IMAP 会话都应受到 SSL 通道等额外安全层的保护。

有关测试说明,请参阅"测试 saslauthd 身份验证"一节。

测试 saslauthd 身份验证

Cyrus SASL 提供了测试saslauthd身份验证的testsaslauthd工具。 用户名和密码作为命令行参数给出。 示例显示了身份验证成功后的响应:

testsaslauthd -u username -p password

注意事项

有时,testaslauthd程序不与 Cyrus SASL 主软件包一起发布。 在这种情况下,它可能与-devel-dev-debug软件包一起发布。

如果saslauthd被配置为联系 PAM 身份验证框架,请指定额外的"-s smtp";如果saslauthd在非默认位置建立 UNIX 域套接字,请指定额外的"-f/path/to/socketdir/mux"。

如果身份验证成功,请继续阅读"在 Postfix SMTP 服务器中启用 SASL 身份验证和授权"部分。

Cyrus SASL 插件 - 辅助属性插件

Cyrus SASL 使用插件基础设施(称为auxprop )来扩展libsasl 的功能。 目前,Cyrus SASL 源提供三种身份验证插件。

插件描述
sasldb账户存储在 Cyrus SASL Berkeley DB 数据库中
sql账户存储在 SQL 数据库中
ldapdb账户存储在 LDAP 数据库中

重要

这三个插件支持共享密码机制,即 CRAM-MD5、DIGEST-MD5 和 NTLM。 这些机制以加密方式发送凭证,但其验证过程要求密码以明文形式提供。 因此,密码不能(!)以加密形式存储。

sasldb 插件

sasldb auxprop 插件根据存储在 Berkeley DB 数据库中的凭证验证 SASL 客户端。 数据库模式是 Cyrus SASL 特有的。 数据库通常位于/etc/sasldb2 中。

注意

sasldb2文件包含明文密码,只有用户postfixpostfix所属组有读写权限。

saslpasswd2命令行实用程序创建并维护数据库:

% saslpasswd2 -c -u example.com username
Password:
Again (for verification):

该命令创建一个账户[email protected]

重要

用户必须指定[email protected]作为登录名,而不是用户名

运行以下命令,重新使用 Postfix的 mydomain参数值作为登录域:

% saslpasswd2 -c -u `postconf -h mydomain` username
Password:
Again (for verification):

注意

不带任何选项运行saslpasswd2,以获得如何使用该命令的进一步帮助。

sasldblistusers2命令会列出 sasldb 数据库中的所有现有用户:

% sasldblistusers2
[email protected]: password1
[email protected]: password2

按照以下说明配置 libsasl 以使用 sasldb:

/etc/sasl2/smtpd.conf:
    pwcheck_method: auxprop
    auxprop_plugin: sasldb
    mech_list: PLAIN LOGIN CRAM-MD5 DIGEST-MD5 NTLM

注意

在上述示例中,请将mech_list调整为适用于您的环境的机制。

sql 插件

sql auxprop 插件是一个通用的 SQL 插件。 它允许访问存储在 MySQL、PostgreSQL 或 SQLite 数据库中的凭证。 该插件要求 SASL 客户端密码以明文形式存储。

提示

如果必须存储加密密码,则不能使用 sql auxprop 插件。 请参阅"将 saslauthd 与 PAM 结合使用"部分,并配置 PAM 以使用pam_mysql模块等查找加密密码。 您将无法使用任何需要访问明文密码的方法,例如共享秘密方法 CRAM-MD5 和 DIGEST-MD5。

下面的示例将 libsasl 配置为使用 sql 插件,并将其连接到 PostgreSQL 服务器:

/etc/sasl2/smtpd.conf:
    pwcheck_method: auxprop
    auxprop_plugin: sql
    mech_list: PLAIN LOGIN CRAM-MD5 DIGEST-MD5 NTLM
    sql_engine: pgsql
    sql_hostnames: 127.0.0.1, 192.0.2.1
    sql_user: username
    sql_passwd: secret
    sql_database: dbname
    sql_select: SELECT password FROM users WHERE user = '%u@%r'

注意

如果smtpd.conf包含密码,请设置适当的权限。 postfix用户应能读取该文件。

注意

在上述示例中,请将mech_list调整为适用于您环境的机制。

sql 插件有以下配置选项:

sql_engine

指定mysql以连接 MySQL 服务器,指定pgsql以连接 PostgreSQL 服务器,指定sqlite以连接 SQLite 数据库

sql_hostnames

指定一个或多个服务器(主机名或主机名:端口),以逗号分隔。

注意

对于 MySQL 服务器,指定localhost可通过 UNIX 域套接字连接,指定127.0.0.1可通过 TCP 套接字连接。

sql_user

用于访问数据库的登录名。

sql_passwd

访问数据库的密码。

sql_database

要连接的数据库名称。

sql_select

从数据库表中获取明文密码的 SELECT 语句。

重要

语句不要用引号括起来! 使用单引号转义宏!

sql 插件提供用于构建sql_select语句的宏。 它们将被客户端发送的参数所取代。 可使用以下宏:

%u

正在选择属性的用户名称。

%p

所选属性的名称。 虽然从技术上讲这可以是任何名称,但 Cyrus SASL 会尝试使用 userPassword 和 cmusaslsecretMECHNAME(其中 MECHNAME 是 SASL 机制的名称)。

%r

用户所属域的名称。 这可以是 KERBEROS 领域、SASL 应用程序所在计算机的全称域名或用户名中"@"后面的域。

ldapdb 插件

ldapdb auxprop 插件可访问存储在 LDAP 服务器中的凭证。 该插件要求 SASL 客户端密码以明文形式存储。

提示

如果必须存储加密密码,则不能使用 ldapdb auxprop 插件。 取而代之的是使用"saslauthd -a ldap"直接查询 LDAP 数据库,并在saslauthd.conf 中进行适当配置,如此处所述。 您将无法使用任何需要访问明文密码的方法,如共享秘密方法 CRAM-MD5 和 DIGEST-MD5。

ldapdb 插件实现了代理授权。 这意味着,ldapdb 插件在向 LDAP 服务器询问远程 SMTP 客户端的密码之前,先使用自己的用户名和密码与 LDAP 服务器进行身份验证。 然后,LDAP 服务器决定是否授权 ldapdb 插件读取远程 SMTP 客户端的密码。

一言以蔽之: 配置 ldapdb 意味着身份验证和授权必须配置两次--一次是在 Postfix SMTP 服务器中,对远程 SMTP 客户端进行身份验证和授权;另一次是在 LDAP 服务器中,对 ldapdb 插件进行身份验证和授权。

本例将 libsasl 配置为使用 ldapdb 插件,并使用该插件连接 LDAP 服务器:

/etc/sasl2/smtpd.conf:
    pwcheck_method: auxprop
    auxprop_plugin: ldapdb
    mech_list: PLAIN LOGIN NTLM CRAM-MD5 DIGEST-MD5
    ldapdb_uri: ldap://localhost
    ldapdb_id: proxyuser
    ldapdb_pw: password
    ldapdb_mech: DIGEST-MD5

重要

如果smtpd.conf包含密码,请设置适当的权限。 postfix用户应能读取该文件。

注释

共享秘密机制(CRAM-MD5 等)要求 SASL 客户端密码以明文形式存储。

以下是适用的smtpd.conf文件条目的摘要:

auxprop_plugin

指定ldapdb以启用插件。

ldapdb_uri

指定ldapi://用于通过 UNIX 域套接字连接,指定ldap://用于未加密的 TCP 连接,或指定ldaps://用于加密的 TCP 连接。

ldapdb_id

用于验证 ldapdb 插件与 LDAP 服务器(代理授权)的登录名。

ldapdb_pw

用于验证 ldapdb 插件与 LDAP 服务器(代理授权)的密码(明文)。

ldapdb_mech

用于将 ldapdb 插件验证为 LDAP 服务器的机制。

注意

在此指定 LDAP 服务器支持的机制。

ldapdb_rc(可选)

包含 ldapdb LDAP 客户端(libldap)个别配置选项的文件路径。 这样就可以指定 TLS 客户证书,进而使用 SASL 外部机制。

注意事项

该机制支持通过加密传输层进行身份验证,如果插件必须连接到远程计算机上的 OpenLDAP 服务器,建议使用该机制。

ldapdb_starttls(可选)

连接到 LDAP 服务器的 TLS 策略。 可指定trydemand。 如果选项为try,插件将尝试与 LDAP 服务器建立 TLS 加密连接,如果 TLS 失败,将退回到未加密连接。 如果策略为demand,且无法建立 TLS 加密连接,则连接会立即失败。

当 ldapdb 插件连接到 OpenLDAP 服务器并成功通过身份验证时,OpenLDAP 服务器将决定插件用户是否有权读取 SASL 帐户信息。

以下配置举例说明了 OpenLDAP slapd 服务器中的授权配置:

/etc/openldap/slapd.conf:
    authz-regexp
    uid=(.*),cn=.*,cn=auth
    ldap:///dc=example,dc=com??sub?cn=$1
    authz-policy to

在这里,authz-regexp选项用于 ldapdb 用户的身份验证。 它将登录名映射到 LDAP 目录树中的一个 DN,slapd可在此查找 SASL 帐户信息。 authz-policy选项定义了身份验证策略。 在本例中,它将认证权限"授予 "ldapdb 插件。

最后一个配置步骤是告诉 OpenLDAPslapd服务器,ldapdb 可以在哪里搜索与邮件客户端给出的用户名相匹配的用户名。 下面的示例添加了一个附加属性 ldapdb 用户对象(此处为authzTo,因为 authz-policy 为"to"),并配置了登录名 "proxyuser "可搜索的范围:

dn: cn=proxyuser,dc=example,dc=com
changetype: modify
add: authzTo
authzTo: dn.regex:uniqueIdentifier=(.*),ou=people,dc=example,dc=com

使用ldapmodifyldapadd命令添加上述属性。

注意

请阅读《OpenLDAP 管理指南》中的 "使用 SASL "一章,了解在 OpenLDAP 中设置 SASL 身份验证的更详细说明。

在 Postfix SMTP 服务器中启用 SASL 验证和授权

Postfix SMTP 服务器默认使用 Cyrus SASL 实现。 如果要使用 Dovecot SASL 实现,请指定smtpd_sasl_type值为dovecot,而不是cyrus

/etc/postfix/main.cf:
    smtpd_sasl_type = dovecot

此外,还要指定 Postfix SMTP 服务器如何找到 Dovecot 验证服务器。 这取决于您在"Postfix 与 Dovecot 的 SASL 通信"一节中选择的设置。

  • 如果您为 UNIX 域套接字通信配置了 Dovecot,请按如下方式配置 Postfix:
  • /etc/postfix/main.cf:
        smtpd_sasl_path = private/auth
    
  • 注意

    本示例使用了相对于 Postfix 队列目录的路径名,因此无论 Postfix SMTP 服务器是否以 chrooted 方式运行,它都能正常工作。

  • 如果为 TCP 套接字通信配置了 Dovecot,则按如下方法配置 Postfix。 如果 Dovecot 运行在另一台机器上,请将 127.0.0.1 替换为该机器的 IP 地址。
  • /etc/postfix/main.cf:
        smtpd_sasl_path = inet:127.0.0.1:12345
    
  • 注意

    如果指定远程 IP 地址,信息将以明文形式通过网络发送。

  • 在 Postfix SMTP 服务器中启用 SASL 验证

  • 无论 SASL 的实现类型如何,在 Postfix SMTP 服务器中启用 SMTP 身份验证总是需要设置smtpd_sasl_auth_enable选项:
/etc/postfix/main.cf:
    smtpd_sasl_auth_enable = yes

在 "postfix 重载 "后,SMTP 客户端将在 SMTP 会话中看到附加功能 AUTH,然后是服务器支持的身份验证机制列表:

% telnet server.example.com 25
...
220 server.example.com ESMTP Postfix
EHLO client.example.com
250-server.example.com
250-PIPELINING
250-SIZE 10240000
250-AUTH DIGEST-MD5 PLAIN CRAM-MD5
...

不过,并非所有客户端都能识别 SASL 身份验证 RFC 所定义的 AUTH 功能。 一些历史实现希望服务器在 AUTH 动词和后面的机制列表之间发送一个"="作为分隔符。

broken_sasl_auth_clients配置选项可让Postfix以这些被破坏的客户端能理解的形式重复AUTH语句:

/etc/postfix/main.cf:
    broken_sasl_auth_clients = yes

注意事项

为 2003 版及以下的 Outlook 和 6 版以下的 Outlook Express 启用此选项。 该选项不会影响其他客户端。

在 "postfix 重新加载 "后,Postfix SMTP 服务器将传播两次 AUTH 功能,一次针对符合要求的客户端,一次针对损坏的客户端:

% telnet server.example.com 25
...
220 server.example.com ESMTP Postfix
EHLO client.example.com
250-server.example.com
250-PIPELINING
250-SIZE 10240000
250-AUTH DIGEST-MD5 PLAIN CRAM-MD5
250-AUTH=DIGEST-MD5 PLAIN CRAM-MD5
...

Postfix SMTP 服务器策略 - SASL 机制属性

Postfix SMTP 服务器支持根据 SASL 机制属性来限制其向客户端提供的 SASL 机制的策略。 下面两节将举例说明如何使用这些策略。

Property描述
noanonymous不要使用允许匿名身份验证的机制。
noplaintext不要使用传输未加密用户名和密码信息的机制。
nodictionary不要使用易受字典攻击的机制。
forward_secrecy要求会话之间保持前向保密(中断一个会话不会中断之前的会话)。
mutual_auth只使用客户端和服务器相互验证的机制。

未加密的 SMTP 会话

默认策略允许 Postfix SMTP 服务器中的任何机制,但基于匿名身份验证的机制除外:

/etc/postfix/main.cf:
    # Specify a list of properties separated by comma or whitespace
    smtpd_sasl_security_options = noanonymous

重要

至少要设置noanonymous选项。 否则,Postfix SMTP 服务器会向陌生人提供与正确认证的客户端相同的授权。

加密 SMTP 会话(TLS)

在 TLS 加密 SMTP 会话期间,有一个单独的参数控制 Postfix SASL 机制策略。 默认设置是复制未加密会话中的设置:

/etc/postfix/main.cf:
    smtpd_sasl_tls_security_options = $smtpd_sasl_security_options

更复杂的策略允许明文机制,但只能通过 TLS 加密连接:

/etc/postfix/main.cf:
    smtpd_sasl_security_options = noanonymous, noplaintext
    smtpd_sasl_tls_security_options = noanonymous

要在建立 TLS 加密会话后才提供 SASL 身份验证,请指定此项:

/etc/postfix/main.cf:
    smtpd_tls_auth_only = yes

在 Postfix SMTP 服务器中启用 SASL 授权

客户端通过 SASL 验证后,Postfix SMTP 服务器将决定远程 SMTP 客户端的授权内容。 可能的 SMTP 客户端授权示例包括

  • 向远程收件人发送邮件。
  • 在 MAIL FROM 命令中使用特定信封发件人。

默认情况下不启用这些权限。

邮件中继授权

通过permit_sasl_authenticated,Postfix SMTP 服务器可以允许通过 SASL 验证的 SMTP 客户端向远程目的地发送邮件。 示例

# 在 Postfix 2.10 及更高版本中,邮件中继策略
# 最好在 smtpd_relay_restrictions 下指定。
/etc/postfix/main.cf:
    smtpd_relay_restrictions =
        permit_mynetworks
        permit_sasl_authenticated
        reject_unauth_destination
    
# 旧版配置将中继控制和垃圾邮件控制合并在 smtpd_recipient_restrictions 下。 
# 要在 Postfix ≥ 2.10 中使用此示例,请指定"smtpd_relay_restrictions="。
# 
/etc/postfix/main.cf:
    smtpd_recipient_restrictions =
        permit_mynetworks
        permit_sasl_authenticated
        reject_unauth_destination
        ...其他规则...

信封发件人地址授权

默认情况下,SMTP 客户端可以在 MAIL FROM 命令中指定任何信封发件人地址。 这是因为 Postfix SMTP 服务器只知道远程 SMTP 客户端的主机名和 IP 地址,而不知道控制远程 SMTP 客户端的用户。

当 SMTP 客户端使用 SASL 身份验证时,情况就会发生变化。 现在,Postfix SMTP 服务器知道发件人是谁了。 Postfix SMTP 服务器可根据信封发件人地址表和 SASL 登录名,决定是否允许通过 SASL 验证的客户端使用某个信封发件人地址:

/etc/postfix/main.cf:
    smtpd_sender_login_maps = hash:/etc/postfix/controlled_envelope_senders
    smtpd_recipient_restrictions =
        ...
        reject_sender_login_mismatch
        permit_sasl_authenticated
        ...

受控信封发件人表指定了发件人信封地址与拥有该地址的 SASL 登录名之间的绑定:

/etc/postfix/controlled_envelope_senders
    # envelope sender           owners (SASL login names)
    [email protected]            [email protected]
    [email protected]        [email protected], [email protected]
    postmaster                  [email protected]
    @example.net                barney, fred, [email protected], [email protected]

这样,如果smtpd_sender_login_maps未指定 SMTP 客户端的登录名为 MAIL FROM 命令中发件人地址的所有者,则上述reject_sender_login_mismatch限制将拒绝该地址。

另请参阅reject_authenticated_sender_login_mismatch 、reject_known_sender_login_ mismatchreject_unauthenticated_sender_login_mismatch,了解对 SASL 登录名和信封发件人的其他控制。

其他 SMTP 服务器 SASL 选项

Postfix 提供多种 SASL 身份验证配置选项。 下一节列出了几个经常讨论的选项。 完整列表请参见postconf(5)

每个账户的访问控制

Postfix 可以根据 SASL 登录名实施策略(Postfix 2.11 及更高版本)。 通常情况下,这可用于扣留或拒绝来自证书已被泄露的账户的邮件。

/etc/postfix/main.cf:
    smtpd_recipient_restrictions = 
        permit_mynetworks 
        check_sasl_access hash:/etc/postfix/sasl_access
        permit_sasl_authenticated
        ...
/etc/postfix/sasl_access:
     # 当smtpd_sasl_local_domain为空时使用此值。
     username   HOLD
     # 当smtpd_sasl_local_domain=example.com 时使用此选项。
     [email protected] HOLD

默认验证域

Postfix 可以在没有域名部分的 SASL 登录名后附加域名(或任何其他字符串),例如用"john"代替"[email protected]":

/etc/postfix/main.cf:
    smtpd_sasl_local_domain = example.com

在所有 SMTP 客户端都配置为发送此类信息之前,作为默认设置和安全网,这对配置错误的客户端或迁移到需要验证 REALM 或域名的验证方法/后端非常有用。

向客户端或网络隐藏 SASL 身份验证

有些客户端坚持使用 SASL 身份验证(如果提供),即使它们未配置为发送凭据--因此它们总是会失败并断开连接。

Postfix 可以向这些客户端/网络隐藏 AUTH 功能:

/etc/postfix/main.cf:
    smtpd_sasl_exceptions_networks = !192.0.2.171/32, 192.0.2.0/24

在邮件标题中添加 SASL 登录名

要在 "收到:"邮件标题中报告 SASL 登录名(Postfix 2.3 及更高版本),请执行以下操作

/etc/postfix/main.cf:
    smtpd_sasl_authenticated_header = yes

注意事项

SASL 登录名将与全世界共享。

测试 Postfix SMTP 服务器的 SASL 验证

要测试服务器端,请连接(例如使用telnet)到 Postfix SMTP 服务器端口,您应该可以进行如下所示的对话。 客户端(即您)发送的信息以粗体显示。

% telnet server.example.com 25
...
220 server.example.com ESMTP Postfix
EHLO client.example.com
250-server.example.com
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-AUTH DIGEST-MD5 PLAIN CRAM-MD5
250 8BITMIME
AUTH PLAIN AHRlc3QAdGVzdHBhc3M=
235 Authentication successful

要通过使用 TLS 加密的连接进行测试,请使用openssl s_client代替telnet

% openssl s_client -connect server.example.com:25 -starttls smtp
...
220 server.example.com ESMTP Postfix
EHLO client.example.com
...see above example for more...

而不是AHRlc3QAdGVzdHBhc3M= ,指定\0username\0password的 base64 编码形式(\0 为空字节)。 上例中的用户名"test",密码为 "testpass"。

注意事项

在向公共列表发布 SASL 协商日志时,请注意用户名/密码信息很容易从 base64 编码形式中恢复。

您可以使用以下命令之一生成 base64 编码的身份验证信息:

  • 使用最新版本的bashshell:
  • % echo -ne '\000username\000password' | openssl base64
    

    其他一些 shell 也支持类似的语法。

  • 使用printf命令

    % printf '\0%s\0%s' 'username' 'password' | openssl base64
    % printf '\0%s\0%s' 'username' 'password' | mmencode
    

    mmencode命令是 metamail 软件的一部分。

  • 使用 PerlMIME::Base64(来自https://www.cpan.org/ ):

    % perl -MMIME::Base64 -e \
        'print encode_base64("\0username\0password");'
    

    如果用户名或密码包含"@",则必须指定"\@"。

  • 使用gen-auth脚本:

    % gen-auth plain
    username: username
    password:
    

    gen-authPerl 脚本由 John Jetmore 编写,可在https://jetmore.org/john/code/gen-auth 上找到。

在 Postfix SMTP/LMTP 客户端配置 SASL 身份验证

Postfix SMTP 和 LMTP 客户端可通过 Cyrus SASL 框架与远程 SMTP 服务器进行身份验证。 目前,Dovecot SASL 实现不提供客户端功能。

注意

本节中的示例仅讨论 SMTP 客户端。 用lmtp_替换smtp_,可获得相应的 LMTP 客户端配置。

您可以阅读以下主题的更多信息:

在 Postfix SMTP/LMTP 客户端启用 SASL 验证

本节介绍 Postfix SMTP 客户端通过需要 SASL 身份验证的邮件网关服务器发送所有邮件的典型情况。

解决问题提示:

为使示例更具可读性,我们分两部分进行介绍。 第一部分是基本配置,第二部分是用户名/密码信息的设置。

/etc/postfix/main.cf:
    smtp_sasl_auth_enable = yes
    smtp_tls_security_level = encrypt
    smtp_sasl_tls_security_options = noanonymous
    relayhost = [mail.isp.example]
    # 另一种形式:
    # relayhost = [mail.isp.example]:submission
    smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
  • smtp_sasl_auth_enable设置可启用客户端身份验证。 我们将在示例的第二部分配置客户端的用户名和密码信息。
  • smtp_tls_security_level设置确保与远程 smtp 服务器的连接是加密的,而smtp_sasl_tls_security_options则删除了对明文密码的禁止。
  • relayhost设置会强制 Postfix SMTP 将所有远程邮件发送到指定的邮件服务器,而不是尝试将邮件直接发送到目的地。
  • relayhost设置中,"["和"]"阻止 Postfix SMTP 客户端查找所附名称的 MX(邮件交换)记录。
  • relayhost目的地还可以指定一个非默认的 TCP 端口。 例如,[mail.isp.example]:submission的替代形式会告诉 Postfix 连接到 TCP 网络端口 587,该端口是为电子邮件客户端应用程序预留的。
  • Postfix SMTP 客户端兼容使用非标准"AUTH=method...."语法响应 EHLO 命令的 SMTP 服务器;这不需要额外的 Postfix 客户端配置。
  • 通过设置"smtp_tls_wrappermode= yes",Postfix SMTP 客户端支持 "wrappermode "协议,该协议使用 SMTP 服务器(Postfix 3.0 及更高版本)上的 TCP 端口 465。
  • 使用smtp_sasl_password_maps参数,我们可以配置 Postfix SMTP 客户端向邮件网关服务器发送用户名和密码信息。 正如下一节所述,Postfix SMTP 客户端支持多个 ISP 账户。 因此,用户名和密码存储在一个表中,该表包含每个邮件网关服务器的一个用户名/密码组合。
/etc/postfix/sasl_passwd:
    # destination                   credentials
    [mail.isp.example]              username:password
    # 另一种形式:
    # [mail.isp.example]:submission username:password

重要事项

将 SASL 客户端密码文件保留在/etc/postfix 中,并使该文件只对root可读+ 写入,以保护用户名/密码组合不被其他用户读取。 Postfix SMTP 客户端仍能读取 SASL 客户端密码。 在降低权限和进入可选的 chroot 监狱之前,它会以用户root的身份打开文件。

配置取决于发件人的 SASL 身份验证

Postfix 支持不同发件人地址使用不同的 ISP 账户(2.3 及更高版本)。 当一个人将同一台机器用于工作和个人用途时,或者当拥有不同 ISP 账户的人共享同一台 Postfix 服务器时,这就很有用了。

为了实现这一点,Postfix 支持每个发送方的 SASL 密码和每个发送方的中继主机。 在下面的示例中,Postfix SMTP 客户端将先按发件人地址搜索 SASL 密码文件,然后再按目的地搜索同一文件。 同样,Postfixtrivial-rewrite(8)守护进程也会搜索每个发件人的relayhost文件,最后才使用默认relayhost设置。

/etc/postfix/main.cf:
    smtp_sender_dependent_authentication = yes
    sender_dependent_relayhost_maps = hash:/etc/postfix/sender_relay
    smtp_sasl_auth_enable = yes
    smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
    relayhost = [mail.isp.example]
    # 另一种形式:
    # relayhost = [mail.isp.example]:submission
/etc/postfix/sasl_passwd:
    # 每个发送方认证;另请参阅 /etc/postfix/sender_relay。
    [email protected]               username1:password1
    [email protected]               username2:password2
    # 默认relayhost 的登录信息 .
    [mail.isp.example]              username:password
    # 另一种形式:
    # [mail.isp.example]:submission username:password
/etc/postfix/sender_relay:
    # 每个发件人提供者;另请参阅 /etc/postfix/sasl_passwd。
    [email protected]               [mail.example.com]:submission
    [email protected]               [mail.example.net]
  • 如果您有创意,可以尝试将两个表合并到一个 MySQL 数据库中,然后配置不同的 Postfix 查询来提取相应的信息。
  • 如果系统使用的是dbm文件而不是db文件,请指定dbm而不是hash。 要了解 Postfix 支持哪些查找表,请使用"postconf -m"命令。
  • 每当更改sasl_passwd 表时,执行"postmap /etc/postfix/sasl_passwd" 命令。
  • 每当更改sender_relay 表时,执行"postmap /etc/postfix/sender_relay" 命令。

Postfix SMTP/LMTP 客户端策略 - SASL 机制属性

与 Postfix SMTP 服务器一样,SMTP 客户端也有一个策略,根据 SASL 机制的属性来决定哪些 SASL 机制是可接受的。 下面两节将举例说明如何使用这些策略。

Property描述
noanonymous不要使用允许匿名身份验证的机制。
noplaintext不要使用传输未加密用户名和密码信息的机制。
nodictionary不要使用易受字典攻击的机制。
mutual_auth只使用客户端和服务器相互验证的机制。

未加密 SMTP 会话

默认策略比 Postfix SMTP 服务器的策略更严格--不允许使用明文机制(也不允许使用任何匿名机制):

/etc/postfix/main.cf:
    smtp_sasl_security_options = noplaintext, noanonymous

如果远程服务器只提供明文身份验证机制(SMTP 服务器宣布"AUTH PLAIN LOGIN"),这种不允许明文密码的默认策略会导致身份验证失败。 在这种情况下,SMTP 客户端将记录以下错误信息:

SASL authentication failure: No worthy mechs found

注意

/usr/lib/sasl2目录中未安装libplain.soliblogin.so模块时,也会出现同样的错误信息。

不安全的方法是降低安全标准,允许使用明文验证机制:

/etc/postfix/main.cf:
    smtp_sasl_security_options = noanonymous

更安全的方法是使用 TLS 会话加密来保护明文用户名和密码。 要了解远程 SMTP 服务器是否支持 TLS,请连接到服务器并查看它是否宣布支持 STARTTLS(如示例所示)。 客户端(即您)发送的信息以粗体显示。

% telnet server.example.com 25
...
220 server.example.com ESMTP Postfix
EHLO client.example.com
250-server.example.com
250-PIPELINING
250-SIZE 10240000
250-STARTTLS
...

请酌情指定端口 587(提交),而不是端口 25 (smtp)。

加密 SMTP 会话(TLS)

要在 Postfix SMTP 客户端中开启 TLS,请参阅TLS_README了解配置详情。

smtp_sasl_tls_security_options参数控制 Postfix SASL 机制在 TLS 加密 SMTP 会话期间的策略。 默认设置是复制未加密会话中的设置:

/etc/postfix/main.cf:
    smtp_sasl_tls_security_options = $smtp_sasl_security_options

更复杂的策略允许明文机制,但只能通过 TLS 加密连接:

/etc/postfix/main.cf:
    smtp_sasl_security_options = noanonymous, noplaintext
    smtp_sasl_tls_security_options = noanonymous

Postfix SMTP/LMTP 客户端策略 - SASL 机制名称

考虑到上一节中的 SASL 安全选项,Cyrus SASL 库将选择 SMTP 客户端和服务器都实施的最安全的身份验证机制。 不幸的是,这种身份验证机制可能会因为客户端或服务器未配置为使用该机制而失败。

为了避免这种情况,Postfix SMTP 客户端可以过滤远程 SMTP 服务器的身份验证机制名称。 如果使用得当,过滤器就能从 Cyrus SASL 库中隐藏不需要的机制,迫使该库从 Postfix SMTP 客户端过滤器通过的机制中进行选择。

下面的示例过滤掉了除PLAINLOGIN 机制之外的所有机制:

/etc/postfix/main.cf:
    smtp_sasl_mechanism_filter = plain, login

注意事项

如果远程服务器不提供过滤列表中的任何机制,则身份验证将失败。

在本节的最后,我们将举例说明除GSSAPILOGIN 之外的所有机制:

/etc/postfix/main.cf:
    smtp_sasl_mechanism_filter = !gssapi, !login, static:all

构建支持 SASL 的 Postfix

如前所述,Postfix 支持两种 SASL 实现: Cyrus SASL(SMTP 客户端和服务器)和 Dovecot SASL(仅 SMTP 服务器)。 这两种实现方式可同时内置到 Postfix 中。

构建 Dovecot SASL 支持

这些说明假定您按照INSTALL文档中的描述从源代码构建 Postfix。 如果您从特定供应商的源代码包中构建 Postfix,可能需要进行一些修改。

Postfix 2.3 及更高版本支持 Dovecot 第 1 版 SASL 协议。 在撰写本文时,只有服务器端的 SASL 支持可用,因此您不能用它来验证 Postfix SMTP 客户端与网络提供商服务器之间的身份。

Dovecot 使用自己的守护进程进行身份验证。 这使得 Postfix 的编译过程非常简单,因为不需要将额外的库链接到 Postfix 中。

要生成必要的 Makefile,请在 Postfix 顶层目录中执行以下命令:

% make tidy # 如果您有之前构建时遗留的文件
% make makefiles CCARGS="-DUSE_SASL_AUTH \
    -DDEF_SERVER_SASL_TYPE=\\\"dovecot\\\""

之后,按照INSTALL文件中的说明继续"make"。

注意事项

  • -DDEF_SERVER_SASL_TYPE=\\"dovecot\\"并不是必须的;它只是让 Postfix 的配置更方便一些,因为你不必在 Postfixmain.cf文件中指定 SASL 插件类型(但当你切换到以后的 Postfix 版本时,如果该版本使用的是默认的cyrus SASL 类型,这可能会引起意外)。
  • 如果还想支持 LDAP 或 TLS(或 Cyrus SASL),则需要将CCARGSAUXLIBS选项合并到上述命令行中;详情请参见LDAP_READMETLS_ README
  • % make tidy # 如果您有之前构建的遗留文件
    % make makefiles CCARGS="-DUSE_SASL_AUTH \
        -DDEF_SERVER_SASL_TYPE=\\\"dovecot\\\" \
        ...CCARGS options for LDAP or TLS etc...." \
       AUXLIBS="...AUXLIBS options for LDAP or TLS etc...."
    

构建 Cyrus SASL 支持

构建 Cyrus SASL 库

Postfix 使用 cyrus-sasl-1.5.x 或 cyrus-sasl-2.1.x,可从https://github.com/cyrusimap/cyrus-sasl/releases 获取。

重要事项

如果按默认方式安装 Cyrus SASL 库,则必须为 1.5.x 版创建一个符号链接/usr/lib/sasl->/usr/local/lib/sasl,或为 2.1.x 版创建一个符号链接/ usr/lib/ sasl2->/usr/local/lib/sasl2

据报道,Microsoft Outlook (Express) 需要使用非标准的 LOGIN 和/或 NTLM 身份验证机制。 要启用这些身份验证机制,请使用以下方法构建 Cyrus SASL 库:

% ./configure --enable-login --enable-ntlm

构建支持 Cyrus SASL 的 Postfix

这些说明假定您按照INSTALL文档中的描述从源代码构建 Postfix。 如果从特定供应商的源代码包中构建 Postfix,可能需要进行一些修改。

以下假设 Cyrus SASL 包含文件在/usr/local/include ,Cyrus SASL 库在/usr/local/lib 中。

在某些系统中,这会生成必要的Makefile定义:

Cyrus SASL 版本 2.1.x

% make tidy # 如果您有之前构建时遗留的文件
% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
    -I/usr/local/include/sasl" AUXLIBS="-L/usr/local/lib -lsasl2"

如果 Cyrus SASL 共享库位于运行时链接器不知道的目录中,请在"-lsasl2 "后添加"-Wl,-R,/path/to/directory "选项。

Cyrus SASL 1.5.x 版

% make tidy # 如果您有之前构建时遗留的文件
% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
    -I/usr/local/include" AUXLIBS="-L/usr/local/lib -lsasl"

在 Solaris 2.x 上,您需要指定运行时链接信息,否则 ld.so 运行时链接程序将找不到 SASL 共享库:

Cyrus SASL 版本 2.1.x

% make tidy # 删除先前构建的遗留文件
% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
    -I/usr/local/include/sasl" AUXLIBS="-L/usr/local/lib \
    -R/usr/local/lib -lsasl2"

Cyrus SASL 1.5.x 版

% make tidy # 如果您有之前构建时遗留的文件
% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
    -I/usr/local/include" AUXLIBS="-L/usr/local/lib \
    -R/usr/local/lib -lsasl"

使用 Cyrus SASL 1.5.x 版本

Postfix 支持 Cyrus SASL 1.x 版本,但除非迫不得已,否则不应使用它。 Cyrus SASL 的制造商写道:

该库已被弃用,应用程序应过渡到使用 SASLv2 库(来源:Project Cyrus: Downloads)。

如果您仍需要进行设置,这里有一个快速介绍:

请阅读有关 Cyrus SASL 框架的 SMTP 服务器配置的常规章节。 不同之处在于

  • Cyrus SASL 1.5.x 版仅在/usr/lib/sasl/目录中搜索配置(smtpd.conf)。 您必须将配置放在该目录下。 有些系统可能修改了 Cyrus SASL,把文件放到了/var/lib/sasl/ 等目录下。
  • 使用saslpasswd命令而不是saslpasswd2sasldb 中创建用户。
  • 使用sasldblistusers命令而不是sasldblistusers2sasldb 中查找用户。
  • smtpd.conf文件中,不能使用mech_list来限制所提供机制的范围。 取而代之的是,从/usr/lib/sasl/ 中移除它们的库(并记住在系统更新重新安装新版本时再次移除这些文件)。

荣誉