Chinaunix首页 | 论坛 | 博客
  • 博客访问: 579911
  • 博文数量: 142
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 1835
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-10 14:30
个人简介

工作中~

文章分类

全部博文(142)

文章存档

2009年(25)

2008年(117)

我的朋友

分类:

2008-10-22 10:54:46

Postfix SASL身份验证

———  《postfix权威指南》学习笔记   lxq007

基本的smtp协议没有验证用户身份的能力。虽然信封上的寄件人地址已经隐含了发信者的身份,然而,
由于信封地址实在太容易假造,所以不能当成身份凭据。为了判断客户端是否有权使用转发服务(relay),服务器端必须确认客户端(寄件人)是否当真是对方所自称的那个人。在不能以寄件人地址为身份证书的前提下,smtp势必需要其他补充机制,才能验证客户端的身份。

从postfix的角度看,它需要扮演两种角色:当它身为smtp server时,需要能够验证用户个人的身份(让他们能使用smtp server寄出邮件);当它身为smtp client时,它需要能够提供出自己的身份证书给其他mta检验(以便通过远程mta将邮件递送到最终目的地)。

大多数邮件系统只容许内部网络上的客户端使用转发服务,换言之,ip地址成了客户端身份的识别凭据。然而,并非所有合法用户都具有固定ip地址。比方说,带着笔记本电脑出差远方的同事,他们可能使用领近isp或饭店旅馆提供的临时性ip地址;或者,有些在家工作的用户,他们位于办公室之外的网络,但是需要透过办公室里的邮件系统来寄信。不管你是否能够事先知道用户的ip地址,sasl都能提供可靠的身份验证。

RFC 2554 “smtp service extension for authentication”制定了如何在基本smtp协议上增加验证功能的机制,此机制使得smtp能使用sasl协议来验证客户端身份。   


一、sasl概论
设定sasl时,你必须决定两件事;一是用于交换“标识信 息”(或称身份证书)的验证机制authentication mechanism);一是决定标识信息存储方法的验证架构(authentication framework)。SASL验证机制规范client与server之间的应答过程以及传输内容的编码法,sasl验证架构决定服务器本身如何存储客户端的身份证书以及如何核验客户端提供的密码。


1 选择适当的验证机制

Cyrus sasl支持多种验证机制,至于要使用哪一种验证机制,客户端与服务器双方必须事先取得共识。以下是一些比较常见的机制;

PLAIN
    PLAIN是最简单的机制,但同时也是最危险的机制,因为身份证书(登录名称与密码)是以base64字符串格式通过网络,没有任何加密保护措施。使用PLAIN机制时,最好结合TLS

LOGIN
    LOGIN不是其正式支持的机制,但某些旧版的MUA使用这种机制,所以Cyrus SASL让你可选择其是否支持LOGIN机制。如果你的用户仍在使用这类老掉牙的MUA,你必须在编译SASL函数库时,指定要包含LOGIN的支持。LOGIN的证书交换过程类似PLAIN

OPT
    OPT是一种使用“单次密码”的验证机制。此机制不提供任何加密保护,因为没必要————每个密码都只能使用一次,每次联机都要改用新密码。SMTP client必须能够产生OPT证书。

DIGEST-MD5
    使用这种机制时,client与server共享同一个隐性密码(seceret password),而且此密码不通过网络传输。验证过程是从服务器先提出challenge(质询)开始,客户端使用此challenge与隐性密码计算出一个response(应答)。不同的challenge,不可能计算出相同的response;任何拥有secret password的一方,都可以用相同的challenge算出相同的response。因此,服务器只要比较客户端返回的response是否与自己算出的response相同,就可以知道客户端所拥有的密码是否正确。由于真正的密码并没有通过网络,所以不怕网络监测。

KERBEROS
    Kerberos是一种网络型验证协议。除非你的网络已经使用Kerberos,否则你应该用不到kerberos机制;相对的,如果你的网络已经架设了kerberos验证中心,SASL就能完美的将smtp验证整合进现有的体系。

ANONYMOUS
   
ANONYMOUS机制对smtp没有意义,因为smtp验证的用意在于限制转发服务的使用对象,而不是为了形成open relay,sasl之所以提供这种机制,主要是为了支持其他协议。


当客户端链接到一个支持sasl的邮件服务器时,服务器会以优先级列出可用的机制供客户端选择。如果客户端也支持多钟机制,则当第一种机制验证失败时,客户端可能会继续尝试第二种机制,直到通过验证或是所有机制都失败为止。如果双方在一开始就无法协调出共同的机制,验证过程就算失败。

一旦双方在使用哪种机制上达成共识,就开始进行验证过程。实际的交互过程随机制而定,但通常包含一次或多次应答过程。验证协议本身也规定了应答内容的编码格式。


2 选择适当的验证架构

SASL验证架构(SASL authentication framework)可以使用现有的unix系统密码(如/etc/passwd、/etc/shadow或PAM),也可用smtp用户专用密码文件。如果你的网路上kerberos之类的中间控制式验证构架,也可以使用。

哪一种验证架构最适合你,取决于你的服务器从何、如何取得证书信息。举例来说,如果smtp与pop/imap的所有用户的证书数据都是储存在系统密码文件(/etc/passwd或/etc/shadow),并通过pam来验证,那么sasl就应该透过pam来取得证书数据。另一方面,如果所有smtp user都只有虚账户,你或许应该将证书数据存放在专用的数据库,并设定sasl与POP/IMAP server从该数据库取得证书数据。


二、Postfix 的 SASL配置

1 设定验证架构

对于每个使用cyrus sasl函数库的应用系统,cyrus sasl各提供一个独立的配置文件。影响postfix的sasl配置文件是smtpd.conf。通常位于 /usr/local/lib/sasl2/smtpd.conf。


unix系统密码

通常,让sasl直接使用现有的系统密码来验证用户身份是最方便的。传统的系统密码文件应该是/etc/passwd,但是讲究安全性的现代系统则比较可能使用/etc/shadow、pam或诸如此类的证书数据库。由于这类密码文件只有特权进程才能访问,而postfix却被刻意设计成避开特权身份,所 以postfix不能直接访问系统密码文件。

cyrus函数库对于这个问题的解决办法,是提供一个特殊的验证服务器程序,称为saslauthd,它能够代替postfix来取得密码数据。saslauthd daemon本身需要特权身份,不过,由于它是一个独立于postfix之外的进程,而且通常不必于外界进行网络通信,所以安全性的危害已经被降到最低。 如果你打算让sasl使用unix系统密码,你必须启动cyrus sasl包随附的saslauthd daemon。请注意,使用saslauthd来访问unix系统密码,表示你只能使用明文密码,因为asalauthd需要实际密码才能进行核验。

要让sasl知道postfix将通过saslauthd daemon来访问证书数据库,你必须将下列内容加入smtpd.conf配置文件:
pwcheck_method:  saslauthd

cyrus sasl包随附的saslauthd应该会被安装在$PATH环境变量所列的某个目录下。你必须先在后台启动saslauthd daemon,postfix才能使用它来验证客户端。当你启动saslauthd时,你必须使用-a选项指定密码系统的类型最常见的类型包括pam、 shadow或getpwent(用语传统的/etc/psswd)。举例来说,在一个使用pam的系统上,你应该使用下列命令来启动saslauthd daemon:
      # saslauthd -a pam


sasl专用密码

如果你不想使用系统密码来验证smtp client,你刻意另外建一个无关系统密码的独立账户数据库。当你的postfix系统纯粹用于提供寄信服务,而不用于接收外来邮件,用户也不用登录服务器系统本身时,使用sasl密码可能是个好主意。请将下列内容加入你的smtpd.conf配置文件:
       pwcheck_method: auxprop

在cyrus的术语中,auxprop的意义是auxiliary property plug-ins(辅助性的专属外挂模块),其作用是使用外部程序来进行验证。默认的辅助外挂模块是sasldb(这也是cyrus sasl包随附的程序之一),它应该能满足postfix的所有需求。关键字auxprop只是要求使用外部的sasl密码文件。

使用sasl密码时,不需要用到saslauthd daemon,但是你必须将所有的smtp client账户与密码存放在一个专用的外部密码文件中。sasl默认使用的密码文件是/etc/sasldb2。postfix smtp server至少要具备能读取此文件的权限;如果你使用cyrus sasl的auto_transition功能,则postfix将需要能够写此文件的权限;如果你用不到auto_transition功能,最好不要将写权限开放给postfix。

2 设定Postfix

所有与sasl密码验证相关的postfix参数,全部都是以smtpd_sasl*(关于smtp server的参数)或smtp_sasl*(关于smtp client的参数)为前缀。对于服务器端的配置,你至少需要设定smtpd_sasl_auth_enable参数,并且将permit_sasl_authenticated限制条件列在某一个smtpd_*_restriction的过滤规则里。

2.1 启用sasl验证

smtpd_sasl_auth_enable参数决定Postfix SMTP server是否支持SASL验证:
      smtpd_sasl_auth_enable = yes

依照规范说明书的标准规定,当smtp client送出ehlo命令之后,smt server应该要列出其验证机制支持列表,而且此列表是出现在关键字AUTH与一个空格之后,例如:

不过,有些mua却收到auth与一个等号:
  250-AUTH=PLAIN LOGIN DIGEST-MD5 CRAM-MD5

postfix容许你接受这种不遵守规定的行为:
       broken_sasl_auth_clients = yes

设定此参数之后,postfix会分别以标准与非标准两种格式来列出它所支持的smtp验证机制,例如:

由于两种格式都出现在smtp server的响应中,所以既不会影响标准的mua,同时又能让那些不标准的mua使用smtp sasl验证。

2.2 避免寄件人冒名

当客户端通过postfix寄信时,要如何确定客户端使用的真实的寄件人地址?比方说,某人以A身份通过smtp验证,但是却以B为发信人地址,要如何避免这种冒名情况?postfix容许你设定寄件地址与sasl登录身份的对应关系。举例来说,假设某人的邮件地址是kdent@example.com,其sasl登录身份为kdent,如果你希望kdent只能以该地址的名义来发邮件,而不能使用其他寄件地址,你应该将下列对应关系定义在一个查询表中:
       kdent@example.com                  kdent

这是一个普通的postfix查询表,你可以逐一列出每一个地址与每一位sasl用户的对应关系,也可以使用正则表达式来表示邮件地址的人名部分或网域部分。制作好查询表之后,请将main.cf的smtpd_sender_login_maps参数指向此表:
       smtpd_sender_login_maps = hash:/etc/postfxi/sasl_senders

下一步是将reject_sender_login_mismatch限制条件纳入某个smtpd_*_restrictions过滤规则组合里,这样一 来,如果kdent通过sasl验证,但是他却试图以mary@example.com的名义寄出邮件,那么postfix将拒绝帮他寄信。

2.3 核准授权用户
如果你的ube过滤规则里包含了smtpd_recipient_restrictions,你得使postfix准许通过验证得用户使用转发服务,也就是将permit_sasl_authenticated安插在限制条件里得适当位置。

2.4 设定验证机制
当客户端联机到smtp server时,哪些密码验证机制可使用,由smtpd_sasl_security_options参数决定。完整得机制选项,取决于你得系统上有哪些机制可用以及你得sasl函数库支持哪些机制。如果不指定任何选项,默认值是接受包括明文密码在内得所有可用机制,但匿名登录除外。如果使用了 saslauthd daemon,就必须接受明文密码,所以,默认值的设想是合情合理的。如果你指定了任何选项,则默认值无效,所以你的选项里必须包含 noanonymous。例如:
       smtpd_asal_security_options = noanonymous, noplaintext

以下是通用的机制选项:
noplaintext
    此选项将plaintext密码验证排除在外。这使得sasl选项challenge/response技术(不传送实际密码)来使用。如果你的安全政策不容许密码以明文形式流经网络,那就指定noplaintext选项吧,但是这也表示你不能使用saslauthd。

noactive
    此选项将可能遭受“主动攻击”(active attack)的密码机制排除在外。在“主动攻击”中,攻击者想办法将他们安插到client与server之间,所以,某些类型的主动攻击又被称为"中间人攻击“(man-in-the-middle attack)。攻击者可以读取或改变数据,让client或server误以为数据真的是对方送过来的。

nodictionary
    此选项将可能遭受”字典攻击“(dictionary attack)的密码机制排除在外。在”字典攻击“中,攻击者使用预编的密码数据库,逐一测试哪个密码”恰好“能闯入你的系统。这类密码数 据库通常由城市、团队、宠物、常见人名、字典词汇,加上各种明显的词汇变化等组成,所以称为”字典攻击“。

noanonymous
    排除匿名登录。smtp验证的最主要目的,就是要确认用户的身份,所以”匿名登录“对smtp server是没有意义的。postfix的默认行为是禁止匿名登录。如果你指定了其他选项,你必须明确设定noanonymous。

mutual auth
    要求使用互证机制--client与server双方都要提供证明自己身份的证据。指定mutual_auth后,会使得Postfix只声明具有互证能力的验证协议。


三、测试SASL验证配置

如何要确定所有步骤都没有出错,证明postfix确实真的已依照我们的要求来进行验证?最好的办法,是直接观察smtp server的交互情况,实际体验验证过程,并立刻查阅日志文件留下的线索。

要想联机到smtp server,最容易的方法是使用telnet工具程序,然后与服务器进程smtp对话。最容易测试的plain机制,如果你禁用这项机制,建议你暂时先启用它,等完成测试实验之后再关掉它。

先让我们了解plain机制的细节。plain机制要求你在auth命令之后提供一个身份标识串,此字符串编码成base64格式。构成此字符串的各项数据的次序是“登录身份”,其后跟着一个null字符,然后是“密码拥有者的身份”,再跟一个null字符,最后是“密码”本身。 通常,“登录身份”与“密码拥有者的身份”是相同的。举例来说,假设用户kdnet的密码为rumpelstiltskin,而且其登录身份与密码拥有者 身份相同,那么,他的身份标识符串是“kdent\okdent\orumpelistiltskin”(编码前的格式)。

麻烦之处,在于如何将标识符串编码成base64格式且不包含字符串末端的CR字符。如果你的系统上有mmcncode与printf命令,这步骤应该不难。printf命令能显出指定格式的字符串,但是不会像echo之类的命令那样,自动在字符串末端补一个换行字符。mmencode命令能将输入字符串编码成各种mime格式,且其默认格式正好是我们所需要的base64。
所以,我们可用下列命令来产生base64格式的标识符串:
      # printf 'kdent\0kdent\0rumpelstiltskin' | mmencode


注:如果
没有命令mmencode(或mimeencode),可以安装个metamail,我使用的是Debian系统,在这使用命名mimeencode
      # aptitude install metamail
      # printf '
kdent\0kdent\0rumpelstiltskin' | mimencode
       a2RlbnQAa2RlbnQAcnVtcGVsc3RpbHRza2lu

某些系统平台的printf可能不能正确地处理字符串中间地null字符(\0),要想知道自己系统上地printf有没有这个毛病,只要看base64编码结果是否比原字符串短(base64格式的字符串,应该比原字符串更长)。如果你地printf有问题,不妨使用echo -n(“-n”表示不输出结尾的换行字符)来代替printf。
下图示范如何使用telnet联机到SMTP server,并展开ESMTP对话(黑体字代表需手动输入的部分):

 



下图为测试LOGIN机制的(其中dDFAYW50aS1saWUuY29t是t1@anti-lie.com的BASE64编码,dDE=是密码t1的BASE64编码,均为手动输入):



四、smtp客户端验证

本文上边,是着重于postfix如何扮演smtp验证地服务器端角色--验证远程mua或mta地身份,借此判断对方是否有权使用转发服务。现在,我们要换个角度,讨论postfix如何扮演客户端角色--提出自己地身份证明,借此获得远程mta地转发服务地使用权。

首先,你得提供一个密码文件给postfix,其中包含能通过远程服务器得证书数据。此密码文件得每一笔记录,各包含一个代表远程服务器的网域以及一组能通过该服务器验证的账户与密码,格式如下:
       destination      username:password

当postfix要寄出一封邮件时,它先检查收件地址的网域部分,如果不能在密码文件中找到完全相符的destination,再寻找打算联机的主机名称。这种检查过程使得postfix可以轻易连接共享相同账户数据库的多个mx主机。决定密码文件位置的参数是 smtp_sasl_password_maps。
决定客户端行为的是smtp_sasl_security_options参数,其设定方法与服务器端的smtpd_sasl_security_options参数相同,所以不再赘述。如果你没指定任何选项,则默认行为是容许系统上所有能找到的机制,唯独匿名登录除外。

smtp客户端验证的设定过程

让我们举个例子来示范要如何设定postfix,才能使其在通过远程系统转发邮件时,提出自己的身份证明。在这个例子中,假设我们有一组可以通过ora.com网域的所有服务器主机的账户以及一组可以通过mail.postfix.org主机的账户。
1、创建/etc/postfix/sasl_passwd密码文件,并填入我们拥有的账户与密码,例如:
       ora.com               kdent:rumpelstiltskin
       mail.postfix.org        kyle:quixote
2、使用postmap产生数据库文件:
        postmap /etc/postfix/sasl_passwd
3、编辑main.cf配置文件,启动客户端验证功能。请注意,这次要设定的参数是smtp_sasl_auth_enable,而不是 smtpd_sasl_auth_enable(后者用于启动服务器端验证)。接着,在smtp_sasl_password_maps参数中指出密码文 件的位置:
        smtp_asal_auth_enable = yes
        smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
4、重新加载postfix,使我们所做的改变生效:
        postfix reload
现在,每当postfix smtp client试图通过/etc/postfix/sasl_passwd所列的任何网域或主机来转发邮件时,它就会提供对应的验证书籍。比方说,如果你的 postfix smtp client联机到mail.ora.com服务器,则它会使用kden与rumpelstiltskin这组账户与密码。 















阅读(2079) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~