我刚刚收到了几封内容类似的邮件,这些邮件都是用 base64 编码的。现在我想使用正文检查来拒绝或丢弃此类邮件。
之前我的 body_checks 中有类似这样的内容:
/Quanzhoucooway/ DISCARD
但由于消息已编码,因此无法检测到该关键字。
以下是一个 base64 编码的消息:
DQpIaSBGcmllbmRzLA0KDQpHb29kIGRheSENCg0KVGhpcyBpcyBWaWN0b3JpYSBmcm9tIFF1YW56
aG91Y29vd2F5IHNob2VzIHRyYWRpbmcgY28uLGx0ZCwgYSBwcm9mZXNzaW9uYWxtYW51ZmFjdHVy
ZXIgYW5kIGV4cG9ydGVyIG9mIGFsbCBraW5kcyBvZiBzaG9lcywgbWFpbmx5IGluIGNhc3VhbCBz
aG9lcyBhbmQgc3BvcnRzIHNob2VzICwgd2hpY2ggaGFzIGJlZW4gc3VwcGxpZWQgdG8gdGhlIGZh
bW91cyBmYXNoaW9uIGJyYW5kIHN0b3JlcyBmcm9tIDIwMTAuDQoNCk5vdGljaW5ndGhhdCB5b3Ug
YXJlIGxvb2tpbmcgZm9yIGhpZ2ggcXVhbGl0eSBmYXNoaW9uIHNob2VzLCBzbyBJIGhvcGUgd2Ug
Y2FuIHdvcmsgdG9nZXRoZXIgaW4gdGhlIGZ1dHVyZS4gSWYgeW91IGFyZSBpbnRlcmVzdGVkLCBJ
IHdpbGwgc2VuZCB5b3Ugb3VyIGl0ZW1zIGFjY29yZGluZ2x5Lg0KDQpGWUksIHdlIGNhbiBtYWtl
IGN1c3RvbWl6ZWQgc2FtcGxlcyBmb3IgeW91IGFjY29yZGluZ2x5Lg0KDQpMb29raW5nIGZvciB5
b3VyIHNvb25lc3QgcmVzcG9uc2UuDQoNCkJSIQ0KDQpWaWN0b3JpYSANCg==
那么阻止此类电子邮件的最佳做法是什么?
答案1
不要对 Postfix 这样做body_check
但编写 Spamassassin 规则相反,Spamassain 会在应用其规则之前解码邮件正文。例如:
body LOCAL_QUANZHOUCOOWAY /Quanzhoucooway/
score LOCAL_QUANZHOUCOOWAY 7.0
describe LOCAL_QUANZHOUCOOWAY Block word Quanzhoucooway
这些规则属于/etc/mail/spamassassin/local.cf
(或~/.spamassassin/user_prefs
)。
答案2
从技术上来说,你可以直接过滤 base64 编码的数据中的关键字。我并不是说这是一个实用或合理的做法,因为有更好更简单的替代方案(如上文 Esa 的回答中所述),但它是可能的。
诀窍在于认识到base64 编码是将原始未编码数据的 3 字节块确定性地映射到 base64 字符的 4 字符块。因此,只要未编码数据中出现特定的 3 字节块序列,编码版本中就会出现相同的 4 字符块序列。
例如,如果你将字符串输入Quanzhoucooway
到base64 编码器,您将得到输出UXVhbnpob3Vjb293YXk=
。由于输入的长度不是 3 字节的倍数,因此输出包含一些填充在最后,但如果我们删除最后的=
符号和最后一个实际的 base64 字符(因为它还编码了一些填充位),我们就会得到保证出现在 base64 编码数据中的k
字符串,只要字节三元组、、和部分三元组按该顺序出现在输入中。UXVhbnpob3Vjb293YX
Qua
nzh
ouc
oow
ay
但是,当然,字符串Quanzhoucooway
可能不会恰好从三元组边界开始。例如,如果我们XQuanzhoucooway
对字符串进行编码,则会得到看起来完全不同的输出WFF1YW56aG91Y29vd2F5
。这次,输入长度可以被三整除,因此末尾没有要丢弃的填充字符,但我们需要丢弃前两个字符(WF
),每个字符都对前置字节中的一些位进行编码X
,剩下F1YW56aG91Y29vd2F5
。
最后,base64 编码XXQuanzhoucooway
输出为WFhRdWFuemhvdWNvb3dheQ==
,两端都有填充。删除前三个字符WFh
(编码前缀XX
)和后三个字符Q==
(编码末尾的零位填充),我们剩下字符串RdWFuemhvdWNvb3dhe
。因此,我们获得以下三个 base64 编码字符串:
UXVhbnpob3Vjb293YX
F1YW56aG91Y29vd2F5
RdWFuemhvdWNvb3dhe
其中(至少)一个必须出现在包含单词的任何输入字符串的 base64 编码形式中Quanzhoucooway
。
当然,如果你运气不好,base64 编码器可能会在任意两个编码三元组之间插入换行符。(例如,你的示例消息在F1YW56
和之间有一个换行符aG91Y29vd2F5
。)因此,为了可靠地将这些字符串与正则表达式匹配,你需要类似以下内容(使用 PCRE 语法):
/UXVh\s*bnpo\s*b3Vj\s*b293\s*YX/ DISCARD
/F1\s*YW56\s*aG91\s*Y29v\s*d2F5/ DISCARD
/R\s*dWFu\s*emhv\s*dWNv\s*b3dh\s*e/ DISCARD
手动生成这些模式有点繁琐,但用你最喜欢的编程语言编写一个简单的脚本来完成它并不难,至少只要它提供了一个 base64 编码器。
如果你真的想要,你甚至可以实现不区分大小写的匹配,方法是对关键字的小写和大写版本进行 base64 编码,并将它们组合成与任意组合匹配的正则表达式。例如, 的 base64 编码是 , 的 base64quanzhoucooway
编码cXVhbnpob3Vjb293YXk=
是QUANZHOUCOOWAY
,UVVBTlpIT1VDT09XQVk=
因此规则:
/[cU][XV]V[hB]\s*[bT][nl]p[oI]\s*[bT][31]V[jD]\s*[bT][20]9[3X]\s*[YQ][XV]/ DISCARD
无论如何都会匹配 base64 编码的单词“Quanzhoucooway”,前提是它以三元组边界开始。为移位版本生成另外两个相应的正则表达式留作练习。;)
唉,做任何比这种简单的子字符串匹配更复杂的事情很快就会变得不切实际。但至少这是一个巧妙的技巧。原则上,如果你出于某种原因不能使用 SpamAssassin 或任何其他可以在过滤前解码 base64 编码的过滤器,它甚至可能很有用。但如果你能做到这一点,而不是使用这样的黑客手段,你当然应该这么做。