---
title: "使用宝塔面板受到CC攻击后自动开启 Cloudflare 经典的 5 秒盾"
date: 2023-07-09T19:21:00+00:00
tags: [cloudflare]
---

项目地址：[https://github.com/csh733/autouam_control](https://github.com/csh733/autouam_control)

**原理：** 通过检测系统负载（cpu 或 load）自动开启 Cloudflare UAM 和 challenge（验证码）

## 宝塔面板计划任务

复制下面的脚本代码，使用前修改以下配置值，放在计划任务的 shell 脚本之中。

```bash
#!/bin/bash

# --------------------------使用前修改以下配置值--------------------------

mode="load"
# 两种模式可选，一：load (负载) 二：cpu。建议选 load

challenge="1"
# 是否同时开启验证码质询 设为1即开启。建议开启

keeptime="180"
# ≈开盾最小时间，如60 则开盾60秒内负载降低不会关，60秒后关。建议值 180

interval="1"
# 检测间隔时间，默认0.5秒。建议设为1

email="눈_눈"
# CloudFlare 账号邮箱

api_key="눈_눈"
# CloudFlare API KEY

zone_id="눈_눈"
# 区域ID 在域名的概述页面获取

default_security_level="high"
# 默认安全等级 关闭UAM时将会把安全等级调整为它

check="6"
#自定义开盾阈值（非必需）。load模式建议设为CPU核心数 + 2，如4核则设为6。
#load模式填负载值 如:8  cpu模式填百分数值 如:90

# --------------------------下方无需修改--------------------------

api_url="https://api.cloudflare.com/client/v4/zones/$zone_id/settings/security_level"
# API的地址

api_url1="https://api.cloudflare.com/client/v4/zones/$zone_id/firewall/rules"
# API的地址之二

api_url2="https://api.cloudflare.com/client/v4/zones/$zone_id/filters"
# API的地址之三

# 安装依赖
if ! which jq &> /dev/null; then
    echo "jq not found!"
    if [[ -f "/usr/bin/apt-get" ]]; then
        apt-get install -y jq
    elif [[ -f "/usr/bin/dnf" ]]; then
        dnf install -y epel-release
        dnf install -y jq
    elif [[ -f "/usr/bin/yum" ]]; then
        yum install -y epel-release
        yum install -y jq
    fi
fi

for ((;;)); do
    if [[ "$mode" == "cpu" ]]; then
        check=${check:-90}
        #系统空闲时间
        TIME_INTERVAL=5
        time=$(date "+%Y-%m-%d %H:%M:%S")
        LAST_CPU_INFO=$(cat /proc/stat | grep -w cpu | awk '{print $2,$3,$4,$5,$6,$7,$8}')
        LAST_SYS_IDLE=$(echo $LAST_CPU_INFO | awk '{print $4}')
        LAST_TOTAL_CPU_T=$(echo $LAST_CPU_INFO | awk '{print $1+$2+$3+$4+$5+$6+$7}')
        sleep ${TIME_INTERVAL}
        NEXT_CPU_INFO=$(cat /proc/stat | grep -w cpu | awk '{print $2,$3,$4,$5,$6,$7,$8}')
        NEXT_SYS_IDLE=$(echo $NEXT_CPU_INFO | awk '{print $4}')
        NEXT_TOTAL_CPU_T=$(echo $NEXT_CPU_INFO | awk '{print $1+$2+$3+$4+$5+$6+$7}')

        #系统空闲时间
        SYSTEM_IDLE=$(echo ${NEXT_SYS_IDLE} ${LAST_SYS_IDLE} | awk '{print $1-$2}')
        #CPU总时间
        TOTAL_TIME=$(echo ${NEXT_TOTAL_CPU_T} ${LAST_TOTAL_CPU_T} | awk '{print $1-$2}')
        load=$(echo ${SYSTEM_IDLE} ${TOTAL_TIME} | awk '{printf "%.2f", 100-$1/$2*100}')
    else
        load=$(cat /proc/loadavg | colrm 5)
        check=${check:-$(cat /proc/cpuinfo | grep "processor" | wc -l)}
    fi

    if [[ ! -f "status.txt" ]]; then
        echo "" > status.txt
    else
        status=$(cat status.txt)
    fi

    if [[ -f "ruleid.txt" ]]; then
        ruleid=$(cat ruleid.txt)
    fi

    if [[ -f "filterid.txt" ]]; then
        filterid=$(cat filterid.txt)
    fi

    now=$(date +%s)
    time=$(date +%s -r status.txt)

    echo "当前$mode负载:$load"
    if [[ $status -eq 1 ]]; then
        echo "UAM ON!"
        if [[ "$challenge" -eq 1 ]]; then
            echo "Challenge ON!"
        fi
    else
        echo "UAM OFF!"
        if [[ "$challenge" -eq 1 ]]; then
            echo "Challenge OFF!"
        fi
    fi

    newtime=$(expr $now - $time)
    closetime=$(expr $keeptime - $newtime)

    if [[ $(awk 'BEGIN {print ('$load'<'$check') ? 1:0}') -eq 1 ]] && [[ $status -eq 1 ]] && [[ $newtime -gt $keeptime ]]; then
        echo -e "\n$mode负载低于$check，当前已开盾超过规定时间$newtime秒，尝试调整至默认安全等级（$default_security_level）"
        # Disable Under Attack Mode
        result=$(curl -X PATCH "$api_url" \
            -H "X-Auth-Email: $email" \
            -H "X-Auth-Key: $api_key" \
            -H "Content-Type: application/json" \
            --data "{
                \"value\": \"$default_security_level\"
            }" --silent \
        | jq -r '.success')
        if [[ "$result" = "true" ]]; then
            echo 0 > status.txt
            echo -e "\n成功"
        fi
        if [[ "$challenge" -eq 1 ]]; then
            result=$(curl -X DELETE "$api_url1/$ruleid" \
                -H "X-Auth-Email: $email" \
                -H "X-Auth-Key: $api_key" \
                -H "Content-Type: application/json" \
                --silent)
            result1=$(curl -X DELETE "$api_url2/$filterid" \
                -H "X-Auth-Email: $email" \
                -H "X-Auth-Key: $api_key" \
                -H "Content-Type: application/json" \
                --silent)
            if echo $result | jq -e '.success' && echo $result1 | jq -e '.success'; then
                echo -e "\n验证码关闭成功"
            fi
        fi
    elif [[ $(awk 'BEGIN {print ('$load'<'$check') ? 1:0}') -eq 1 ]]; then
        echo -e "\n$mode负载低于$check，不做任何改变，状态持续了$newtime秒"
        if [[ $status -eq 1 ]]; then
            echo -e "将于$closetime秒后调整安全等级至$default_security_level"
        fi
    elif [[ $(awk 'BEGIN {print ('$load'>'$check') ? 1:0}') -eq 1 ]] && [[ $status -eq 1 ]] && [[ $newtime -gt $keeptime ]]; then
        echo -e "\n$mode负载高于$check，当前已开启UAM超过$keeptime秒，UAM无效"
    elif [[ $(awk 'BEGIN {print ('$load'>'$check') ? 1:0}') -eq 1 ]] && [[ $status -eq 1 ]]; then
        echo -e "\n$mode负载高于$check，当前已开启($newtime秒)，请再观察"
    elif [[ $(awk 'BEGIN {print ('$load'>'$check') ? 1:0}') -eq 1 ]]; then
        echo -e "\n$mode负载高于$check，开启UAM"
        # Enable Under Attack Mode
        result=$(curl -X PATCH "$api_url" \
            -H "X-Auth-Email: $email" \
            -H "X-Auth-Key: $api_key" \
            -H "Content-Type: application/json" \
                --data "{
                    \"value\": \"under_attack\"
                }" --silent \
        | jq -r '.success')
        if [[ "$result" = "true" ]]; then
            echo 1 > status.txt
            echo -e "\n成功"
        fi
        if [[ "$challenge" -eq 1 ]]; then
            while :; do
                result=$(curl -X POST "$api_url2" \
                    -H "X-Auth-Email: $email" \
                    -H "X-Auth-Key: $api_key" \
                    -H "Content-Type: application/json" \
                    --data '[{
                        "expression": "(not cf.client.bot)"
                    }]' --silent)
                if echo $result | jq -e '.success'; then
                    filterid=$(echo $result | jq -r '.result[].id')
                else
                    filterid=$(echo $result | jq -r '.errors[].meta.id')
                    for i in $filterid; do
                        result1=$(curl -X DELETE "$api_url2/$i" \
                            -H "X-Auth-Email: $email" \
                            -H "X-Auth-Key: $api_key" \
                            -H "Content-Type: application/json" --silent)
                    done
                    if echo $result1 | jq -e '.success'; then
                        echo "\n冲突的filter删除成功"
                    fi
                fi
                echo $result | jq -e '.success' && break
            done
            result=$(curl -X POST "$api_url1" \
                -H "X-Auth-Email: $email" \
                -H "X-Auth-Key: $api_key" \
                -H "Content-Type: application/json" \
                --data "[{
                    \"action\": \"challenge\",
                    \"filter\": {
                        \"id\": \"$filterid\",
                        \"expression\": \"(not cf.client.bot)\"
                    }
                }]" --silent)
            if echo $result | jq -e '.success'; then
                ruleid=$(echo $result | jq -r '.result[].id')
                echo "$filterid" > filterid.txt
                echo "$ruleid" > ruleid.txt
                echo -e "验证码开启成功，规则id：$ruleid"
            fi
        fi
    else
        echo 0 > status.txt
    fi
    sleep $interval
    clear
done
```
