如何调整 Virtualmin 网站以适应高流量?(替代:如何防御 DoS?)

如何调整 Virtualmin 网站以适应高流量?(替代:如何防御 DoS?)

我有一个在 PHP-FPM/Nginx/MariaDB 上运行的网站,通过 Virtualmin 托管在 8GB RAM、4 核 Xeon 3.1ghz CPU 上,隐藏在 Cloudflare 后面。

最近,我们遭遇了一些简单的 DoS 攻击,一个人在其浏览器控制台上运行如下脚本:

setInterval(function() { fetch("/") }, 1)

能够轻松关闭网站。我尝试过微调 PHP-FPM 配置以应对高流量,但没有成功,我尝试过增加 MariaDB 的 RAM,但同样没有成功。

这是我的 PHP-FPM 配置:

listen.mode = 0660
pm = static
pm.max_children = 50
pm.start_servers = 16
pm.min_spare_servers = 8
pm.max_spare_servers = 16
php_value[memory_limit] = 128M
php_value[max_execution_time] = 300

我是不是漏掉了什么?一个人不可能只用一个简单的 Javascript 命令就能搞垮整个网站。

答案1

也许一些 iptables 规则有帮助

### 1: Drop invalid packets ###
/sbin/iptables -t mangle -A PREROUTING -m conntrack --ctstate INVALID -j DROP

### 2: Drop TCP packets that are new and are not SYN ###
/sbin/iptables -t mangle -A PREROUTING -p tcp ! --syn -m conntrack --ctstate NEW -j DROP

### 3: Drop SYN packets with suspicious MSS value ###
/sbin/iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP

### 4: Block packets with bogus TCP flags ###
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,ACK FIN -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,URG URG -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,FIN FIN -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,PSH PSH -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL ALL -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
/sbin/iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

### 5: Block spoofed packets ###
/sbin/iptables -t mangle -A PREROUTING -s 224.0.0.0/3 -j DROP
/sbin/iptables -t mangle -A PREROUTING -s 169.254.0.0/16 -j DROP
/sbin/iptables -t mangle -A PREROUTING -s 172.16.0.0/12 -j DROP
/sbin/iptables -t mangle -A PREROUTING -s 192.0.2.0/24 -j DROP
/sbin/iptables -t mangle -A PREROUTING -s 192.168.0.0/16 -j DROP
/sbin/iptables -t mangle -A PREROUTING -s 10.0.0.0/8 -j DROP
/sbin/iptables -t mangle -A PREROUTING -s 0.0.0.0/8 -j DROP
/sbin/iptables -t mangle -A PREROUTING -s 240.0.0.0/5 -j DROP
/sbin/iptables -t mangle -A PREROUTING -s 127.0.0.0/8 ! -i lo -j DROP

### 6: Drop ICMP (you usually don't need this protocol) ###
/sbin/iptables -t mangle -A PREROUTING -p icmp -j DROP

### 7: Drop fragments in all chains ###
/sbin/iptables -t mangle -A PREROUTING -f -j DROP

### 8: Limit connections per source IP ###
/sbin/iptables -A INPUT -p tcp -m connlimit --connlimit-above 111 -j REJECT --reject-with tcp-reset

### 9: Limit RST packets ###
/sbin/iptables -A INPUT -p tcp --tcp-flags RST RST -m limit --limit 2/s --limit-burst 2 -j ACCEPT
/sbin/iptables -A INPUT -p tcp --tcp-flags RST RST -j DROP

### 10: Limit new TCP connections per second per source IP ###
/sbin/iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m limit --limit 60/s --limit-burst 20 -j ACCEPT
/sbin/iptables -A INPUT -p tcp -m conntrack --ctstate NEW -j DROP

### 11: Use SYNPROXY on all ports (disables connection limiting rule) ###
#/sbin/iptables -t raw -A PREROUTING -p tcp -m tcp --syn -j CT --notrack
#/sbin/iptables -A INPUT -p tcp -m tcp -m conntrack --ctstate INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460
#/sbin/iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

### SSH brute-force protection ###
/sbin/iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -m recent --set
/sbin/iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 10 -j DROP

### Protection against port scanning ###
/sbin/iptables -N port-scanning
/sbin/iptables -A port-scanning -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 2 -j RETURN
/sbin/iptables -A port-scanning -j DROP

并在 php fpm 中使用它

; Set appropriate permissions for Unix sockets
listen.mode = 0660

; Use a dynamic process manager
pm = dynamic

; Adjust the maximum number of child processes
pm.max_children = 50

; Start with a moderate number of servers
pm.start_servers = 10

; Keep a few spare servers to handle increased load
pm.min_spare_servers = 5
pm.max_spare_servers = 15

; Set a reasonable memory limit for PHP processes
php_value[memory_limit] = 256M

; Increase the maximum execution time for PHP scripts
php_value[max_execution_time] = 600

答案2

也许 IDPS 使用 suricata。Suricata 对数据包进行深度检查,并且可以与 cf 集成

#!/bin/bash

# Cloudflare API credentials
CF_API_KEY="your_api_key"
CF_API_EMAIL="[email protected]"
CF_ZONE_ID="your_zone_id"

# Suricata log path
SURICATA_LOG_PATH="/var/log/suricata/eve.json"

# Install Suricata
sudo apt-get update
sudo apt-get install suricata -y

# Enable Suricata service
sudo systemctl enable suricata
sudo systemctl start suricata

# Backup the original Suricata configuration file
sudo cp /etc/suricata/suricata.yaml /etc/suricata/suricata.yaml.bak

# Modify Suricata configuration for basic setup
sudo sed -i 's|#default-rule-path: /etc/suricata/rules|default-rule-path: /etc/suricata/rules|' /etc/suricata/suricata.yaml
sudo sed -i 's|#rule-files:|rule-files:|' /etc/suricata/suricata.yaml
sudo sed -i 's|#  - suricata.rules|  - suricata.rules|' /etc/suricata/suricata.yaml

# Download a basic set of Suricata rules
sudo suricata-update enable-source et/open
sudo suricata-update

# Restart Suricata to apply changes
sudo systemctl restart suricata

# Configure Logpush for Suricata logs with Cloudflare
echo "cloudflare:
  token: $CF_API_KEY
  email: $CF_API_EMAIL
  zone: $CF_ZONE_ID
  dataset: suricata" | sudo tee -a /etc/suricata/suricata.yaml

# Restart Suricata to apply Logpush configuration
sudo systemctl restart suricata

echo "Suricata installed, configured, and integrated with Cloudflare DDoS prevention."

然后你可以配置一些IDPS规则

#!/bin/bash

# Cloudflare API credentials
CF_API_KEY="your_api_key"
CF_API_EMAIL="[email protected]"
CF_ZONE_ID="your_zone_id"

# Path to Suricata custom rules directory
CUSTOM_RULES_DIR="/etc/suricata/rules/custom"

# Create custom rules directory if it doesn't exist
sudo mkdir -p "$CUSTOM_RULES_DIR"

# Create a custom rule file (e.g., custom-ddos.rules)
sudo tee "$CUSTOM_RULES_DIR/custom-ddos.rules" > /dev/null <<'EOF'
# Custom rule to detect and log potential DDoS-like behavior and notify Cloudflare
alert ip any any -> any any (msg:"Potential DDoS-like Behavior"; \
                          threshold: type limit, track by_src, seconds 60, count 100, \
                          sid:1000001; \
                          flowbits: set,ddos_detected; \
                          flowbits: set,cf_notify;)

alert ip any any -> any any (msg:"DDoS Detection: Log and Notify Cloudflare"; \
                          flowbits: isset,ddos_detected; \
                          flowbits: isset,cf_notify; \
                          metadata: cloudflare_rule_id 123456; \
                          flowbits: unset,cf_notify; \
                          flowbits: unset,ddos_detected; \
                          flowbits: set,cf_logged; \
                          sid:1000002;)
EOF

# Restart Suricata to apply the new rule
sudo systemctl restart suricata

echo "Custom DDoS prevention rule added."

# Logpush endpoint
LOGPUSH_ENDPOINT="https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/logpush/jobs"

# Log to Cloudflare when DDoS-like behavior is detected
tail -n0 -F /var/log/suricata/eve.json | while read -r line; do
    if echo "$line" | grep -q "flowbits: set,cf_logged"; then
        continue
    fi

    if echo "$line" | grep -q "flowbits: set,ddos_detected"; then
        # Log to Cloudflare using Logpush API
        curl -X POST "$LOGPUSH_ENDPOINT" \
            -H "X-Auth-Key: $CF_API_KEY" \
            -H "X-Auth-Email: $CF_API_EMAIL" \
            -H "Content-Type: application/json" \
            --data-raw "{\"fields\": {\"message\": \"$line\"}}"

        # Set flowbit to indicate that the log has been sent to Cloudflare
        sudo echo "$line" | suricatasc -c "flowbit-set,cf_logged"
    fi
done

您还可以添加针对 http 流量的规则

alert tcp any any -> $HOME_NET 80 (msg: "Possible DDoS attack"; flags: S; flow: stateless; threshold: type both, track by_dst, count 200, seconds 1; sid:1000001; rev:1; \
    flowbits: set,ddos_detected; flowbits: set,cf_notify; flowbits: set,drop_traffic;)

相关内容