Linux自建邮局之Postfix反垃圾挡信机制

摘要

“不请自来的大宗邮件”(Unsolicited Bulk E-mail,UBE),或”不请自来的广告邮件”(Unsolicited Commercial E-mail,UCE),就是一般俗称的”垃圾邮件”(spam),寄件人没有事先征得收件人的同意,就擅自寄送大量(烦人的)邮件给一大群陌生的收件人,这样的行为称为”滥发垃圾邮件”,而专门干这种事的人,叫做”垃圾邮件发送者”(spammer)。垃圾邮件之所以存在,是因为寄送成本便宜。邮递量从几百人增加到几千人并不会增加太多成本,所以,来邮件发送者的目标就是尽量收集多的邮件地址。

按照UBE的判别依据,postfix提供的检查机制可分四大类:

客户端判别规则

Postfix提供四种检查客户端身份的参数,每一种参数都可设定一系列决定如何响应客户端的限 制条件(restriction)。如果条件成立,可能的响应动作包括OK(收下邮件)与reject(当场 拒收)。

例如,你可以设定一条检查规则。挡掉来自特定IP 地址的邮件。相对的,如果条件不成 立,则由后续条件继续处理(这种结果 通常以DUNNO表示)。

语法检查参数

Postfix内置一系列专用检查语法的参数, 可用来核验客户端的smtp对话内容是否符合标准规 定。由于垃圾邮件发送者通常不遵守标准规定,则对于不符合规定的客户端或邮件,你可以要求 postfix予以拒收。有些语法检查参数也可作为客户端判别规则。

内容检查

你可以将一组描述垃圾邮件特征的正则表达式(regular expression)写在查询表(称为模式 表)中,要求Postfix依据样式表来检查邮件的标题与正文内容。

自定义过滤规则

你可将一系列内置的限制条件组织成新的过滤规则。

设定postfix的垃圾邮件标识参数时,你还必须指定如何处理被辨认出来的垃圾邮件。一般而言, postfix可以当场拒收,或是收下邮件但是暂存在另一个队列,或是交给外部过滤程序去处理。


一、客户端判别规则

下列过滤规则可设定一系列对客户端信息的限制条件:

Linux自建邮局之Postfix反垃圾挡信机制

上述的每一项参数,分别用于检查smtp对话过程中的特定阶段。在每一个阶段,客户端分别提供不同类型 的信息。potfix依据你给各规则设定的限制条件来检查这些信息。

下图为SMTP对话过程及各阶段对应的限制条件:

(描述了上述参数与SMTP对话过程各阶段的对应关系,其中header_checks与body_checks 参数为"内容检查")

Linux自建邮局之Postfix反垃圾挡信机制

1 smtp对话过程(简述)

首先,一个smtp client通过socket连接到postfix。由于是socket方式连接,所以postfix在建立连 接时就可以知道客户端的ip地址。 smtpd client_restrictions让你可依据客户端的ip地址或主机名称来 决定是接收还是拒收该信息。连接成功后,客户端送出HELO命令来显示自 己(送信方)的主机名称.postfix 依据smtpd_helo_restrictions的限制条件来检查这个主机名称,借此决定应该收下还是拒收邮件。

下一步,客户端发出mail from命令来显示寄件人的邮件地址,接着以一个rcpt to命令来表明收件人的 邮件地址。寄件人与收件人的邮件地址的限制条件,分别设定在smtpd_sender_restrictions与 smtpd_ recipient_restrictions中。

如果到DATA命令为止之前的一切都可以接收,客户端就可以开始传送邮件的内容。邮件内容分成两部分, 前半部是标题,由header_check过滤;后 半部是正文(body),由check_body过滤。如果最后的标题与 正文检查也过关,postfix就收下信息,并交给适当的MDA执行投递操作。

注:很多垃圾邮件发送者在HELO步骤送出的是“收信方”的主机名称,任何遵守规定的smtp client都不会 这样做,所以你可以在smtp_helo_restrictions设一个限制条件,禁止对方使用我们的主机名称。

2 设定限制条件

任何限制条件都可以用于任何过滤规则。postfix的这种设计,主要是为了让你可以更有灵活性的安排限制条件的顺序。

表:限制条件与对应的受检信息

限制条件 客户端提供的受检信息
reject_rbl_client 客户端的IP地址或主机名称
reject_rhsbl_client
reject_unknown_client
check_client_access type:mapname HELO提供的主机名称
permit_naked_ip_address
reject_invalid_hostname
reject_non_fqdn_hostname
reject_unknown_hostname
check_helo_access type:mapname MAIL FROM提供的寄件人邮件地址
reject_non_fqdn_sender
reject_rhsbl_sender
reject_unknown_sender_domain
check_sender_access type:mapname RCPT TO提供的收件人邮件地址
permit_auth_destination
permit_mx_backup
reject_non_fqdn_recipient
reject_unauth_destination
reject_unknown_recipient_domain
check_recipient_access type:mapname
reject_unauth_pipelining DATA命令
permit 无条件批准
reject 无条件拒绝
defer 无条件延迟
warn_if_reject 将原本的REJECT动作改成WARN
reject_unauth_pipelining 禁止非授权客户端使用PIPELINING命令

拒绝在Postfix支持指令流水线前发送SMTP指 令流水线的客户端连接。指令流水线是一些邮件 客户端为了快速发送邮件所采用的技术

上边所列的限制条件大致可分为3类。

第一类是内置条件,它们的名称以permit_和reject_开头,不需 要额外自变量。

第二类为自定义条件,它们的名称类似check_*_access,需要一个type:mapname自变量, 其中mapname是访问表(access table)的名称。在技术上, 访问表与一般的postfix查询表没两样,同样 都是由一系列的key-value组合而成; 在用途上,访问表供管理员定义自己的过滤规则;索引键描述客户端的 匹配条件,对应值描述如何处理符合条件的客户端。

第三类为通用条件,它们没有额外自变量,也不检查任何信 息,用于直接改变邮件的处理流程,或是改变其他限制条件的作用。

2.1 内置限制条件的工作流程

每一种内置限制条件(reject_和permit_系列),分别检查不同的客户端信息,Postfix依据 检查结果决定如何处理邮件。处理方式包括:OK、 REJECT以及DUNNO. 当你在同一个过滤规则中列 出多个限制条件时,  postfix依照它们的排列顺序来进行检查过程。检查过程中,如果某条件的检 查结果为reject,则POSTFIX会立刻拒收邮件; 如果检查结果为OK,则略过同一过滤规则中的其余条件,继续检查下一个规则;到所有 规则都检查完毕或是出现reject结果为止。

当过滤规则的检查结果为reject时,postfix的默认行为并不是真的当场拒收,除非客户端已经送出recp to命令。如果你想改变延迟reject时机的行为,让 reject动作在第一时间发生,你可将main.cf的smtpd_delay_reject设成成no: smtpd_delay_reject = no

2.2 测试限制条件:

当管理员修改了或增加了新的限制条件时,有些新条件的效果很难完全预测,为此,POSTFIX 提供了一个参数,让你用来测试新限制条件 soft_bounce =yes  #硬性拒绝码(5xx)被改成软性(4xx) 在sotf_bounce模式下,硬性拒绝码(5xx)会被改成软性拒绝码(4xx)。对smtp client 而言, 5xx代表服务器端彻底拒绝请求,即使下次再尝试寄出同一封邮件,服务器端也不会接受。所 有,收到5xx响应码的客户端不会继续尝试同样的动作。另一方面,4xx代表服务器端只是暂时拒绝请 求,客户端下次仍有机会成功寄出邮件, 所以smtp client会保留邮件以等待下次寄送时机。 利用 sotf_bounce模式来测试新条件,即使发生误判,只要我们能实时更正,被误判的smtp client就 有机会寄出它的信。

每增加一条你没把握的新限制条件,都可以打开soft_bounce模式,然后观察日志文件,看看是 否发生误判,并调整条件设计,等一切都妥当之后,再关掉sotf bounce模式。

另一个有用的条件测试工具是warn_if_reject修饰符。将这个修饰符放在限制条件之前,该条件 原本的reject动作都被改成warn。也就是 说,smtp client不会被挡在门外,但是postfix会在 日志文件里留下一笔警告记录, 表示该条件发生作用了。 如果你不确定新条件在实际环境下会造成什 么后果, 但是又不喜欢 soft_bounce 模式那种全面性的影响,你可以用warn_if_reject。来测 试新条件,等到确定新条件的效果符合预期之 后,再拿掉warn_if_reject修饰符。
举例来说:

smtpd_recipient_restrictions =
	permit_mynetworks,
	reject_unauth_destination,
	warn_if_reject reject_invalid_hostname,
	reject_unknown_recipient_domain,
	reject_non_fqdn_recipient

2.3 实例

smtpd_recipient_restrictions =
	permit_mynetworks,
	reject_unauth_destination,
	reject_invalid_hostname,
	reject_unknown_sender_domain

当客户端建立连接时,若它来自mynetworks或mynetworks_style定义的网络,则permit_mynetworks返回OK, 整个smtpd_recipient_restrictions过滤规则也就跟着结束。
若客户端来自外界网络,permit_mynetworks返回DUNNO。

若邮件的收件人不在Postfix所辖的网域(由mydestination定义),reject_unauth_destination返回REJECT;否则返回DUNNO。

reject_invalid_hostname,若客户端使用HELO命令提供的主机名称是无效的,这项检查返回REJECT;有效则为DUNNO

reject_unknown_sender_domain,如果客户端在MAIL FROM提供的邮件地址的网域部分是无效的(即用DNS查不出来),则检查结果会是REJECT。

3 定义限制条件

 依据检查对象的不同,限制条件分为六大类型:

1、访问表

check_*_access形式的,依据访问表所列的IP地址、主机名称或邮件地址而决定Postfix 应拒收还是接收。

2、客户端参数

依据配置文件里的一般信息而非访问列表来检查客户端的资格。如permit_mynetwork条件 就是检查客户端是否来自mynetworks或mynetworks_style定义的网络。

3、严格语法检查

某些限制条件要求Postfix非常严格地贯彻SMTP标准。

4、DNS检查

利用DNS系统提供的信息来审核客户端是否诚实。

5、实时黑名单

RBL是一种依附在DNS系统下的网络服务,供MTA实时查询客户端是否来自恶名昭彰的垃圾源。

6、通用限制条件

无条件拒绝reject或收下permit邮件,或是改变其他条件的行为(warn_if_reject)。


3.1 访问表(access map)

访问表也是Postfix查询表的一种,由key-value组成,访问表的索引键(key)是客户端标识信息(IP地址、邮件地址、主机名称),而value是处理动作(OK或REJECT).

check_client_access maptype:mapname

check_client_access 指向一个含有IP地址、网络地址、主机名称、从属网域名称的访问表. 设定此限制条件时,Postfix先从DNS系统反查出客户端IP地址的完整主机名称( ptr记录),并自己分析出主机本名与从属网域,然后以这些信息与访问表中的每一个索引键比对,如果发现相符的索引键,则采取对应值所指定的处理动作。

check_helo_access maptype:mapname 所指的访问表含有主机名称与从属网域,用于比对客户端在HELO 命令中显示的主机名称。如果发现相符的索引键,则Postfix执行对应值所指定的处理动作。

check_recipient_access maptype:mapname 指向一个含有邮件地址、网域名称、人名的访问表,用于比对客户端在RCPT TO命令中提供的收件地址。如果发现相符的索引键,则Postfix执行对应值所指定的处理动作。

check_sender_access maptype:mapname 指向一个含有邮件地址、网域名称、人名的访问表,用于比对客户端在 MAIL FROM命令中提供的寄件人邮件地址。如果发现相符的索引键,则Postfix执行对应值所指定的处理动作。

索引键:

check_recipient_accesscheck_sender_access用来检查客户端提供的邮件地址,有user@example.com、example.com、user@等格式。

check_client_accesscheck_helo_access检查的数据都是IP地址与主机名称,如下写法均可

192、192.168、 192.168.132、192.168.132.221

对应值:

OK 通过当前过滤规则的检查,继续检查下一个限制条件

REJECT

REJECT message-text

另外加一段简短信息,说明拒绝服务的理由,这段信息会连同拒绝码一起返回给客户端,并且被记录在postfix的日志文件里。access_map_reject_code定义所有check_*_access限制条件的默认拒绝码;maps_rbl_reject_code参数定义reject_maps_rbl的默认拒绝码;两者均为554

DUNNO

未知,继续检查下一个限制条件

FILTER transport:nexthop

将邮件转交给指定的内容过滤器。

HOLD

HOLD message-text 将邮件放在保留队列

DISCARD

DISCARD message-text要求postfix收下邮件后立刻丢弃,但是让客户端误以为它已成功送出邮件。如果你加注一段简短信息, 则postfix会将这段信息记录在日志文件里;否则只记录一般信息.别轻易尝试discard动作,除非你已经谨慎考虑过可能的后果。暗自丢掉邮件的行为,有违邮件系统的设计初衷.虽然丢掉垃圾邮件是 理所当然的动作,但万一发生误判,势必无法挽回已经消息的合法邮件,而且有损用于对于internet e-mail的信任。

4xx message-text

返回指定的拒绝码与信息给客户端,表示暂时拒收邮件。400-499范围内的拒绝码代表服务器端暂时性问题,客户端应该先保留邮件,下次再尝试传送。

5xx message-text

返回指定的拒绝码与信息给客户端,表示彻底拒收邮件。500-599范围内的拒绝码代表服务器端不管怎样都不会收下邮件,客户端应该发出退信通知给原寄件人。

访问表的索引键也可以是“正则表达式”。一般而言,使用正则表达式来描述访问表是一种浪费,因为postfix已经有分析邮件地址、网域名称、ip地址的能力,所以正则表达式带来的好处并不多。但如果要检查邮件的内容(标题或正文),则表达式就非常好用。
范例:Linux自建邮局之Postfix反垃圾挡信机制

/etc/postfix/client_access文件,其内容如下:

10.157                  REJECT
192.168.132.221         REJECT
example.com             REJECT

/etc/postfix/sender_access文件,其内容如下:

user@example.com                    REJECT
test1@                              REJECT
example-test.com                    REJECT
  #转换查询表
#postmap   /etc/postfix/client_access
#postmap   /etc/postfix/sender_access

3.2 客户端条件设置

permit_auth_destination

如果收件地址位于Postfix的辖域,则批准请求。所谓"postfix的辖",包括mydestination、inet_interfaces、virtual_alias_maps或virtual_mailbox_maps及relay_domain所列的网域及子网域。
permit_mynetworks

如果客户端的IP地址位于mynetworks参数所列的任何地址范围内,则批准请求。
reject_unauth_destination

如果收件地址不位于Postfix的辖域,批准请求.拒绝码为relay_domains_reject_code参数提供。

3.3严格语法条件

在内置限制条件,有部分是以“客户端在smtp对话过程提供的信息是否符合标准“为判断依据的。这类条件可侦测出大量垃圾邮件,但是发生误判的机会也很 高。你应该研究你收到的垃圾邮件与真实邮件之间的差异(或共同处),才会知道哪些条件可以使用(或不可使用)。如果你事先知道哪些寄件人可能被误判,建议 你将他们列入白名单里。

reject_invalid_hostname

客户端在helo命令提供的主机名称不是有效的主机名称,返回invalid_hostname_reject_code参数指定的拒绝码(默认为501)

reject_non_fqdn_hostname

客户端在HELO命令提供的主机名称不是RFC要求的完整格式(FQDN),则返回non_fqdn_reject_code参数指定的拒绝码(默认504). 并非所有合法寄件人都会提供FQDN完整名称(尤其是Windows)。

reject_non_fqdn_recipient

客户端在RCPT TO命令提供的收件地址的网域部分,不是RFC要求的完整格式(FQDN),则返回non_fqdn_reject_code参数指定的拒绝码(默认504)。

reject_non_fqdn_sender

客户端在mail from命令提供的寄件人地址的网域部分,不是RFC要求的完整格式(FQDN),则返回non_fqdn_reject_code参数指定的拒绝码(默认504)。

reject_unauth_pipelining

流水线操作(Pipelining)是一种加速处理大宗邮件的技术,其原理是容许客户端一次送出多个SMTP命令. 协议要求客户端必须先检查服务器端是否支持pipelining,才可开始流水线操作,但有些MUA与MTA不遵守规定。此条件会拒绝不遵守规定的SMTP client。

3.4 DNS限制条件

DNS限制条件确定客户端所在的网络以及信封上的邮件地址,是否有可查验的dns信息。如果邮件管理员总是能取得有效的DNS信息,Internet E-mail系统的可用度将获得普遍提升,因为垃圾邮件发送者将难以遁形。不幸的, DNS系统是网管人员最常疏忽的一环,有许多合法用户所在的网络并没有可兹查验的dns信息,因此,完全依赖dns来过滤垃圾邮件, 反而成了不切实际的想法。你应该研究你所收到的垃圾邮件与真实邮件的本质,看看哪些限制条件既能够阻挡最多的垃圾邮件,而误判机率又不令人担心。如果你事先知道哪些寄件人可能被误判,建议你将他们列入白名单里,以免受到dns限制条件的影响。

reject_unknown_client

当SMTP client通过socket建立连接时,POSTFIX Server可从socket连接知道客户端的IP地址.先查询客户端IP地址的PTR记录(改IP记录在DNS系统登录的主机名称),如果查不出,则会拒绝服务;如果能从DNS查出主机名称,则POSTFIX还会使用该主机名再向DNS查出其对应的IP地址,如查出的IP地址不符合socket连接提供的远程IP地址,则会拒绝服务.此拒绝码定义在unknown_client_reject_code参数,其默认值为450(由于当前很多的合法邮件均没有PTR记录,所以建议不使用这条规则)。

reject_unknown_hostname

如果HELO命令提供的主机名称既没有A记录,也没有MX记录,则拒绝服务并返回unknown_hostname_reject_code参数指定的拒绝码(450)。这条规则建议不使用,因为许多客户端的HELO所提供的主机名称不是完整形式,FOXMAIL中HELO所提供的主机名称为客户端系统的计算机名称。

reject_unknown_recipient_domain

如果RCPT to命令提供收件人地址,其网域部分查不出有效的DNS A或MX记录,则以unknown_address_reject_code参数定义的拒绝码拒绝服务(450)。

reject_unknown_sender_domain

如果mail from命令提供寄件人地址, 其网域部分查不出有效的DNS A 或 MX记录,则以unknown_address_reject_code参数定义的拒绝码拒绝服务(450).建议使用这条规则.

3.5 实时黑名单

实时黑名单(Real-Time Blacklist)是一种专为抵制垃圾邮件而设计的网络服务。这种服务依赖于DNS服务,所以也成为DNSBL。Postfix提供下列三种DNSBL的限制条件:

reject_rbl_client rblprovider.domain

将客户端IP地址( 例如 192.168.1.3)颠倒顺序(成为3.1.168.192),搭配RBL管理员的网域名称( 例如xpl.spamhaus.org ) 构成一个主机名称( 成为3.1.168.192.xpl.spamhaus.org), 然后以此主机名称向DNS系统查询,如果能查出一笔A记录,表示该地址已被列入黑名单,则会当场拒收邮件。

reject_rhsbl_client rblprovider.domain

如果客户端的主机名在指定的rblprovdier.domain网域下有一笔A记录,则拒绝服服务.

reject_rhsbl_sender rblprovider.domain

如果寄件人的邮件地址的网域部分,在指定的rblprovdier.domain网域下有一笔A记录,则拒绝服务。

3.6 通用限制条件

除了针对特定信息的检查条件之外,postfix还提供了四个可用于任何过滤规则的限制条件,它们适合放在过滤规则的最后,作为该组规则的默认处理政策。

permit

批准收下邮件。postfix不再继续当前的过滤规则,但是会跳到下一组过滤规则

reject

无条件拒收。postfix不再继续处理任何过滤规则。

defer

婉拒请求,客户端被告知稍候再试。


二、SMTP语法规范参数

smtp是相当宽松的协议,有些smtp client/server的对话过程甚至比协议本身要求更宽松.为此,postfix提供两个参数,让你自己决定是否要求严格遵守smtp协议的对话过程与语法。第一个参数是smtp_helo_required,它决定是否要求smtp client以helo或ehlo动作为开场白。按照smtp rfc的规定,smtp clients连接到server后的第一句话必须是helo或ehlo。 默认情况下,postfix对客户端抱持宽容态度,容许客户端不严格遵循smtp协议。但如果你设定smtpd_helo_required = yes,而客户端见面不打招呼,则postfix将拒绝服务。 smtp rfc也明确规范了信封地址的格式,正常情况下,postfix几乎接受任何有意义的信封地址,但是, 如果你设定了strict_rfc821_envelopes = yes,则没有提供正确格式地址的客户端将被挡在门外。 实际上,要求对方必须提供helo/ehlo或许是个好主意,因为大部分的客户端至少都会遵守smtp协议的基本对话过程。但并非所有客户端都提供符合标准格式的邮件地址,如果要求太严格,可能会错失一些合法邮件。


三、内容检查

直接让postfix将垃圾邮件过滤的最后机会,是检查邮件内容本身。

Postfix提供了四个检查邮件内容的参数:

headr_checks 检查标题

mime_header_checks   检查标题的MIME相关字段

nested_header_checks   检查查夹带附件的标题

body_checks   检查邮件的正文

内容检查的影响是全面性的,即该阶段已经没有机会让特定寄件人或收件人绕过检查。

1 设定内容检查参数

在默认情况下,如果你没有设定mime_header_checks和nested_header_checks参数,它们将与 header_checks共享同一个查询表。如果你想将其区分开来,则必须分别提供不同的查询表给它们。设定检查参数时,必须先注明正则表达式的语法格 式(regexp代表postfix的标准正则表达式语法,pcre代表perl兼容的语法)以及模式表的完整路径。例如:

header_checks = regexp:/etc/postfix/checks/header_checks
mime_header_checks = regexp:/etc/postfix/checks/mime_header_checks
body_checks = regexp:/etc/postfix/checks/body_checks

模式表的索引键是描述比对特征的正则表达式,此正则表达式本身必须放在一对分隔符(通常是/)之间,例如:header_checks模式表如下:

/free mortgage quote/ reject
/^Date:.* 200[0-7]/ REJECT Your email has a date from the past.
/^Date:.*19[0-9][0-9]/ REJECT Fix your system clock and try again.
/^Date:.* 2[0-9][1-9][0-9] / REJECT Your email has a error date.
/^Date:.* 200[9] / REJECT Your email has a error date. 

2 内容检查的响应动作

REJECT message-text

如果模式匹配成功,则拒绝邮件,并将message-text传给客户端。

WARN message-text

模拟拒收动作。

IGNORE

删除符合模式的标题字段或整行文字。用来删除某些敏感信息。

HOLD message-text

将邮件放在保留队列。

DISCARD message

要求Postfix假装接收邮件,但其实偷偷丢掉。能解决迂回攻击的问题。还有如果有无辜用户邮件地址被用来当初垃圾邮件发信者地址,可用此没收邮件,以免无辜受害者收到退信通知。

FILTER transport:nexthop

将邮件转交给指定的内容过滤器。

3 模式匹配

执行标题检查时,标题里的每一个字段都要依序与模式表里的正则表达式匹配。如果字段内容跨越多行,在比对之前,它们会先被合并成一行, postfix先从模式表里的第一个正则表达式开始比对 ,只要发现字段符合某正则表达式, 整个比对过程就立刻结束,并执行该正则表达式对应的动作。只有在所有字段都不符合所有模式的请客下,整个标题才算通过检查。

执行正文检查时,body_checks指定的模式表里的每一个正则表达式,依序与正文里的每一文字行比对,每次只比对一行。如果发现符合模式的字符串,整个比对过程立刻结束,执行此模式所对应的动作。

如果要比对的文字行超过长度上限,postfix会将它们拆成符合长度限制的段落,分段检查。文字行的字符数上限由line_length_limit参数决定 ,其默认值为2048。如果标题的总长度超过header_size_limit(默认值为100k)postfix也是以同样原则分段处理。最后,如果正文总长度超过body_checks_size_limit (默认值为50k),postfix不会检查超过限制的部分.这项限制相当有用,因为可避免postfix去扫描整个文件。

有些管理员运用header_checks来进行简单的病毒过滤。例如,使用下列正则表达式可挡掉夹带危险文件的邮件:

/name ?="?.*\.{bat|scr|com|dll|exe|hta|pif|vbs}"?/ reject

如果你的postfix系统要服务许多windows系统的计算机,上述模式或许能帮你的用户群减少不少困扰,但同时也阻断了“交流正常程序文件”的机会。请注意,这个模式的防毒效果有限,因为我们还漏掉了一些扩展名, 不足以阻挡所有windows可执行文件,况且有许多pc客户端不用扩展名就可以直接运行文件。

下面是一个典型的body_checks模式文件的内容:

/increase your sales by/ reject
/in compliance (with|of) strict/ reject /lowest rates.*\!/
reject /[:alpha:]<!--.*-->[:alpha:]/
reject suspicious embedded htm comments

前两个模式很简单,不再解释。第三个模式挑出任何含有“lowest rates”字样且其后跟着任何文字(.*)以及一个感叹号(!)的字符串,例如“we have our lowest rates in 40 years!”)。最后一个模式检查是否有html注释嵌在字句中间,例如“via<!--ooxx->gra“。垃圾邮件发送者常用这种技巧试图通过过滤程序,但是,这也成为垃圾邮件的绝佳特征,因为一般的正常邮件多半不包含html注释,就算有,也不会刻意夹在字句中间。 使用postmap工具可以测试写好的正则表达式.假设msg.txt是一个垃圾邮件样本文件,我们可用下列方式将它导入postmap:

postmap -q - regexp:/etc/postfix/body_checks < msg.txt

postfix会显示出符合模式的字符串,以及对应该模式的动作。

每个站点面临的垃圾邮件源都不太一样,你应当研究收到的垃圾邮件,根据你自己的研究结果来写 出适当的过滤模式.编写正则表达式时一定要相当谨慎,如果设计不当,可能会严重降低服务器的效率。另一个潜在的问题在于没有任何邮件可以绕过内容检查,即使邮件已通过所有smtpd_*_restrictions过 滤规则的检验,甚至已被纳入白名单,最后仍有可能被header_checks与body_checks挡在门外。

在你设计判别垃圾邮件的过滤规则时,请留心用户群之间需求与心态。有些人对垃圾邮件深恶痛绝,甚至宁愿承担较高的误判风险;有些人则宁可多收一些垃圾邮 件,也不愿意错失任何真实邮件。被你挡掉的化妆品广告邮件,有可能是某位女同事订阅的电子报。如果无法兼顾所有人的要求,且必须分别位不同用户设定不同的过滤规则时, 则最好不要在mta做这件事, 应该考虑使用特殊的mda, 例如procmail,maildrop,或任何能依用户类别来选择过滤规则的软件。

倘若你真的希望在postfix解决不同用户的争议,则postfix提供了分级机制,可针对不同收件人使用不同的过滤规则。


四、自定义过滤条件组合

为了满足不同层次的观众,政府设计了电影分级制度;同样的,为了满足不同用户的需求,postfix也提供了分级制度,让你可依据用户的身份来选择适当的 过滤条件组合。postfix的分级机制称为“规范等级”(restriction class),这是非常强大的工具,让你能更灵活运用postfix的垃圾邮件过滤条件。如果你的用户需要不同松紧程度的过滤条件组合,或是有一两位用户 需要与众不同的过滤规则,投资时间研究如何设定规范等级决定是值得的。

具体做法如下:

1、 定义多组“规范等级”,每个等级都有自己的专属名称,不同的等级各由松紧不等的限制条件组合而成。

2、制作一个访问表,索引键是用户的标识信息(通常是邮件地址),对应值是该用户适用的限制等级的名称。

3、在一般的smtp_*_rrestrictions过滤规则中,加上一条检查访问表的条件。任何check_*_access条件都可以用来检查访问表,换言之,你可以依据客户端(check_client_access)、寄件人(check_sender_access)或收件人(check_recipient_access)来执行分级过滤。

规范等级实例

为了举例说明,假设我们有两组用户:一组是电信警察,以打击垃圾邮件发送者为职责,研究垃圾邮件是他们的专业;另一组人是八卦部队,如果让他们收到垃圾邮件,天下只会更乱而已。 很显然,这两组人不能共享相同的过滤规则,否则一定会出事。为了满足这两种极端的要求,我们拟定了两级规范,分别命名为“spamlover”与“spamhater”。所有规范等级的名称都必须列在smtpd_restriction_classes参数,像这样:

smptd_restriction_classes = spamlover, spamhater

接下来, 我们当初怎样设定一般的smtpd_*_restrictions过滤规则,现在就可以怎样定义我们的规范等级。

以下是spamhater的定义,其限制条件相当严格:

spamhater = reject_invalid_hostname,
reject_non_fqdn_hostname,
reject_unknown_sender_domain,
reject_rbl_client nospam.example.com

下面是spamlover的定义,只有一个简单的permit(无条件批准)

spamlover = permit

当然,现实环境中你应该视实际情况调整规范等级的定义,增加或减少某些限制条件。

现在,我们已经完成新规范等级的声明与定义,下一步,我们要制作一个访问表,让postfix知道哪些人适合哪些规范等级。由于我们的规范等级是针对不同用户而设计的,所以访问表的索引键是收件人的邮件地址,而对应值是用户适合的规范等级。假设这个访问表的名称是per_user_ube,它的内容看起来应该类似这样:

#
#per_user_ube
#
a@example.com spamhater
b@example.com spamlover

最后,要求postfix在审核收件人限制时,检查你指定的访问表:

smtp_recipient_restrictions =
	permit_mynetworks
	reject_unauth_destination
	check_recipient_access hash:/etc/postfix/per_user_ube

记得,postmap /etc/postfix/per_user_ube

一切就绪后,每当外界有人写信给a@example.com,postfix先执行一遍正常的默认过滤规则,在遇到check_recipient_access时,它会检查指定的收件人访问表,并查出a@example.com适用的规范等级为spamhater,然后执行spamhater定义的限制条件。如果spamhater下的任何条件都返回reject,postfix就拒收邮件;否则就将邮件交给适当的mda处理。外界写给b@example.com的邮件也是依照同样的过程来处理,如果postfix所执行的规范等级为spamlover,会无条件收下任何邮件。


五、反垃圾邮件实例

反垃圾邮件的main.cf配置文件样本

smtpd_restriction_classes =
	spamlover,
	spamhater
spamhater =
	reject_invalid_hostname,
	reject_non_fqdn_hostname,
	reject_unknown_sender_domain,
	reject_rbl_client nospam.example.com 
	spamlover = permit
smtd_helo_required = yes
smtpd_client_restrictions =
	check_client_access hash:/ect/postfix/client_access
smtpd_helo_restrictions =
	reject_invalid_hostname,
	check_helo_access hash:/etc/postfix/helo_access
smtpd_sender_restrictions =
	reject_non_fqdn_sender,
	reject_unknown_sender_domain,
	check_sender_access hash:/etc/postfix/sender_access
smtpd_recipient_restrictions =
	permit_mynetworks,
	reject_unauth_destination,
	reject_non_fqdn_recipient,
	reject_unknown_recipient_domain
smtpd_data_restrictions =
	reject_unauth_pipelining,
header_checks = /etc/postfix/header_checks,
body_checks = /etc/postfix/body_checks

这个例子需要好几个访问表,你应该分析实际收到的垃圾邮件,收集垃圾邮件发送者的ip或邮件地址,创建你自己的访问表。不过,就经验来说,check_helo_access和check_sender_access的效果有限, 阻挡不了太多的垃圾邮件。基本上,垃圾邮件发送者有无限多的邮件地址与主机名称可以使用,每次你更新了访问表之后, 他们又从别的地方冒出来,让你疲于奔命。况且,主机名称与发信者地址太容易捏造了,而且他们时常假冒来自拥有大群合法用户的大型网站,使你防不胜防。

虽然挡不住精明的垃圾邮件发送者,但是阻挡垃圾邮件发送者的效果还挺不错。有些家伙不懂变化,总是千篇一律的使用相同信息, 对付这种连干坏事也没有脑筋的垃圾邮件发送者,访问表是最好的武器。

有些在线营销服务发送信息真实的广告信,而且也遵守规定的提供真实的选退机制,让你决定是否愿意继续收到广告信。然而,如果你不相信那些听都没有听过的公司的选退机制,你可用mail from或helo的信息来阻挡他们的广告信,而不要冒着让他们有机会证实你的邮件地址的风险。当然,有些站点恶名远扬,你完全不想再见到他们,不管他们是否诚实、提供选退机制,你都可以直接挡掉它们的垃圾邮件。

此外,有许多垃圾邮件假冒它们来自某些小国家。如果你确定不可能会收到来自马尔代夫共和国的合法邮件,你可以将该国的顶层网域名称填入访问表,一举阻断所有假冒来自该地址的垃圾邮件。然而,如果你的邮件系统服务很多用户,你或许不应该如此武断,将你个人的独断意识强加在每位用户身上。焉知你的用户没有住在马尔代夫的亲戚?或是特别喜欢到该国出差?

 

lookback
  • 本文由 发表于 2015年6月5日18:36:49
  • 除非特殊声明,本站文章均为原创,转载请务必保留本文链接
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: