MENU

DDNS + 动态白名单,云服务器再也不怕被暴力入侵登录了

随着云计算技术的快速发展,越来越多的企业和个人用户选择将业务部署到云端。然而,云服务器的安全性问题却时刻威胁着用户的数据和业务安全,尤其是暴力破解攻击。这类攻击通过不断尝试各种密码组合,犹如数字化的"开锁匠"在轮番试探门锁构造,最终获取服务器的控制权限。如果服务器的安全策略设置不当,攻击者很可能在短时间内入侵服务器,进而造成业务中断、数据泄露等严重后果。

云服务器暴露在公网时,SSH 端口常常会遭遇暴力破解攻击。传统固定 IP 白名单方案虽然安全,但难以应对家庭宽带动态 IP 的变化。本文将介绍一种动态 DDNS + 防火墙白名单自动化更新的组合方案,既能享受家庭网络的灵活性,又能保障服务器安全。

相关名词解释

DNS(域名解析系统)

如果把互联网比作快递网络,DNS 就是那个总爱碎碎念的派件员捧着厚厚的地址簿,能把 "http://www.你家小区.com" 翻译成精确的经纬度坐标(IP 地址)。不过这位快递员患有严重强迫症,非得把全球 53 台根服务器当圣经供着,每次查地址都要从北美、欧洲、亚洲的 "分舵" 逐级请示,活像在玩一场数字版的传话游戏。

DDNS(动态域名解析)

在家庭或者一些特殊的网络环境中,运营商一般只提供动态 IP 地址,这就意味着你的 IP 地址可能经常变动。这时候 DDNS 提着智能手电筒登场了。它专治那些爱玩捉迷藏的宽带 IP,比如你家光猫每次重启就换个身份证号(公网IP),这货就如同一名居家侦探,一旦检测到 IP 变脸,立马给 DNS 总部发加密电报,其反应速度比小区物业换告示栏还快,堪称 IP 界的变色龙。

安全组、防火墙

至于安全组,它其实是云计算世界的夜店保安。这位保安手持激光扫描仪(五元组过滤规则),对进出包厢(云服务器)的客人查得那叫一个细致 —— 不仅要看邀请函(源 IP)是不是 VIP 名单上的,还得确认你带的伴手礼(端口号)是不是 82 年的拉菲(22号端口)。

方案核心逻辑

  1. 动态 DNS(DDNS)
    通过 ddns-go 工具将家庭宽带的动态 IP 实时绑定到域名
  2. 自动化更新白名单
    编写脚本定期获取域名解析的 IP,并动态更新云服务器防火墙安全组规则,仅允许该 IP 访问敏感端口(如 SSH 的 22 端口)

方案优势与适用场景

该方案通过动态 IP 绑定与自动化规则更新的双重机制,用最小的运行维护成本,实现了:

  • IP 捉迷藏终结者:宽带重启换 IP?DDNS 秒级锁定,安全组自动「换锁」
  • 暴力破解克星:SSH 等敏感端口从「全网裸奔」变「定向 SSVIP 通道」
  • 零硬件投入:家庭宽带+云服务器+开源工具,低成本打造堪比企业级防护
  • 扩展性强:可结合 Webhook 实现多云同步、二次认证、告警通知等增强功能

适用于开发者个人服务器、小微企业级应用、IoT 设备远程管理等场景,特别适合需要兼顾成本与安全的中小规模云端业务。

具体实现步骤

本文以阿里云服务器为例,其他云服务商同理。

1. 本地部署 DDns-Go 动态解析

DDns-Go 是一个简单易用的动态域名解析(DDNS)工具,支持将您的公网 IPv4/IPv6 地址自动解析到多个域名服务商。适用于家庭服务器、NAS 等需要动态更新域名的场景。

  1. DDns-Go Releases 页面下载对应系统的二进制文件
  2. 解压后运行,安装 DDns-Go 服务
# Mac/Linux:
sudo ./ddns-go -s install -f 10 -cacheTimes 180 -c ./ddns_go_config.yaml

# Windows(以管理员打开 CMD):
ddns-go.exe -s install -f 10 -cacheTimes 180 -c ./ddns_go_config.yaml
  1. 浏览器访问 DDns-Go Web 配置界面
  2. 在 DDns-Go Web 配置界面中按照提示,设置域名提供商、API 密钥、域名等配置信息

2. 创建阿里云自定义权限策略

  1. 访问 阿里云 RAM 权限策略
  2. 创建自定义权限策略:
    名称:ModifySecurityGroupRuleForDDns
    备注:修改安全组规则 for DDNS
    内容:先转到 脚本编辑,替换为以下配置代码,然后转到 可视化编辑 根据实际情况进行微调
{
  "Version": "1",
  "Statement": [
      {
          "Effect": "Deny",
          "Action": [
              "ecs:AuthorizeSecurityGroup",
              "ecs:ConfigureSecurityGroupPermissions",
              "ecs:ModifySecurityGroupRule"
          ],
          "Resource": "*",
          "Condition": {
              "ForAnyValue:StringLike": {
                  "ecs:SecurityGroupSourceCidrIps": [
                      "0.0.0.0/0"
                  ]
              }
          }
      },
      {
          "Effect": "Deny",
          "Action": [
              "ecs:CreateInstance",
              "ecs:RunInstances"
          ],
          "Resource": "*",
          "Condition": {
              "Bool": {
                  "ecs:NotSpecifySecurityGroupId": [
                      "true"
                  ]
              }
          }
      },
      {
          "Effect": "Allow",
          "Action": [
              "ecs:ModifySecurityGroupRule",
              "ecs:DescribeSecurityGroupAttribute"
          ]
      }
  ]
}

3. 创建阿里云 RAM 用户

  1. 访问 阿里云 RAM 用户
  2. 创建用户,勾选 使用永久 AccessKey 访问
  3. 复制 AccessKey IDAccessKey Secret 备用
  4. 找到 权限管理,新增并授予刚刚创建的 ModifySecurityGroupRuleForDDns 自定义权限策略

4. 云服务器安装 jq 命令行工具

jq 是一个轻量级且无依赖的命令行 JSON 处理器,能够极大的降低后续编写 Shell 脚本的难度。

建议通过包管理器安装,其他安装方式详见 jq 官方文档

# Ubuntu/Debian
sudo apt update && sudo apt install jq

# CentOS/RHEL
sudo yum install epel-release && sudo yum install jq

# Fedora(或 CentOS 8+)
sudo dnf install jq

# 运行简单测试命令验证功能,应输出 "万里淘知"
echo '{"name": "万里淘知"}' | jq '.name'

5. 云服务器安装阿里云 CLI

阿里云命令行工具 CLI(Alibaba Cloud CLI)是基于阿里云开放 API 建立的管理工具。

阿里云自研系统一般会预装该工具,如发现未预装可根据 阿里云命令行工具 CLI 官方文档-阿里云帮助中心) 自行安装。

阿里云 CLI 安装完成后,按照官方文档配置身份凭证:

aliyun configure set \
  --profile AkProfile-DDns \
  --mode AK \
  --access-key-id **** \           # 替换为之前复制的 AccessKey ID
  --access-key-secret **** \   # 替换为之前复制的 AccessKey Secret
  --region ****                           # 指定默认区域的 Region Id

6. 新增默认安全组规则

由于并没有给脚本 RAM 用户添加新增安全组规则权限,需要手动新增一条默认安全组规则,脚本将只获取这条安全组规则,然后自动修改该条安全组规则内容,不会影响到自己设置的其他安全组规则。

由于我为了省事,是直接安全组入方向对自己开放所有协议的所有端口:

授权策略 ="Accept"
优先级  =1
协议类型 ="ALL"
端口范围 ="-1/-1"
描述   ="DDnsAutoUpdate" # 这个不要与其他规则备注重复,作为脚本获取规则 ID 时的判断依据

7. 部署自动更新脚本

在云服务器合适的地方新建一个 DDnsAutoUpdate.sh 文件,内容粘贴下面的核心代码即可。注意修改相关配置信息与上面新增的那条默认安全组规则配置内容一致,否则可能无法正确获取到需要修改的规则 ID

#!/bin/bash

# ------------------ 全局配置参数 ------------------
ALIYUN_PROFILE="AkProfile-DDns"                          # 阿里云 CLI 配置名称
ALIYUN_REGION_ID="cn-hangzhou"                         # 云资源所在区域
SECURITY_GROUP_ID="sg-****"                                # 安全组 ID
DNS_NAME="v4.ddns.example.com"                       # 动态 DNS 记录名称
IP_STORE_FILE="/tmp/ddns_last_ip_record.txt"    # IP 存储文件路径

# 安全组规则特征
RULE_POLICY="Accept"                 # 授权策略
RULE_PRIORITY=1                          # 规则优先级
RULE_IP_PROTOCOL="ALL"           # 协议类型
RULE_PORT_RANGE="-1/-1"          # 端口范围
RULE_NIC_TYPE="internet"            # 网络类型
RULE_DIRECTION="ingress"           # 规则方向
RULE_DESCRIPTION="DDnsAutoUpdate"    # 规则描述

# ------------------ 功能实现部分 ------------------
# 使用DOH获取DNS记录(IPv4)
NOW_DNS=$(curl -sLG --connect-timeout 5 --max-time 7 \
  -H "accept: application/dns-json" \
  "https://doh.pub/dns-query?name=${DNS_NAME}&type=A" || {
    echo "错误: DNS 查询失败"
    exit 1
})

# 提取并严格验证IP格式
NOW_IP=$(echo "${NOW_DNS}" | jq -r '.Answer[0].data  // empty' 2>/dev/null)
if [[ -z "${NOW_IP}" ]]; then
  echo "错误: 未找到有效的 DNS 记录"
  exit 1
fi

# IP 格式验证(正则表达式+分段值校验)
if ! [[ "${NOW_IP}" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; then
  echo "错误: 无效 IP 格式 - ${NOW_IP}"
  exit 1
fi

IFS='.' read -ra IP_SEGMENTS <<< "${NOW_IP}"
for SEG in "${IP_SEGMENTS[@]}"; do
  if ((SEG > 255)); then
    echo "错误: IP 段值超出范围 - ${NOW_IP}"
    exit 1
  fi
done

echo "信息: 当前解析 IP - ${NOW_IP}"

# ------------------ IP 变化检测 ------------------
LAST_IP=""
if [[ -f "${IP_STORE_FILE}" ]]; then
  LAST_IP=$(cat "${IP_STORE_FILE}")
fi

if [[ "${NOW_IP}" == "${LAST_IP}" ]]; then
  echo "信息: IP 未变化,无需更新"
  exit 0
fi

# ------------------ 阿里云配置切换 ------------------
if ! aliyun configure switch --profile "${ALIYUN_PROFILE}" &>/dev/null; then
  echo "错误: 阿里云 Profile 切换失败"
  exit 1
fi

# ------------------ 安全组规则查询 ------------------
READ_RULES_CMD=(
  aliyun ecs DescribeSecurityGroupAttribute
    --RegionId "${ALIYUN_REGION_ID}"
    --SecurityGroupId "${SECURITY_GROUP_ID}"
    --NicType "${RULE_NIC_TYPE}"
    --Direction "${RULE_DIRECTION}"
)

RULES=$("${READ_RULES_CMD[@]}" 2>&1) || {
  echo "错误: 安全组规则查询失败 - ${RULES}"
  exit 1
}

# ------------------ 规则 ID 提取 ------------------
RULE_ID=$(echo "${RULES}" | jq -r \
    --arg proto   "${RULE_IP_PROTOCOL}" \
    --arg ports   "${RULE_PORT_RANGE}" \
    --arg desc_pat "${RULE_DESCRIPTION}" \
    '
    .Permissions.Permission[] |
    select(
        .IpProtocol == $proto and
        .PortRange == $ports and
        ((.Description // "") | tostring | contains($desc_pat))
    ) | .SecurityGroupRuleId' | head -n1)
if [[ -z "$RULE_ID" ]]; then
    echo "错误:未找到符合条件的安全组规则"
    echo "信息:${RULES}"
    exit 1
fi

echo "信息: 目标规则 ID - ${RULE_ID}"

# ------------------ 安全组规则更新 ------------------
MODIFY_RULE_CMD=(
  aliyun ecs ModifySecurityGroupRule
    --RegionId "${ALIYUN_REGION_ID}"
    --SecurityGroupId "${SECURITY_GROUP_ID}"
    --SecurityGroupRuleId "${RULE_ID}"
    --Policy "${RULE_POLICY}"
    --Priority "${RULE_PRIORITY}"
    --IpProtocol "${RULE_IP_PROTOCOL}"
    --SourceCidrIp "${NOW_IP}"
    --Description "${RULE_DESCRIPTION}"
)

echo "信息: 正在更新安全组规则 ..."
OUTPUT=$("${MODIFY_RULE_CMD[@]}" 2>&1) || {
  echo "错误: 规则更新失败 - ${OUTPUT}"
  exit 1
}

# ------------------ 更新后处理 ------------------
echo "${NOW_IP}" > "${IP_STORE_FILE}"
echo "成功: 安全组规则已更新,新IP - ${NOW_IP}"

8. 测试与应用

运行 Shell 脚本查看执行情况,如果一切正常的就将其添加到定时计划任务中。

阿里云 Workbench 远程连接工具

访问 阿里云 Workbench 远程连接工具,直接按照上图的位置找到计划任务添加定时任务即可。如果有啥其他细节不明白可以直接询问 AI 终端助手。

写在最后

云服务器安全就像一场「攻防游击战」——攻击者四处试探,防守方见招拆招。与其被动加固「城墙」,不如让安全策略学会「动态隐身」!

你在实践中有过怎样的神操作呢?评论区等你来 Battle!

返回文章列表 文章二维码 打赏
本页链接的二维码
打赏二维码
添加新评论

请注意:提交内容均经由站长手动审核,请勿提交违规内容!