February 17Feb 17 #!/bin/sh # ----------------------------------------------------------------------------- # 防火牆腳本 - 適用於 Debian 13 / iptables-nft (nf_tables backend) # 存放路徑:/usr/local/bin/firewall.sh # 權限設定:chmod 700 /usr/local/bin/firewall.sh # 整合 systemd 開機啟動 (參考 firewall.service) # # 功能說明: # - 支援 start / stop 參數 # - 無參數執行時進入測試模式,7 秒後自動清除規則(避免鎖死自己) # - 包含核心參數調校(抗攻擊、防 IP Spoofing) # - 支援來源 IP 限制、連續埠、反向排除 # ----------------------------------------------------------------------------- # ========================== 使用者設定區塊 ========================== # # 警告:修改前請務必閱讀註解,並確認您的管理 IP 已正確設定! # 1. 禁止連線的 IP 或網段(空白分隔) # 範例:BADIPS="198.108.0.0/16 203.0.113.0/24" BADIPS="" # 2. 不可能出現的私有 IP(RFC 1918) # 注意:若您的伺服器本身 IP 屬於以下網段,請務必刪除該行! # 10.0.0.0/8 → 大型企業內網 # 172.16.0.0/12 → 中型企業內網 # 192.168.0.0/16→ 小型辦公室/家庭網路 IMPOSSIBLE_IPS="10.0.0.0/8 172.16.0.0/12 192.168.0.0/16" # 3. 允許對內連線的 TCP 通訊埠 # 格式說明: # - 單一埠:22 # - 連續埠:7000:7009(包含 7000~7009) # - 指定來源 IP:22,192.168.1.100 # - 反向排除(!):22,!192.168.1.100(允許所有人,除了該 IP) # - 網段寫法:22,10.0.0.0/8 # # 重要:請務必將「你的管理員IP」換成您當前連線的 IP,否則套用 DROP 後將無法連線! IN_TCP_PORTALLOWED="22,你的管理員IP 888,你的管理員IP 80 443" # 4. 允許對內連線的 UDP 通訊埠(格式同上) IN_UDP_PORTALLOWED="" # 5. 允許對內連線的 ICMP 類型 # 常用類型: # 0:Echo Reply(回應 PING) # 3:Destination Unreachable # 8:Echo Request(允許外部 PING 本機) # 11:Time Exceeded(traceroute 需要) IN_ICMP_ALLOWED="8" # ========================== 系統函式區塊 ========================== # # 警告:以下為程式邏輯,若您不熟悉 shell script,請勿任意修改 # 停止功能:清除所有規則,完全開放防火牆(供 systemd ExecStop 或緊急使用) if [ "$1" = "stop" ]; then echo -n "Stopping firewall (flushing all rules)..." iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT iptables -P FORWARD ACCEPT iptables -t filter -F iptables -t filter -X echo " OK" echo "警告:所有防火牆規則已清除,伺服器目前無任何防護!" exit 0 fi # 清除現有規則,還原預設策略 echo -n "Initializing iptables..." iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT iptables -t filter -F iptables -t filter -X echo " OK" # 若帶有 start 參數,則跳過測試模式 [ "$1" = "start" ] && skiptest="1" # ========================== 核心參數調校 ========================== # # 這些設定可提升伺服器對抗某些網路攻擊的能力 # 啟用 SYN Cookies(防止 SYN Flood 攻擊) sysctl -w net.ipv4.tcp_syncookies=2 > /dev/null 2>&1 # 忽略廣播 PING(防止 Smurf 攻擊) sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=2 > /dev/null 2>&1 || \ sysctl -w net.ipv4.icmp_echo_ignore_all_broadcasts=2 > /dev/null 2>&1 # 忽略格式錯誤的 ICMP 封包 sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=2 > /dev/null 2>&1 || \ sysctl -w net.ipv4.icmp_echo_ignore_bogus_error_responses=2 > /dev/null 2>&1 # 關閉 ICMP 重新導向(防止路由表被惡意變更) sysctl -w net.ipv4.conf.all.accept_redirects=0 > /dev/null 2>&1 sysctl -w net.ipv4.conf.default.accept_redirects=0 > /dev/null 2>&1 sysctl -w net.ipv4.conf.all.send_redirects=0 > /dev/null 2>&1 sysctl -w net.ipv4.conf.default.send_redirects=0 > /dev/null 2>&1 # 關閉來源路由(防止封包偽造) sysctl -w net.ipv4.conf.all.accept_source_route=0 > /dev/null 2>&1 sysctl -w net.ipv4.conf.default.accept_source_route=0 > /dev/null 2>&1 # 啟用逆向路徑過濾(防止 IP Spoofing) sysctl -w net.ipv4.conf.all.rp_filter=2 > /dev/null 2>&1 sysctl -w net.ipv4.conf.default.rp_filter=2 > /dev/null 2>&1 # TCP 逾時調校(加快斷線偵測) sysctl -w net.ipv4.tcp_retries1=3 > /dev/null 2>&1 sysctl -w net.ipv4.tcp_fin_timeout=30 > /dev/null 2>&1 sysctl -w net.ipv4.tcp_keepalive_time=1400 > /dev/null 2>&1 # 注意:以下功能為現代 TCP 必要選項,請勿關閉: # - tcp_window_scaling(高延遲高頻寬連線效能) # - tcp_sack(封包遺失重傳效率) # - tcp_timestamps(RTT 計算與 PAWS 保護) # ========================== 防火牆規則設定 ========================== # echo -n "Applying firewall rules..." # 設定預設策略:INPUT 與 FORWARD 預設丟棄,OUTPUT 預設允許 iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT # 允許 Loopback 介面(本機程式互相通訊) iptables -A INPUT -i lo -j ACCEPT # -------------------------- 可疑封包處理 -------------------------- # # 建立 BADPKT 鏈,集中記錄與丟棄可疑封包 iptables -N BADPKT iptables -A BADPKT -m limit --limit 3/min -j LOG --log-prefix "BADPKT: " iptables -A BADPKT -j DROP # 阻擋連線狀態為 INVALID 的封包 iptables -A INPUT -m conntrack --ctstate INVALID -j BADPKT # 阻擋非 SYN 的新連線(異常連線嘗試) iptables -A INPUT -p tcp ! --syn -m conntrack --ctstate NEW -j BADPKT # 阻擋各種異常 TCP Flags 組合(掃描或攻擊手法) iptables -A INPUT -p tcp --tcp-flags ALL NONE -j BADPKT iptables -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j BADPKT iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j BADPKT iptables -A INPUT -p tcp --tcp-flags FIN,RST FIN,RST -j BADPKT iptables -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j BADPKT iptables -A INPUT -p tcp --tcp-flags ACK,URG URG -j BADPKT iptables -A INPUT -p tcp --tcp-flags ACK,PSH PSH -j BADPKT iptables -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j BADPKT iptables -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j BADPKT iptables -A INPUT -p tcp --tcp-flags ALL ALL -j BADPKT iptables -A INPUT -p tcp --tcp-flags ALL FIN -j BADPKT # -------------------------- 狀態允許規則 -------------------------- # # 允許已建立連線與相關連線(回應封包不需重新驗證) iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # -------------------------- 阻擋特定 IP -------------------------- # iptables -N BADIP iptables -A BADIP -j DROP for ip in $BADIPS $IMPOSSIBLE_IPS; do # 忽略空白變數 [ -n "$ip" ] && iptables -A INPUT -s $ip -j BADIP done # -------------------------- 允許特定連線 -------------------------- # # 允許 TCP 連線 for entry in $IN_TCP_PORTALLOWED; do # 處理格式 "port,source" 或 "port" case "$entry" in *,*) port=$(echo "$entry" | cut -d, -f1) src=$(echo "$entry" | cut -d, -f2-) # 處理反向排除 "!" 符號 if echo "$src" | grep -q '^!'; then src_ip=$(echo "$src" | sed 's/^!//') iptables -A INPUT -p tcp --dport $port --syn -m conntrack --ctstate NEW -s $src_ip -j DROP iptables -A INPUT -p tcp --dport $port --syn -m conntrack --ctstate NEW -j ACCEPT else iptables -A INPUT -p tcp --dport $port --syn -m conntrack --ctstate NEW -s $src -j ACCEPT fi ;; *) iptables -A INPUT -p tcp --dport $entry --syn -m conntrack --ctstate NEW -j ACCEPT ;; esac done # 允許 UDP 連線(無 SYN 標誌) for entry in $IN_UDP_PORTALLOWED; do case "$entry" in *,*) port=$(echo "$entry" | cut -d, -f1) src=$(echo "$entry" | cut -d, -f2-) if echo "$src" | grep -q '^!'; then src_ip=$(echo "$src" | sed 's/^!//') iptables -A INPUT -p udp --dport $port -m conntrack --ctstate NEW -s $src_ip -j DROP iptables -A INPUT -p udp --dport $port -m conntrack --ctstate NEW -j ACCEPT else iptables -A INPUT -p udp --dport $port -m conntrack --ctstate NEW -s $src -j ACCEPT fi ;; *) iptables -A INPUT -p udp --dport $entry -m conntrack --ctstate NEW -j ACCEPT ;; esac done # 允許 ICMP 類型 for entry in $IN_ICMP_ALLOWED; do case "$entry" in *,*) type=$(echo "$entry" | cut -d, -f1) src=$(echo "$entry" | cut -d, -f2-) if echo "$src" | grep -q '^!'; then src_ip=$(echo "$src" | sed 's/^!//') iptables -A INPUT -p icmp --icmp-type $type -m conntrack --ctstate NEW -s $src_ip -j DROP iptables -A INPUT -p icmp --icmp-type $type -m conntrack --ctstate NEW -j ACCEPT else iptables -A INPUT -p icmp --icmp-type $type -m conntrack --ctstate NEW -s $src -j ACCEPT fi ;; *) iptables -A INPUT -p icmp --icmp-type $entry -m conntrack --ctstate NEW -j ACCEPT ;; esac done # 對外連線不限制(預設 OUTPUT ACCEPT) # 若需要限制對外連線,可在 OUTPUT 鏈設定規則,此處不贅述 echo " OK" # ========================== 測試模式 ========================== # if [ "$skiptest" = "1" ]; then exit 0 fi echo "" echo "!!! 測試模式 !!!" echo "防火牆規則已套用,將在 7 秒後自動清除,以防止您意外鎖定自己。" echo "若您仍能正常連線,請按 Ctrl + C 中斷,然後執行:" echo " /usr/local/bin/firewall.sh start" echo "" i=1 while [ "$i" -le 7 ]; do echo -n "." sleep 1 i=$((i + 1)) done echo "" echo -n "正在清除規則..." iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT iptables -P FORWARD ACCEPT iptables -t filter -F iptables -t filter -X echo " OK" echo "測試模式結束。若連線中斷,請使用 VNC/Serial Console 重新登入並修正規則。" firewall.sh
Create an account or sign in to comment