postfix 过滤详解

过去这类的邮件被称为垃圾邮件,比较正式的称呼是 SPAM 邮件,postfix 则称此种邮件为 UCE,有那么一点缩小打击范围的含意,因此使用 UCE 过滤并无法解决其它问题邮件(例如:匿迹邮件、病毒邮件、邮件炸弹)所带来的困扰,请不要期望过高。
尽管如此,与 sendmail 使用 access 来进行存取控管相比较,postfix 的 UCE 过滤显然要精细得多,弹性也比较好,以外挂方式读取过滤规则使得管理员能随时修改设定,并将它模块化,可以说是 postfix 最大的优点。
如前所述,postfix 并不使用复杂的宏语言来进行规则运算,而是采用较为单纯的查表法来控制,但各位可不要小看它,它所支持的查表方式可谓琳琅满目,诸如:字段比对(纯文字文件,字段以逗号或空格或定位点区隔)、DBM 检索、HASH 杂凑、NIS 查询、RBL 查询.....等,比对规则也可以选择采用正规表示法(regexp)或是 perl 改良过的正规表示法(pcre)。

邮件标头过滤
标头过滤所过滤的对象,除了邮件标头外,更扩大范围到附加档案的 MIME 标头,使得过滤可以更精确的进行,而不会因规则过于模糊,殃及无辜的邮件。用过 procmail 的使用者要特别注意:附加档案档名或档案类型是在此过滤,而非在邮件内文过滤。设定方式如下:
header_checks = regexp:/etc/postfix/header_checks
header_checks = pcre:/etc/postfix/header_checks
在外挂设定档 header_checks(可以改用其它档名)中,当字符串比对命中时,可以采取各种处理动作,包括:
 

REJECT
拒收信件。

OK
跳过符合条件的标头不作后续检查,在 sendmail 中一旦 OK 该信件就会被接受,但在 postfix 中,OK 仅用来跳过该标头的后续比对,万一有其它标头被拒绝,该封邮件一样会被拒绝。

IGNORE
从邮件删除该标头。

WARN
附加警告讯息。

HOLD
放回队列,等候处理。

DISCARD
直接将邮件丢弃,不响应拒收讯息。

FILTER transport.nexthop
呼叫外挂过滤程序,进行邮件内文剖析过滤。外挂过滤程序可以是任何一种可执行的档案,例如:shell script。该程序必须先定义在 master.cf 中,模拟成一个 socket 来执行(由 master 模块负责伺服监听),当需要呼叫它执行时,postfix 中的 clearup 模块会将整封邮件丢到指定的 port 号,master 模块监听到讯息后会执行相对应的过滤程序。
 

header_checks 的范例如下:
/^Subject: Make Money Fast/ REJECT
/^To: [email=friend@public.com/]friend@public.com/[/email] REJECT
如果未设置此参数,则邮件标头过滤功能将会关闭不启用,这是系统默认值。

邮件内文过滤
这是用来过滤所有标头过滤没检查到的邮件内容,设定方式与前面相同:
body_checks = regexp:/etc/postfix/body_checks
body_checks = pcre:/etc/postfix/body_checks
如果未设置此参数,则邮件标头过滤功能将会关闭不启用,这是系统默认值。

客户端过滤
用户使用 SMTP 通讯协议连上服务器提出寄信请求时,针对客户端输入的指令进行过滤。在 Linux 系管师进阶班讲义 中已经详细论及在 SMTP 联机阶段中出现的各种欺骗服务器的手法, postfix 提供非常详尽的设定可以针对这些问题加以预防。使用客户端过滤时,必须将 smtpd_delay_reject = yes 设定上去,这是系统默认值。当设定成 no 时,虽然效率较高,但是这样做将会使得 HELO 网域伪装、送信人信箱伪装、寄信人信箱伪装以外的其它过滤功能失效。
客户端过滤能够使用的过滤功能,包括:
 

reject_unknown_client
客户端之 IP 或 Domain name 无法从 DNS 查询验证时,拒绝联机。

permit_mynetworks
符合 $mynetworks 定义的客户端允许联机。

reject_rbl_client
从 SPAM 数据库站台验证客户端网域名称,符合时拒绝联机,当这种情况发生时,postfix 将会依照 default_rbl_reply 的设定回复相关讯息,也可以依照 rbl_reply_maps 的设定根据不同客户端给予不同讯息,事实上我们根本不需要设置此两个参数(除非想将讯息改成中文)。这个参数必须放在最后面,当成过滤政策。

reject_rhsbl_client
同上,使用另一种 SPAM 数据库站台。这个参数必须放在最后面,当成过滤政策。

check_client_access
根据 access 设定过滤存取权限,与 sendmail 中的 access 数据库兼容。 可以省略参数名称,直接写档名,例如:hash:/etc/postfix/access。

permit
允许联机,设定在过滤规则的最后面,表示未被之前的规则拒绝的客户端一律允许联机,也就是采用黑名单政策。

defer
延迟联机,设定在过滤规则的最后面,表示未被之前的规则拒绝或接受的客户端,必须在稍后重新接受检验,也就是采用拖延政策。

reject
拒绝联机,设定在过滤规则的最后面,表示未被之前的规则接受的客户端一律拒绝联机,也就是采用白名单政策。

warn_if_reject
被拒绝时产生警告讯息,这是用来测试过滤规则用的。

reject_unauth_pipelining
当客户端持续一直传送 SMTP 命令时,拒绝其联机,这可以防止某些软件一次寄送大量邮件。
 

使用客户端过滤跟稍后会介绍的各种 SMTP 过滤,可以把规则依照前后顺序编排成一组规则炼(写成一行,中间用逗号隔开或从逗号后面分行),由于组合出来的过滤功能并非单独运作的,因此顺序非常重要!
smtpd_client_restrictions = reject_rbl_client dialup.ecenter.idv.tw(台湾免费的 SPAM 数据库:挡拨接发广告信)
smtpd_client_restrictions = reject_rbl_client relays.ordb.org(国外免费的 SPAM 数据库:挡开放转信的服务器)
smtpd_client_restrictions = reject_rbl_client spam.ecenter.idv.tw(台湾免费的 SPAM 数据库:挡寄广告信的信箱)
smtpd_client_restrictions = hash:/etc/postfix/access, reject(采用白名单政策)
smtpd_client_restrictions = permit_mynetworks,reject_unknown_client
smtpd_client_restrictions = permit_mynetworks,hash:/etc/postfix/client_checks,reject_unknown_client,reject_unauth_pipelining
取得石牌国小垃圾信阻挡清单(每日更新)

是否要求使用 HELO 命令
当启用此功能时,将要求客户端进行联机时须先传送 HELO 字符串,稍后我们可以根据 HELO 字符串传回来的网域名称进行过滤,由于某些寄信程序不会传送 HELO 命令,这样做有可能会使得这些客户端程序无法正常寄信。默认值是:
smtpd_helo_required = no

HELO 命令过滤
用来过滤 HELO 命令后面的网域名称是否允许其联机,能够使用的过滤功能,包括:
 

reject_invalid_hostname
网域名称字符串不符合文法时,拒绝其联机。

reject_unknown_hostname
网域名称无法从 DNS 查到 A 或 MX 纪录时,拒绝其联机。

reject_non_fqdn_hostname
网域名称不是完整 FQDN 格式时,拒绝其联机。

check_helo_access
根据 access 设定过滤存取权限。

其它 permit、defer、reject、warn_if_reject、reject_unauth_pipelining 请参考前面的说明。
 

设定范例:
smtpd_helo_restrictions = permit_mynetworks, reject_invalid_hostname

信封标头字段过滤
此功能用来过滤邮件的信封标头是否符合 RFC 821 之规定,预设是不启用此过滤。因为目前最多人使用的 MUA 是 outlook express,它会使用许多额外的标头来进行邮件控制,例如:大家熟知的要求回复功能,如果启用此参数将使得这些信件被拒绝无法寄出。
strict_rfc821_envelopes = yes

寄信人过滤
此功能并非过滤邮件标头里的寄信人字段,而是过滤 mail from: 命令后面的字符串,默认值是不过滤,但由于广告信寄信程序为了能顺利寄信,经常会伪造此字符串,建议应该启用。
可以使用的选项包括:
 

reject_unknown_sender_domain
寄信人的网域名称无法从 DNS 查询验证时,拒绝联机。

reject_rhsbl_sender
寄信人信箱如果被纪录在 SPAM 数据库站台,就拒绝他联机。

check_sender_access
根据 access 设定过滤存取权限。

reject_non_fqdn_sender
寄信人的网域名称不是完整 FQDN 格式时,拒绝其联机。

reject_sender_login_mismatch
寄信人信箱与登入的账号不吻合时,拒绝其联机。须配合 SASL 使用者认证机制使用(SMTP AUTH)。
配合 smtpd_sender_login_maps 指定的对应表,可以让登入账号与使用的信箱作对应,例如:shane 账号可以用 webmaster 信箱寄信。

其它 permit、defer、reject、warn_if_reject、reject_unauth_pipelining 请参考前面的说明。
 

设定范例如下:
smtpd_sender_restrictions = reject_rhsbl_sender dsn.rfc-ignorant.org(国外免费的 SPAM 数据库:挡寄广告信的信箱)
smtpd_sender_restrictions = hash:/etc/postfix/access, reject_unknown_sender_domain
smtpd_sender_restrictions = permit_sasl_authenticated,reject_unknown_sender_domain,reject_non_fqdn_sender

收信人过滤
此功能并非过滤邮件标头里的收信人字段,而是过滤 rcpt to: 命令后面的字符串,默认值是不过滤,但由于广告信寄信程序为了能顺利寄信,经常会伪造此字符串,建议应该启用。
可以使用的选项包括:
 

permit_auth_destination
收信人网域符合 $relay_domains、$mydestination、$inet_interfaces、$vitual_alias_domains、$virtual_mailbox_domains 的定义时,接受联机。

reject_unauth_destination
收信人网域不符合上述设定时,拒绝联机。

permit_mx_backup
当从 DNS 上查到本机为收信人网域的备份 MX 时,接受联机。使用此功能有安全漏洞,可以配合 permit_mx_backup_networks = 172.16.0.0/16 来检查主要 MX 是否在该网段内,来加强过滤功能(避免被不信任的网域设定为转信 MX)。

check_relay_domains
允许代收要给 relay_domians 的信件。

check_recipient_access
根据 access 设定过滤存取权限。

check_recipient_maps
当收信人网域不符合 permit_auth_destination 之要求,或是收信人信箱不符合 $local_recipient_maps、$virtual_alias_maps、$virtual_mailbox_maps、$relay_recipient_maps 的定义时,拒绝联机。此参数可以放在收信人过滤规则的最后面,当作过滤政策。

reject_unknown_recipient_domain
收信人的网域名称无法从 DNS 查询验证时,拒绝联机。

reject_rhsbl_recipient
收信人信箱如果被纪录在 SPAM 数据库站台,就拒绝他联机。

reject_non_fqdn_recipient
收信人的网域名称不是完整 FQDN 格式时,拒绝其联机。

其它 permit、defer、reject、warn_if_reject、reject_unauth_pipelining 请参考前面的说明。

 

设定范例如下:
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination,reject_non_fqdn_recipient

ETRN 命令过滤
用来过滤哪些网域或哪些客户端,可以使用 ETRN 命令。ETRN 命令用来一次处理大量邮件,当某个客户端使用 ETRN 时,有时候会影响到其它用户寄信的效能,通常只有拨接用户、帮拨接用户转信的 mail gateway、邮件讨论群组(mailing list)或电子报发行站台,需要使用此功能。postfix 的默认值是所有客户端都可以使用 ETRN 命令。
能使用的特殊参数只有 check_etrn_access,其余与客户端过滤参数相同,请自行查阅前文。设定范例如下:
smtpd_etrn_restrictions = permit_mynetworks, hash:/etc/postfix/etrn_access, reject

 
伍、效能调校
在这一章中,所有未特别说明的参数,都是设定在 main.cf 中!
行程限制
系统预设行程限制(default_process_limit)为 100,也就是说同时可以收发总共 100 封邮件,如果发现服务器效能很差,可以尝试降低此数值,请修改 master.cf:

# ==========================================================================
# service type private unpriv  chroot wakeup maxproc command + args
#                  (yes)    (yes)    (yes)    (never)  (100)
# ==========================================================================
    . . .
    smtp      inet      n           -               -               -               10               smtpd
    . . .
以上各字段意义说明如下:
service
识别名称

type
服务类型总共有三种:inet、unix、fifo。inet 是指透过网络接口 sockets 提供服务(例如:127.0.0.1:25),unix 指使用 unix sockets 提供服务(直接呼叫执行),fifo 是指使用 pipe name 提供服务(例如:网络传真) 。

private
切断对外服务,默认值是 yes。注意:inet 类型无法设定成 yes。

unpriv
不要以 root 身分执行,而是以 $mail_owner 身分执行。默认值是 yes。

chroot
开启邮件暂存数据夹时,要不要将该数据夹变成根目录,这是为了防止与 postfix 无关的数据夹遭到入侵者以 $mail_owner 身分闯入。默认值是 yes。注意:pipe、virtual 和 local 模块无法设定成 yes。

wakeup
服务每隔多久唤醒一次,默认值是 0(不唤醒)。只有 pickup、qmgr 和 flush 模块需要设定唤醒周期。

maxproc
最大执行绪。

command + args
该服务执行的命令及参数。

master.cf 除了控制 postfix 各个模块的运作方式外,也可以加入外挂过滤引擎,postfix 希望透过这个方式与其它程序设计专家合作,后文将介绍两个经常使用的过滤程序 SapmAssassin 以及病毒过滤软件 amavisd + clamav。更详细的内容可以自行到 www.postfix.org 查看或阅读 /usr/share/doc/postfix-1.xx/README_FILES/FILTER_README!

同步处理限制
postfix 采用同步处理限制来进行流量调整和控制,当 postfix 寄信到某个邮件主机时,首先传两封信过去(initial_destination_concurrency = 2),如果一切正常则逐步增加每次传送的量,一直到传输失败或者是到达同步上限每次 20 封信(default_destination_concurrency_limit = 20)。
如果想要针对不同 agent 来设定同步上限,也可以使用底下的参数(未设定的参数将会沿用 default_destination_concurrency_limit 限制):
local_destination_concurrency_limit = 2
uucp_destination_concurrency_limit = 2
smtp_destination_concurrency_limit = 10
收信人限制
这是指一封信可以寄给多少人,postfix 预设可以处理 50 个收信人(default_destination_recipient_limit = 50),如果一封信的收信人超过 50 人,postfix 会自动将此信复制成很多份,以 50 人为单位分批寄送。
和同步处理限制一样,可以针对不同 agent 来设定不同上限:
uucp_destination_recipient_limit = 2
smtp_destination_recipient_limit = 10
延迟传送
当邮件服务器使用拨接线路联机时,由于部分时段处于断线状态,当 postfix 处理信件时会因为无法收发信件,持续产生错误讯息,为了避免发生这个现象,我们可以设定 defer_transports = smtp 来告知 postfix,要从 smtp agent 传送出去的邮件暂时不要传送。这些邮件可以等到上线后,再以 ETRN 指令全部寄出。
如果本机是前述邮件服务器的 mail gateway,由于该服务器只有部分时段上线,因此有可能 mail gateway 已经累积许多信件等待传送给它,为了避免 mail gateway 持续尝试传送,可以设定:
defer_transport = hold
接着在 /etc/postfix/transport 设定:
customer.com   hold:[gateway.customer.com]
这个设定的意思是,要给 customer.com 的邮件先暂存在 gateway.customer.com,等待前者上线后再全部传送给它(使用 ETRN 命令)。
设定好后,还需修改 master.cf,找到 smtp 行程设定(可参考前面小节),将 smtp 改为 hold 即可:
hold   unix   -   -   n   -   -   smtp
传送失败处理
当邮件传送失败的时候,负责传送邮件的 Agent 会将邮件退回给 qmgr 模块,qmgr 模块则会计算从邮件到达到现在的时间间隔,依此时间间隔将邮件排入延迟传送队列中,以等待下次传送。
如果该封邮件传送到一半的时候失败了,也就是说有些收信人有收到,有些没有。这种情况下,除了将该邮件排入延迟传送队列外,也会将传送失败的对象排入 dead 清单一段时间,在这段时间内如果有其它邮件要传送给这些对象时,就会直接排入延迟传送队列,而不用徒劳无功地去尝试传送!
底下是有关于邮件传送失败处理的相关效能设定:
queue_run_delay = 1000s      qmgr 模块每 1000 秒(约 16 分钟)检查一次 defer 队列,查看是否有邮件须排入 active 队列
maximal_queue_lifetime = 5d 无法传送的信件在 defer 队列里最多保存 5 天,超过时间则退给寄信人
minimal_backoff_time = 1000s     传送失败的邮件至少在 defer 队列中暂停 1000 秒,而且被排入 dead 清单的收信人至少也要待 1000 秒,也就是说在这段时间内不再尝试寄信给他
maximal_backoff_time = 4000s    传送失败的邮件最多在 defer 队列中等待 4000 秒(约 1 小时)
qmgr_message_recipient_limit = 1000  dead 清单的大小,也就是说第 1001 个传送失败的对象,不会被排入 dead 清单
拖延战术
当怀有恶意的客户端连续传送大量邮件时,postfix 为了处理这些邮件耗掉太多资源,导致无法正常工作,这也就是经常被讨论的「阻断服务攻击」。
postfix 的设计者认为阻断服务攻击是不可能被解决的,因为我们无法单从邮件区分出它是恶意或善意,但是我们可以透过一些手段来降低损害。postfix 采用的方法是针对每条联机,设定一个联机错误计数器( session error count),当客户端联机时,开启计数器,如果客户端传送不存在的 SMTP 命令(这绝对是恶意想阻断服务),或是超过字数限制的长字符串(内存溢位攻击)、超过一行的标头(引发邮件剖析错误),计数器就会不断累加。当邮件交寄成功时,计数器才会归零重新计算。
现在我们只要根据计数器采取适当的处理动作就行了:
smtpd_soft_error_limit = 10  当计数器到达 10 时,就暂停该联机一段时间
smtpd_hard_error_limit = 100       当计数器到达 100 时,直接断线
smtpd_error_sleep_time = 5s 每次暂停 5 秒钟

上一篇: extman+extmail安装   下一篇: linux文件权限对照表

提交疑问

回顶部