我有一个 Postfix/Dovecot 设置并使用 OpenLDAP 作为用户/密码后端。由于虚拟主机,用户必须使用其完全合格的电子邮件地址作为用户名登录,因此域部分对于身份验证是必需的,即用户名如下所示<local-part>@<fqdn-domain>
。
然而,不断有攻击试图使用不带域部分的用户名进行身份验证。由于这会导致 LDAP 查询中的 DN 无效,我的日志中充满了大量由于 LDAP DN 无效而产生的错误消息。
是否有任何配置选项允许 Dovecot 对提供的用户名强制执行一些初始语法检查,如果检查失败,Dovecot 会通过立即拒绝响应来简化身份验证过程,而不是查询 LDAP 服务器然后失败?
Dovecot 中的 LDAP 配置是
uris = ldapi://%2frun%2fopenldap%2fslapd.sock
auth_bind = yes
auth_bind_userdn = uid=%n,ou=users,o=%d,dc=my-host,dc=my-domain,dc=my-tld
base = ou=users,o=%d,dc=server,dc=my-host,dc=my-domain,dc=my-tld
如您所见,我的 LDAP 设置使用所谓的“连接点”为不同的托管域在 DIT 中提供不同的子分支。(o=%d
DN 中的 -part。)根据Dovecot 配置手册 - 用户变量,%d
如果用户名在 之后没有域部分,则为空@
。
当攻击者尝试使用不完整的用户名进行身份验证时,这会导致我的日志中出现多余的错误消息,例如
Dec 26 16:25:54 server dovecot[24946]: auth: Error: ldap(root,187.205.80.184): ldap_bind() failed: Invalid DN syntax
这里来自 187.205.80.184 的攻击者尝试以用户身份进行身份验证root
,而 Dovecot 尝试查找,uid=root,ou=users,o=,dc=my-host,dc=my-domain,dc=my-tld
这显然是无效的,因为后面没有任何内容o=
。
答案1
从 Dovecot v2.2.33 开始,你可以使用以下方式设置默认域条件语句:
%{if;%d;eq;;example.com;%d}
这是:
if
使用条件语句%d
值 1比较eq
操作员:字符串相等- 空的值 2为了比较
example.com
如果条件为true
;则结果值为%d
空字符串(默认)%d
如果条件为false
; 则结果值%d
设置为 (非空)
您可以在 LDAP 配置中使用它,而不是%d
:
uris = ldapi://%2frun%2fopenldap%2fslapd.sock
auth_bind = yes
auth_bind_userdn = uid=%n,ou=users,o=%{if;%d;eq;;example.com;%d},dc=example,dc=com
base = ou=users,o=%{if;%d;eq;;example.com;%d},dc=example,dc=com
答案2
我自己找到了另一种解决方案,它不需要变量中的条件,因此也适用于较旧的 Dovecot 版本。在 -variable 的特定情况下,%d
以下配置指令可以解决问题
auth_realms = <vhosted-dom-1> <vhosted-dom-2> ... <vhosted-domain-n>
auth_default_realm = nowhere.notld
第一行是受支持的身份验证领域的空格分隔列表。根据客户端选择的 SASL 身份验证方法,这会通知客户端现有的身份验证领域。当然,这并不能阻止(愚蠢的)脚本攻击者仍然使用没有域部分的用户名。但是,正确设置该配置是一种好的做法。
第二行定义了默认领域(或我这里所说的域),如果客户端未能提供,Dovecot 会自动添加该领域。这里我将其设置为虚构的名称nowhere.notld
。该值实际上并不重要,它应该与任何实际域不同。
最后说明:当然,这不会阻止有关身份验证尝试失败的日志消息。但这没关系。但是,它可以防止由于无效 DN 而导致 LDAP 出现致命错误。相反,Dovevot 会发出有关身份验证失败的适当警告。