Security

Postfix中的自動黑名單

  • June 29, 2020

我有許多成功限制濫用的 Postfix 指令。但是:在強制執行限制後,施虐者只需重新連接並完成重新失敗相同測試的完整過程。關於連接客戶端強制執行的先前限制,記憶體沒有持久性。

是否有任何解決方案可以縮短此循環並在僅執行一次資源昂貴指令後直接進入塊?理想情況下,我希望支持將 IPv4 / IPv6 地址列入黑名單-

更新:

我對解決方案進行了重大更新,並添加了 IPv6 支持和內務管理,以實施“滾動”阻止列表以在違規者停止訪問您的伺服器後修剪 IP。

介紹:

**儘管有許多 Postfix 指令可以阻止濫用者,但這些指令的問題是沒有持久性記憶這些先前的決定。**因此,濫用者可以無休止地重新連接,他們的流量必須通過相同的測試重新失敗。因此,最終目標是打破這種無休止的濫用循環,並在第一次資源密集型測試失敗後禁止違規 IP。

我已經開源了一個我在自己(有點)繁忙的郵件伺服器上執行的解決方案,該郵件伺服器託管了許多域的許多帳戶。簡而言之,它創建了一個 SystemD 服務和計時器,它觸發一個腳本,該腳本使用 RegEx 來抓取/var/log/maillogIPv4 和 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使用我的 repo 的上一次迭代被列入黑名單,該迭代持續記錄違規 IP。如果沒有定期修剪此列表的機制,則會出現可伸縮性問題。我的新方法是創建一個滾動阻止列表:不斷地從郵件日誌中抓取新的濫用者 IP,並刪除那些不再出現在郵件日誌中的 IP。我能想到的任何其他方法都是基於清除 IP 的任意時間。

因此,如果濫用者沒有出現在新的郵件日誌中,則在日誌輪換之後,他們將不會被包含在黑名單中 - 只有當他們進行後續濫用嘗試時。IP 僅在輪換之前的郵件日誌生命週期內被列入黑名單。

程式碼

我可以說回購按照我的測試在錫上所說的那樣做。但是,我不懷疑某些部分可能會更優雅。以下是開展業務並供同行評審的主要腳本。

如果您有任何想法/建議,請讓我們聽聽,或者最好還是向我發送拉取請求(請僅在您測試了增強功能之後)。該腳本很容易測試——它為你做所有事情,所有程式碼都被很好地註釋了——同樣容易放鬆。

請注意:此腳本僅在您有讀取“訪問”映射的指令時才有效main.cf另請注意,Postfix 的限制性指令是從左到右強制執行的,因此任何讀取“訪問”映射的指令都應該離開執行更昂貴測試的指令。

如果您只想進行一些測試,repo 包含一個腳本來解除安裝所有內容。

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 的記憶的持久性,以阻止無休止地重複昂貴的測試。完美嗎?可能可以做一些拋光,但到目前為止我的測試結果似乎很有希望。

如果您厭倦了您的郵件伺服器被垃圾郵件發送者無休止地濫用,這是一種快速簡便的解決方案,可以儘早關閉它們:

https://github.com/f1linux/postfix-autoBlacklisting

引用自:https://unix.stackexchange.com/questions/573014