悪用を効果的に制限する Postfix ディレクティブが多数あります。しかし: 制限が適用された後、不正使用者は再接続して、同じテストに再度失敗するプロセスをすべて実行します。接続中のクライアントに適用されていた以前の制限に関するメモリは保持されません。
このループを短絡し、リソースを大量に消費するディレクティブが一度だけ適用された後にブロックに直接進むような解決策はありますか? 理想的には、IPv4 / IPv6 アドレスの両方をブラックリストに登録するためのサポートが欲しいです。
答え1
アップデート:
ソリューションに重要な更新を加え、IPv6 サポートとハウスキーピングを追加して、違反者がサーバーにアクセスしなくなった後に IP を削減する「ローリング」ブロック リストを実装しました。
イントロ:
悪用者をブロックできる Postfix ディレクティブは多数ありますが、これらの問題は、以前の決定の記憶が永続化されないことです。そのため、悪用者は際限なく再接続することができ、そのトラフィックは同じテストで再度不合格になります。したがって、最終的な目標は、この悪用の際限のないループを断ち切り、リソースを大量に消費する最初のテストが不合格になった後に、問題のある IP を禁止することです。
私はソリューションをオープンソース化した私は、多くのドメインの多くのアカウントをホストしている、独自の (やや) 忙しいメールサーバーを運営しています。簡単に言うと、SystemD サービスとタイマーを作成し、正規表現を使用して/var/log/maillog
IPv4 と IPv6 アドレスの両方の不正パターンをスクレイピングするスクリプトを起動します。これまでのテストでは、不正使用を大幅に削減することに成功しています。
からのサンプル出力/etc/postfix/access
。単一の IPv6 アドレスは含まれません。
213.230.115.33 REJECT
213.230.75.114 REJECT
185.66.252.78 REJECT
162.243.133.39 REJECT
104.168.159.38 REJECT
78.128.113.109 REJECT
77.40.3.227 REJECT
77.40.3.101 REJECT
61.163.192.88 REJECT
37.0.20.10 REJECT
26.189.237.221 REJECT
[2001:da8:5066:66:eda:41ff:fe1d:b27] REJECT
ちなみに、IPv6 をこれと連携させるのはちょっと大変でしたが、最終的には成功しました ;-)
ブラックリスト戦略:
2.5か月で約1200以上のIPがブラックリストに登録されました違反者の IP を永続的に記録するリポジトリの以前の反復を使用しています。このリストを定期的に整理するメカニズムがなければ、スケーラビリティの問題が発生します。私の新しいアプローチは、ローリング ブロック リストを作成することです。つまり、メール ログを継続的にスクレイピングして、新しい違反者の IP を探し、メール ログに表示されなくなった IP を削除します。私が考えついた他のアプローチは、IP を消去するための任意の時間に基づいたものでした。
したがって、ログのローテーション後、不正使用者が新しいメールログに表示されない場合、その不正使用者はブラックリストに含まれません。その後不正使用を試みた場合のみ含まれます。IP は、ローテーション前のメールログの有効期間中のみブラックリストに含まれます。
コード
私のテストでは、このリポジトリは説明どおりの機能を果たしていると言えます。ただし、一部の部分はより洗練されている可能性があると思います。以下は、ピアレビュー用に提供された、機能を果たすメイン スクリプトです。
ご意見やご提案がありましたら、ぜひお聞かせください。またはプルリクエストを送ってください(拡張機能をテストした後でのみお願いします)。スクリプトは簡単にテストできます。すべてが自動的に行われ、すべてのコードに適切なコメントが付けられています- リラックスするのも同じくらい簡単です。
ご注意ください: このスクリプトは、 内の「アクセス」マップを読み取るディレクティブがある場合にのみ有効ですmain.cf
。また、Postfixの制限的なディレクティブは左から右に適用されることにも注意してください。したがって、「アクセス」マップを読み取るディレクティブは、よりコストのかかるテストを実行するディレクティブの左側に置く必要があります。
テストだけを実行したい場合、リポジトリにはすべてをアンインストールするスクリプトが含まれています。
cat <<'EOF'> /etc/postfix/access-autoBlacklisting.sh
#!/bin/bash
#
# Author/Developer: Terrence Houlahan Linux Engineer F1Linux.com
# Linkedin: https://www.linkedin.com/in/terrencehoulahan
# License: GPL 3.0
# Source: https://github.com/f1linux/postfix-autoBlacklisting.git
# Version: 03.20.00
# OPERATION:
# ----------
# This script PREPENDS offending IP addresses from "/var/log/maillog" to "/etc/postfix/access"
# This ensures restrictive access rules applied before permissive grants.
# Consult README.md file for more granular detail about this script and its operation.
# Stop timer from executing Blacklisting script: Existing blacklist in /etc/postfix/access is enforce enforced while the new blacklist rebuilds
systemctl stop Postfix-AutoBlacklisting.timer
# Purge blacklist: Blacklist recreated each script execution capturing both previous offending IPs as well as newest ones present in logs
sed -i '/REJECT$/d' /etc/postfix/access
# Purge the scratch file:
> /etc/postfix/access-blacklist
### Scrape log for different forms of abuse using different tests to identify abuse IPs and squirt each to same central file:
# Enable/Disable any of below tests according to your requirements. Adding your own is easy if you use my tests which isolate offending IPs as templates.
# TEST 1: Blacklist Zombie hosts from endlessly squirting spam: These are identified by no PTR record being set for them.
# This test will catch both new zombies as well as those already RBLed which should serve to stop them constantly being endlessly checked against the RBL
# IPv4 Test:
# Below commented test was found to not be 100 perecent as accurate as the one using the awk form. Have not investigated why however.
#grep "does not resolve to address" /var/log/maillog | grep -Eo "([0-9]{1,3}[\.]){3}[0-9]{1,3}" | sort -u >> /etc/postfix/access-blacklist
grep "does not resolve to address" /var/log/maillog | awk 'match($0, /([0-9]{1,3}[\.]){3}[0-9]{1,3}/) {print substr($0, RSTART, RLENGTH)}' | sort -u >> /etc/postfix/access-blacklist
# IPv6 Test:
grep "does not resolve to address" /var/log/maillog | grep -Eo "2[0-9a-fA-F]{3}:(([0-9a-fA-F]{1,4}[:]{1,2}){1,6}[0-9a-fA-F]{1,4})" | sort -u | awk '{print "["$1"]"}' >> /etc/postfix/access-blacklist
# TEST 2: Block spammers guessing account names where they know our domain:
# WARNING: this could potentially cause a block where an unintentional misspelling of an mail account name occured.
# Uncomment only if you are OK with accepting such a risk:
# IPv4 Test:
#grep "Recipient address rejected: User unknown in virtual mailbox table" /var/log/maillog | sed -rn 's/.*\[(([0-9]{,3}.){4})\].*/\1/gp' >> /etc/postfix/access-blacklist
# IPv6 Test:
#grep "Recipient address rejected: User unknown in virtual mailbox table" /var/log/maillog | grep -Eo "2[0-9a-fA-F]{3}:(([0-9a-fA-F]{1,4}[:]{1,2}){1,6}[0-9a-fA-F]{1,4})" | sort -u | awk '{print "["$1"]"}' >> /etc/postfix/access-blacklist
# Populate an array with sorted and depuplicated list of offending IPs scraped from maillog using foregoing tests:
readarray arrayIPblacklist < <( cat /etc/postfix/access-blacklist | sort -u -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n | sed '/^$/d' )
# If "access" is a new empty file then the subsequent "sed" will fail. Any new file will have a zero size so the '-s' test will not equal 'true'.
# So we use negation to test "true" and echo a blank space to file. The subsequent "sed" will now execute.
# If "access" file already has whitelist entry then the 'if' statement does nothing and "sed" which follows executes as expected for a non-empty file:
if [ ! -s /etc/postfix/access ]; then echo "" > /etc/postfix/access; fi
for i in "${arrayIPblacklist[@]}"; do
# Write list of IPS from array to TOP of "access" file to enforce restrictions BEFORE processing whitelisted "OK" addresses:
sed -i "1i $i" /etc/postfix/access
# Append " REJECT" (with a space prepended in front of it) after each of the IPs added to to the "access" file:
sed -i '1s/$/ REJECT/' /etc/postfix/access
done
# Rebuild the /etc/postfix/access Berkeley DB:
postmap /etc/postfix/access
systemctl reload postfix.service
# After cycle completes and IPs written to /etc/postfix/acces we wipe array which repopulates anew upon next script execution:
unset arrayIPblacklist
systemctl start Postfix-AutoBlacklisting.timer
EOF
結論:
以前ブロックされた IP に関するメモリの永続性を維持し、高価なテストが際限なく繰り返されないようにするシステムとして、私は到達したと思います。これは完璧でしょうか? おそらくもう少し磨きをかける必要があるでしょうが、これまでのテストでは結果は有望に思えます。
メールサーバーがスパマーによって際限なく悪用されていることにうんざりしているなら、できるだけ早くそれらをシャットダウンするために実装できる、次の迅速かつ簡単な解決策があります: