2021/09/18 CentOS7.4





添付ファイルの送信を遮断するメールサーバ

添付ファイルの付いたメールを、全て遮断するメールサーバです。
多くのネット上の情報は、「外部からexeファイルやbatファイルといった実行型ファイルの流入を遮断します」という目的で解説されています。
ですが、添付ファイルを遮断するのはもはや受信ばかりではなく、送信時にも必要になることがあります。


PPAPという名前が付けられて、メールによるパスワード付圧縮ファイルを送信する時代が終わろうとしています。
それまで、添付ファイルを検出して自動で暗号化zipにするシステムが多く導入されました。
時代も代わり
「今日から暗号化zipの送信禁止。ストレージ・ダウンロード型のデータ送信にしましょう」
となり、メール添付が減り、やがて添付ファイルを自動暗号化するシステムが導入されなくなったら、
今後は、今までと同じ操作で添付ファイルを自然に送信できてしまったら、元も子もありません。
あるフェーズからは、添付ファイルの送信を禁止するメールサーバの必要性が出てきます。

ここでは「内部から外部へ、添付ファイルを送信するのを制限する」にフォーカスしてます。

添付ファイルを禁止するメールサーバ
解説 どこを判定してる?
特定の拡張子だけ許可したい(機能に制限があります
特定の送信者だけ添付ファイルの送信を許可したい
header_checksとmime_header_checks





添付メールの外部への送信を遮断するだけなら簡単です。
header_checksという設定を使用して、Postfixにメールヘッダを検査させ、「name=」という添付ファイルに使用されるヘッダを発見したら、メールを拒否するだけです。



1.header_checksファイルを記述
 条件は1行ごとにスラッシュから始まり、スラッシュで閉じ、後ろにアクションを記述します。
 ここではヘッダ内にname=とその後に続くあらゆる文字列を見つけたら、メールを拒否します。
 REJECT ではなく DISCARD と指定すると、メールは拒否せず黙って受け取り、そのまま破棄します。
#cd /etc/postfix
#vi header_checks
追加
/name=.*/ REJECT

なお、ファイルは次のheader_checksパラメータでregexpで指定するのでpostmapは不要です。



2.header_checksを有効にする
 main.cfを編集し、header_checksファイルを指定します。
#vi main.cf

変更
header_checks = regexp:/etc/postfix/header_checks



3.Postfixをリロード
 header_checksファイルが読み込まれます。
#systemctl reload postfix



4.試験
 このメールサーバを経由して、実際に添付ファイル付きメールを送信してみます。
#tail -f /var/log/maillog

Sep  3 00:00:07 localhost postfix/smtpd[12861]: AEAD61005296: client=unknown[192
.168.1.100]
Sep  3 00:00:07 localhost postfix/cleanup[12863]: AEAD61005296: message-id=<5e3c
1f84-dab0-b836-c257-318e327588f4@example.local>
Sep  3 00:00:07 localhost postfix/cleanup[12863]: AEAD61005296: reject: header C
ontent-Type: image/jpeg;? name="010s.jpg" from unknown[192.168.1.100]; from=<linuxuser1@example.local> to=<linuxuser2@example.local> proto=ESMTP helo=<[192.168.1.100]>: 5.7.1 message content rejected  ← 拒否されている


クライアント側にはこういう情報が表示されます。



内部から外部だけでなく、内部から内部への添付メールも同様に拒否されました。
ですのでメインメールサーバへ追加設定するのではなく、外部へ送信するメールリレーにこの添付ファイルを拒否するメールサーバを挟み込むのが良いでしょう。

ユーザーが送信したのなら、拒否メッセージを表示するのは意味があります。
しかしシステム送信など、添付ファイルを「拒否」するとトラブルになるかもしれません。
アクションにREJECT ではなく DISCARDを指定すると、Postfixは受け取った添付ファイル付きメールを
黙って廃棄するので、送信者からは正常に送信したように見えます。





解説 どこを判定してる?

例えば、メールに添付ファイルがついている場合、メール本文の後ろには以下のような情報が
くっついてます。
(メール本文)

--------------EBC32F8D18E99D48FE206785
Content-Type: image/jpeg;
 name="010s.jpg"     ここを判定してる
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename="010s.jpg"

/9j/dNOYh9bpCSjDxNplKIoqfTJfH/bQHNNrumM69SS21+SuUwG5MPNHynIvTWXuU2bzH6b8
BmEbnUNEdiBRsSTY4AlhhijaJnTMLigS1T8n08oYoxJ1Cr0vyomARvVbLXcS84hVnmf06mnD
bQHNNrumM69SS21+SuUwG5MPNHynIvTWXuU2bzH6b816mxDx2iX7SS8/l3VjScjc3ZjPVILG
mrNxjZBeRaxDnLL0a1bsD0/zV6W80+l2tB9JebvSLioKEVXg0VLR01rmSylVIVNSRYEsQYh/
AQEBAAAAAAAAA(以下略)

このうち、「name=」から始まる行を見つけたら、拒否します。



特定の拡張子だけ許可したい

以下のように設定すると、 制限付き で拡張子許可が出来ます。
以下の場合だと、「.txt」と「.xlsx」の拡張子を許可します。
#vi /etc/postfix/header_checks

/name=.*\.txt/ DUNNO
/name=.*\.xlsx/ DUNNO
/name=.*/ REJECT

どんな制限があるかというと、「日本語ファイル名だと正しく判別できません」

以下は、「新しいドキュメント.txt」というファイルを添付したときのMIME情報です。
--------------861116189F9C679181DB860E
Content-Type: text/plain; charset=UTF-8;
 name="=?UTF-8?B?5paw44GX44GE44OG44Kt44K544OIIOODieOCreODpeODoeODs+ODiC50?=
 =?UTF-8?Q?xt?="    日本語ファイル名は拡張子を含めてエンコードされてる
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename="010s.jpg"

動作はメーラによって異なるでしょうがThunderbirdの場合、この通りファイル名は拡張子を含めてUTF-8でエンコードされています。
さらにいやらしいことに、「新しいドキュメント.txt」という文字数は、メールの80文字ルールにより

新しいドキュメント.t
xt

と、エンコードされて2行に割れてしまっています。
条件判断するなら、途中に含まれる改行を処理する必要があります。

これは本家マニュアルにも
「メッセージヘッダーがエンコードされている場合(RFC2047)は、エンコードされた形でのルールを指定する必要があります」
とあります。

ついでにエンコードされると拡張子部分の文字列も、単純に一定ではありません。
「新しいテキスト ドキュメント.txt」
=?ISO-2022-JP?B?GyRCPzckNyQkJUYlLSU5JUgbKEIgGyRCJUklLSVlJWElcyVIGyhCLnR4dA==?=
「古いテキスト ドキュメント.txt」
=?ISO-2022-JP?B?GyRCOEUkJCVGJS0lOSVIGyhCIBskQiVJJS0lZSVhJXMlSBsoQi50eHQ=?=

これではheader_checkの中で、特定の拡張子を処理するのは難しそうです。
どうしても拡張子で許可拒否を制御したいなら日本語ファイル名を使わないでもらう、などの運用が必要かもしれません。

他に考えられるの根本対策は、そもそもheader_checksで検査するのは諦め、Postfixのコンテンツフィルターを使用してスクリプトを使用し、添付ファイルを検出してファイル名をデコード・拡張子を判断する方法でしょう。

ちなみにネットを調べると、よく以下のような記述を見かけます。
#vi /etc/postfix/header_checks

/name=.*\.exe/ REJECT
/name=.*\.bat/ REJECT
/name=.*\.scr/ REJECT
/name=.*\.bat/ REJECT
/name=.*\.vbs/ REJECT

これは「外部からウィルス添付ファイルが入ってくることを拒否する」という主旨のルールなので
「外国から添付ファイル送られてくる → 日本語ファイル名はあまり使われていない」
というロジックが前提です。
今回は「内部から外部へ添付ファイル送信を禁止する」なので、ちょっと目的が異なります。



特定の送信者だけ添付ファイルの送信を許可したい

いざ運用を始めると、細かい要望が出てきてしまいます。
一番考えられるのは「特定のアドレスからだけは、添付ファイルを許可したい」です。
結論から言えば、header_checksでは出来ません

別記の「特定アドレスからのみ添付ファイルの送信を許可するメールサーバ」を参考にしてください。


ちなみに誰もが最初に考える、一番多い勘違いは以下のようなルールです。
/^from: linuxuser@example.com.*/ DUNNO
/^name=.*/ REJECT
「Fromがlinuxuser@example.comなら、DUNNO(送信)」
それ以外は、添付ファイルがなにか指定してあったら拒否

あるいは

if /^name=.*/
 /^from: linuxuser@exapmle.com/ DUNNO
endif
/^name=.*/ REJECT
「添付ファイルを見つけたとき、Fromがlinuxuser@example.comだったらDUNNO(送信)」
次に添付ファイルは全て拒否

これはPostfix本家のマニュアルにも
「多くの人は、header_checksとbody_checksルールの主な制限事項を見落としています」
「これらの規則は、一度に1つの論理的なメッセージヘッダまたは1つのボディラインに対して動作します。ある行に対して行われた決定は、次の行には引き継がれません」
と書いてあります。

具体的には
1.DUNNOは「許可」ではなく、「入力された行がどのパターンにもマッチしなかったふりをして、見過ごす。メールから送られてくる次の入力行を検査する」
2.一度にチェックするのはヘッダで渡された文字列1行だけ
なので
/^from: linuxuser@example.com.*/ DUNNO    FromはDUNNOで送信OKだけど
/^name=.*/ REJECT     nameが見つかった時点で拒否
if /^name=.*/   nameが見つかった。つまり今はname行を処理中

 /^from: linuxuser@exapmle.com/ DUNNO
     今はname行を処理中。当然そこにFromは見つからない

endif
/^name=.*/ REJECT


以下はOKです。
/name=.*\.txt/ DUNNO    name行でtxtが見つかったらDUNNO。つまり送信扱い
/name=.*\.xlsx/ DUNNO   以降の検索条件は「見つからなかった」扱い
/name=.*/ REJECT

Postfixのheader_checksのアクションでは、安全上の理由により「許可」という判断が存在しません。



header_checksとmime_header_checks

mime_header_checksというパラメータがあります。
これはmimeヘッダに関連する部分のみをチェックするパラメータらしく、マニュアルには

「header_checksで検査される範囲は、mime_header_checksの範囲を除く」
とあります。

つまり
 ・mime_header_checks = MIME範囲専門
 ・header_checks = mime_header_checks以外の範囲を担当

今回のような添付ファイル有無で拒否するのはmime_header_checksで指定するのが正しいと思えます。
ただこのmime_header_checksのデフォルトパラメータは、$header_checskとなっていて、
header_checksでファイルを指定すると、同じファイルが暗黙で指定されます。
(postconfで調べると、header_checksにファイルを指定した場合、なにもせずとも
 mime_header_checksに$header_checksが指定されているのが確認できます。)

そもそもチェックする範囲が違うので、条件式がお互いにかち合わなければ同じファイルを使っても問題ないことが分かります。
とはいえ、今回の要件ではmime_header_checksを使う特段の理由がありません。

mime_header_checksが必要になるのは例えば、MIMEヘッダの中を処理したいが、ヘッダに類似の条件が出てきてしまうのでheader_checksとは違うファイルを指定したい場合、とかでしょうか。






prev.gif