mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
5122 字
14 分钟
BGP安全与路由信任:互联网路由为什么可以被劫持
2022-04-27

BGP与域间路由 中,看到了 BGP 如何让上万个自治系统按策略交换路由信息。但有一个问题始终悬而未决:BGP 信任一切。当 AS65002 向你通告”202.97.0.0/16 归我”时,你的路由器不会问”你凭什么?“——它直接把这条路由装进路由表。这种无验证的信任模型,让 BGP 成为互联网最大的单点信任缺陷。一次配置错误可以让半个互联网断线,一次恶意通告可以把别国流量绕道到自己网络。

本章从 BGP 信任模型的根本缺陷出发,分析 BGP 劫持攻击的类型与真实案例,再深入 RPKI、BGPsec、路由泄漏防护等安全方案的原理与部署现状,最后通过 RPKI 验证实验将理论落地。理解了这些,你才能回答一个关键问题:互联网的路由,到底还能不能信?

一、BGP的信任模型缺陷#

1.1 无认证的路由通告#

BGP 的核心假设是:所有 BGP 发言人都是诚实的。当一台路由器收到 BGP UPDATE 消息时,它只检查 AS_PATH 是否包含自己的 ASN(防环),从不验证通告方是否有权通告该前缀。换句话说:

  • 任何 AS 都可以声称自己是 8.8.8.0/24 的起源 AS
  • 任何 AS 都可以在 AS_PATH 中伪造经过的 AS 序列
  • 任何 AS 都可以通告比合法前缀更长的子前缀(/25 vs /24),利用最长前缀匹配”抢走”流量

这不是设计疏忽,而是历史遗留。BGP 设计于 1989 年(RFC 1105),当时的互联网是一个小型学术网络,参与者互相认识、互相信任。30 年后,互联网有 7 万多个 AS,参与者从国家级运营商到不知名的空壳公司,但 BGP 的信任模型没有变。

1.2 信任缺陷的三个层面#

flowchart TB subgraph 缺陷一["缺陷一:起源验证"] A1["AS X 通告前缀 P"] --> A2["谁有权通告 P?"] A2 --> A3["BGP 不检查 "] end subgraph 缺陷二["缺陷二:路径验证"] B1["AS_PATH: 65001 65002 65003"] --> B2["路由真的经过这些 AS?"] B2 --> B3["BGP 不验证 "] end subgraph 缺陷三["缺陷三:策略验证"] C1["AS X 向全球通告从 Peer 学到的路由"] --> C2["这违反了商业协议吗?"] C2 --> C3["BGP 不关心 "] end 缺陷一 --> 劫持["路由劫持"] 缺陷二 --> 伪造["路径伪造"] 缺陷三 --> 泄漏["路由泄漏"] style 缺陷一 fill:#ffebee,stroke:#c62828 style 缺陷二 fill:#fff3e0,stroke:#e65100 style 缺陷三 fill:#fce4ec,stroke:#880e4f style 劫持 fill:#ffcdd2,stroke:#c62828 style 伪造 fill:#ffe0b2,stroke:#e65100 style 泄漏 fill:#f8bbd0,stroke:#880e4f

这三个缺陷对应三类安全问题:

信任缺陷安全问题修复方案
起源无法验证前缀劫持:任何人声称拥有任何前缀RPKI(起源验证)
路径无法验证AS_PATH 伪造:路径中的 AS 序列可以被篡改BGPsec(路径验证)
策略无法验证路由泄漏:违反商业协议的通告RFC 9234 BGP Roles / MANRS
Note

这三个缺陷不是并列的,而是递进的。起源验证(RPKI)解决”谁有权通告这个前缀”,是最基础的——如果连起源都不可信,路径验证就无从谈起。路径验证(BGPsec)解决”路由是否真的经过了这些 AS”,依赖起源验证作为基础。策略验证(路由泄漏防护)解决”通告是否违反商业协议”,在前面两者之上进一步约束行为。

二、BGP劫持攻击类型#

2.1 四种劫持类型#

劫持类型手法隐蔽性影响范围检测难度
前缀劫持(Prefix Hijack)通告他人拥有的精确前缀,伪造 AS_PATH低——合法源也在通告同前缀全球——两条竞争路由容易——可见路由翻动
子前缀劫持(Sub-prefix Hijack)通告更长的子前缀(如 /25 代替 /24)高——最长前缀匹配保证流量走劫持路由全球——流量被”黑洞”或绕道较难——合法前缀仍在,但流量不走它
AS_PATH 伪造在 AS_PATH 中插入或删除 AS中——需要分析路径合理性有限——影响选路决策中等——需要路径分析
路由泄漏(Route Leak)违反商业策略通告路由(如把 Peer 路由当 Transit 通告)低——路径异常可见不定——可能影响全球或局部较易——AS_PATH 可见策略违规
flowchart LR subgraph 正常["正常路由"] V["受害者 AS100<br/>通告 203.0.113.0/24"] R["全球路由器<br/>AS_PATH: 100"] V -->|"合法通告"| R end subgraph 前缀劫持["前缀劫持"] H1["攻击者 AS200<br/>也通告 203.0.113.0/24"] R1["部分路由器<br/>AS_PATH: 200"] H1 -->|"伪造通告"| R1 end subgraph 子前缀劫持["子前缀劫持"] H2["攻击者 AS200<br/>通告 203.0.113.128/25"] R2["所有路由器<br/>最长前缀匹配<br/>AS_PATH: 200"] H2 -->|"更精确的前缀"| R2 end style 正常 fill:#e8f5e9,stroke:#2e7d32 style 前缀劫持 fill:#fff3e0,stroke:#e65100 style 子前缀劫持 fill:#ffebee,stroke:#c62828

前缀劫持和子前缀劫持的关键区别在于最长前缀匹配。前缀劫持时,受害者和攻击者通告同一前缀,BGP 选路属性决定谁”赢”——结果不可预测,流量可能在两者间翻动。子前缀劫持时,攻击者通告更长的前缀,最长前缀匹配规则保证流量必定走攻击者的路由——除非受害者也通告同样长的子前缀。

2.2 真实案例:巴基斯坦 YouTube 劫持(2008)#

2008 年 2 月 24 日,巴基斯坦电信(AS17557)为了执行政府封禁 YouTube 的命令,在 BGP 中通告了 208.65.153.0/24——YouTube 的前缀。但配置错误导致这条路由不仅没有限制在巴基斯坦境内,还被通告给了上游提供商 PCCW(AS3491)。

由于巴基斯坦电信通告的是 /24 精确前缀(和 YouTube 一样长),而 AS_PATH 更短(只有 17557 3491 两个 AS),全球大量路由器选择了巴基斯坦电信的路径。结果:YouTube 在全球范围内断线约 2 小时。

# 事件时间线(UTC)
# 18:48 — 巴基斯坦电信开始通告 208.65.153.0/24
# 18:49 — PCCW 将该路由传播到全球 BGP 路由表
# 18:50 — YouTube 前缀的可见路由源从 1 个变为 2 个
# 20:15 — PCCW 撤销巴基斯坦电信的通告
# 20:18 — YouTube 恢复正常
# 用 BGPStream 回溯该事件(需要 BGP 历史数据)
# bgpstream -c rrc00 -w 1203948000,1203956000 -p 208.65.153.0/24

这个案例的教训:一次配置错误就能让一个国家”黑掉”全球对某个网站的访问。BGP 没有任何机制阻止 PCCW 接受并传播这条伪造路由。

2.3 真实案例:中国电信路由泄漏(2010)#

2010 年 4 月 8 日,中国电信(AS4134)向全球 BGP 路由表通告了约 37,000 条前缀——这些前缀本不该由中国电信起源。事件持续约 18 分钟,影响了全球约 15% 的路由前缀。

事后分析认为这是一次路由泄漏而非恶意劫持:中国电信的边界路由器将内部路由错误地注入了 BGP。但无论动机如何,结果是一样的——大量全球流量被错误地导向中国电信的网络。

Warning

BGP 劫持不一定是恶意的。据统计,超过 80% 的 BGP 路由事件是配置错误导致的。但恶意劫持确实存在——2018 年,某俄罗斯 AS 连续多天劫持了多个大型 CDN 和 DNS 提供商的前缀,流量被导向俄罗斯后又被正常转发(中间人攻击的典型特征)。

2.4 用 Wireshark 观察 BGP 劫持#

在 GNS3 实验环境中模拟前缀劫持,用 tshark 过滤 BGP UPDATE 观察:

# 抓取所有 BGP UPDATE 消息
sudo tshark -i eth0 -f "tcp port 179" \
-Y "bgp.message_type == 2" \
-T fields \
-e bgp.update.nlri_prefix \
-e bgp.update.as_path_segment_value \
-e bgp.update.origin
# 过滤特定前缀的 BGP 通告
sudo tshark -i eth0 -f "tcp port 179" \
-Y "bgp.message_type == 2 && bgp.update.nlri_prefix contains 203.0.113"
# 统计某个前缀的起源 AS 变化
sudo tshark -i eth0 -f "tcp port 179" \
-Y "bgp.message_type == 2" \
-T fields \
-e bgp.update.nlri_prefix \
-e bgp.update.as_path_segment_value \
| grep "203.0.113" | sort | uniq -c | sort -rn

如果同一个前缀出现两个不同的起源 AS,就是前缀劫持的信号。

三、RPKI资源公钥基础设施#

3.1 RPKI 的核心思想#

RPKI(Resource Public Key Infrastructure,资源公钥基础设施)用密码学手段回答一个简单的问题:谁有权通告这个 IP 前缀?

核心思路:IP 地址分配体系本身就是层级化的——IANA 分配给 RIR,RIR 分配给 NIR/LIR,LIR 分配给最终用户。RPKI 把这个层级化的地址分配关系映射为层级化的信任链,每一层用数字签名证明”我把这个前缀授权给了下一层”。

flowchart TB Trust["Trust Anchor<br/>IANA/IRTF 信任锚<br/>根证书 + 根密钥"] RIR1["RIR: ARIN<br/>北美地区<br/>签名: 203.0.0.0/8 → AS3356"] RIR2["RIR: RIPE NCC<br/>欧洲地区<br/>签名: 193.0.0.0/8 → AS3333"] RIR3["RIR: APNIC<br/>亚太地区<br/>签名: 202.0.0.0/8 → AS4134"] LIR1["LIR: 运营商A<br/>签名: 203.0.113.0/24 → AS64500"] LIR2["LIR: 运营商B<br/>签名: 193.1.1.0/24 → AS64501"] Trust --> RIR1 Trust --> RIR2 Trust --> RIR3 RIR1 --> LIR1 RIR2 --> LIR2 style Trust fill:#e3f2fd,stroke:#1565c0 style RIR1 fill:#e8f5e9,stroke:#2e7d32 style RIR2 fill:#e8f5e9,stroke:#2e7d32 style RIR3 fill:#e8f5e9,stroke:#2e7d32 style LIR1 fill:#fff3e0,stroke:#e65100 style LIR2 fill:#fff3e0,stroke:#e65100

3.2 ROA:路由源授权#

ROA(Route Origin Authorization,路由源授权)是 RPKI 的核心数据结构。一个 ROA 本质上是一份签名声明:“前缀 P 被授权给 AS X 通告,且最长前缀长度为 L”。

ROA 结构:
┌──────────────────────────────────────┐
│ Subject: AS64500 │
│ IP Prefix: 203.0.113.0/24 │
│ Max Length: 24 │
│ Validity: 2025-01-01 ~ 2026-12-31 │
│ Signature: [由上级 CA 签发] │
└──────────────────────────────────────┘

Max Length 字段解决子前缀劫持问题。如果 ROA 声明 203.0.113.0/24 MaxLength=24,那么 AS64500 只能通告 /24 或更短的前缀,不能通告 /25、/26 等子前缀。如果攻击者以 AS64500 的身份通告 203.0.113.128/25,RPKI 验证会判定为 Invalid。

# 使用 rpki-client 查询某个前缀的 ROA
rpki-client -d /var/db/rpki-client
# 查看验证结果
rpki-client -t /var/db/rpki-client/json
# 使用 Cloudflare 的 RPKI 查询 API
curl -s "https://rpki.cloudflare.com/api/v1/origin/203.0.113.0/24" | jq .
# 返回示例:
# {
# "validated_roas": [
# {
# "prefix": "203.0.113.0/24",
# "asn": 64500,
# "max_length": 24,
# "trust_anchor": "APNIC"
# }
# ]
# }

3.3 RPKI 验证状态#

路由器收到 BGP 通告后,将前缀与 RPKI 验证结果对照,产生三种验证状态:

验证状态含义典型场景建议动作
Valid找到匹配的 ROA,且起源 AS 和前缀长度都匹配AS64500 通告 203.0.113.0/24,ROA 授权 AS64500 通告 /24正常接受
Invalid找到匹配的 ROA,但起源 AS 不匹配或前缀长度超过 MaxLengthAS65000 通告 203.0.113.0/24,但 ROA 授权的是 AS64500丢弃或降优先级
NotFound没有找到覆盖该前缀的 ROA前缀没有注册 RPKI按原有策略处理
Note

NotFound 不等于”不安全”。很多前缀的持有者还没有注册 RPKI,所以 NotFound 是最常见的状态。截至 2025 年,全球 BGP 路由表中约 40% 的前缀仍处于 NotFound 状态。RPKI 部署是一个渐进过程——随着更多前缀注册 ROA,NotFound 比例会逐渐下降。

3.4 RPKI 部署现状#

RPKI 的部署是一个”鸡和蛋”问题:前缀持有者不注册 ROA 因为运营商不过滤,运营商不过滤因为太多前缀没有 ROA。但近几年情况在快速改善:

指标2020 年2023 年2025 年
全球 BGP 路由表条目~860K~980K~1,100K
有 ROA 的前缀比例~27%~42%~55%
执行 RPKI 过滤的 AS 比例~15%~35%~50%
Invalid 路由条目~1,500~800~500

主要推动力来自大型运营商和 CDN 的带头部署:Cloudflare、Google、Amazon、Microsoft 等都已为所有前缀注册了 ROA,并在自己的网络中执行 RPKI 过滤。APNIC 和 RIPE NCC 等区域互联网注册机构也在积极推动 RPKI 培训。

四、BGPsec与路由签名#

4.1 RPKI 的局限#

RPKI 只解决了起源验证——确认”谁有权通告这个前缀”。但它不验证 AS_PATH:路由经过哪些 AS、路径是否被篡改,RPKI 都不管。

攻击场景:AS65001 合法拥有 203.0.113.0/24(RPKI Valid),攻击者 AS69999 通告 203.0.113.0/24 AS_PATH: 69999 65001——伪造了一条”从 AS65001 经过 AS69999”的路径。RPKI 验证通过(起源 AS 确实是 65001),但 AS_PATH 中 AS69999 的存在是伪造的。

这就是 BGPsec 要解决的问题:路径验证——确保 AS_PATH 中的每一跳都真实参与了路由传播。

4.2 BGPsec 的工作原理#

BGPsec 在 BGP UPDATE 消息中增加一个 BGPsec_Path_Signature 属性,让 AS_PATH 中的每个 AS 都对路由更新进行签名:

flowchart LR AS1["AS100<br/>起源 AS<br/>签名: Sig₁<br/>(对前缀+自己的ASN签名)"] AS2["AS200<br/>转发 AS<br/>签名: Sig₂<br/>(对前缀+AS100+AS200签名)"] AS3["AS300<br/>转发 AS<br/>签名: Sig₃<br/>(对前缀+AS100+AS200+AS300签名)"] AS4["AS400<br/>接收方<br/>验证: Sig₁→Sig₂→Sig₃"] AS1 -->|"BGPsec UPDATE<br/>+Sig₁"| AS2 AS2 -->|"BGPsec UPDATE<br/>+Sig₁+Sig₂"| AS3 AS3 -->|"BGPsec UPDATE<br/>+Sig₁+Sig₂+Sig₃"| AS4 style AS1 fill:#e8f5e9,stroke:#2e7d32 style AS2 fill:#e3f2fd,stroke:#1565c0 style AS3 fill:#e3f2fd,stroke:#1565c0 style AS4 fill:#fff3e0,stroke:#e65100

每个 AS 在转发路由时,用自己的私钥对”前缀 + 之前的签名 + 自己的 ASN”进行签名。接收方从 Trust Anchor 获取每个 AS 的公钥证书,逐个验证签名链。如果 AS_PATH 中某个 AS 没有签名(或签名无效),说明路径被篡改。

4.3 BGPsec vs RPKI 对比#

维度RPKIBGPsec
验证对象起源 AS(谁有权通告前缀)AS_PATH(路由经过了哪些 AS)
安全目标前缀劫持防护路径伪造防护
密码学机制ROA(签名声明)逐跳签名链
验证位置本地 Relying Party路由器上实时验证
部署难度低(只需注册 ROA)高(需要路由器硬件支持)
性能影响极小(离线验证)较大(每跳签名+验证)
部署状态~55% 前缀覆盖极少(实验阶段)
RFC6480-64938205, 8206, 8374, 8375

4.4 为什么 BGPsec 部署这么慢#

BGPsec 从 2017 年成为标准(RFC 8205),到 2025 年几乎没有任何生产部署。原因有三:

  1. 性能开销:每个 AS 都要对 UPDATE 消息签名,路由器需要专用密码学硬件。BGP UPDATE 消息量巨大(全球每秒数万条),签名和验证的延迟可能影响收敛速度。

  2. 增量部署问题:BGPsec 要求 AS_PATH 中的每个 AS 都支持签名。如果路径中有一个 AS 不支持 BGPsec,整条路径就无法验证。在 7 万多个 AS 中,只要有一个不支持,就形成”最短木板”。

  3. 商业激励不足:RPKI 的部署由前缀持有者驱动(保护自己的前缀不被劫持),但 BGPsec 的受益者是路由的接收方而非发送方。发送方没有动力为别人的安全买单。

Tip

在 BGPsec 大规模部署之前,AS_PATH 验证的替代方案是 ASPA(Autonomous System Provider Authorization,RFC 9324)。ASPA 让 AS 声明”我的 Transit 提供商是谁”,接收方可以据此检测 AS_PATH 中的异常 AS。ASPA 比 BGPsec 轻量得多,不需要逐跳签名,正在获得更多部署关注。

五、路由泄漏防护#

5.1 RFC 7908 路由泄漏类型#

路由泄漏(Route Leak)是指 AS 违反商业协议,将路由通告给了不该通告的方向。RFC 7908 定义了六种路由泄漏类型:

类型描述场景
Type 1Stub AS 将从 Transit 提供商学到的路由通告给另一个 Transit 提供商小公司有两个上游,把从一个上学到的路由发给另一个
Type 2Stub AS 将从 Transit 提供商学到的路由通告给 Peer小公司把从上游学到的路由发给对等互联伙伴
Type 3Stub AS 将从 Peer 学到的路由通告给 Transit 提供商小公司把从对等方学到的路由发给上游
Type 4Transit AS 将从一个 Transit 学到的路由通告给另一个 Transit运营商充当了未授权的中间人
Type 5Transit AS 将从 Peer 学到的路由通告给 Transit 提供商运营商把对等方的路由发给自己的上游
Type 6Transit AS 将从一个 Transit 学到的路由通告给 Peer运营商把上游的路由发给对等互联伙伴
flowchart TB subgraph Type1["Type 1: Stub 多宿主泄漏"] direction TB T1A["Transit A"] -->|"路由"| Stub1["Stub AS"] Stub1 -->|"泄漏 "| T1B["Transit B"] end subgraph Type3["Type 3: Stub→Peer→Transit"] direction TB Peer3["Peer"] -->|"路由"| Stub3["Stub AS"] Stub3 -->|"泄漏 "| Transit3["Transit"] end subgraph Type5["Type 5: Transit→Peer→Transit"] direction TB Peer5["Peer"] -->|"路由"| T5M["Transit AS<br/>(中间人)"] T5M -->|"泄漏 "| T5U["Transit<br/>(上游)"] end style Type1 fill:#ffebee,stroke:#c62828 style Type3 fill:#fff3e0,stroke:#e65100 style Type5 fill:#fce4ec,stroke:#880e4f

所有类型的共同特征:路由被通告到了不该到达的方向,违反了 BGP与域间路由 中讨论的 AS 关系模型——Peer 不传 Transit 流量,Customer 不把 Provider 的路由传给另一个 Provider。

5.2 RFC 9234 BGP Roles#

RFC 9234 定义了 BGP 邻居关系中的角色标记,让路由器能自动检测路由泄漏:

角色含义期望行为
Provider我是对方的上游提供商可以发送全表,期望对方只发自己的前缀
Customer我是对方的下游客户只发自己的前缀,期望对方发全表
Peer双方对等互联只发自己的+客户的前缀,期望对方也一样
RSIXP 路由服务器只发客户前缀
RS-ClientIXP 路由服务器客户只发自己的前缀

BGP Roles 在 OPEN 消息中协商——双方必须对彼此的角色达成一致。如果 AS65001 标记邻居为 Customer,但对方标记 AS65001 为 Peer,OPEN 协商失败,会话无法建立。这种双向确认防止了单方面误标记。

# FRR 配置 BGP Roles
router bgp 65001
neighbor 10.0.1.2 remote-as 65002
neighbor 10.0.1.2 role provider
# 本 AS 是对方的 Provider(对方是 Customer)
neighbor 10.0.2.2 remote-as 65003
neighbor 10.0.2.2 role peer
# 双方是对等互联关系
neighbor 10.0.3.2 remote-as 65004
neighbor 10.0.3.2 role customer
# 本 AS 是对方的 Customer(对方是 Provider)

5.3 MANRS 行动倡议#

MANRS(Mutually Agreed Norms for Routing Security,路由安全互认规范)是由 Internet Society 发起的行业倡议,要求参与者实施四项基本安全措施:

  1. 过滤:验证路由通告的合法性(prefix-list + RPKI)
  2. 反欺骗:部署 BCP38/BCP84 源地址验证,防止 IP 欺骗
  3. 协调:在 RPKI 和 IRR 中维护准确的路由注册信息
  4. 全球验证:发布路由时确保其可被 RPKI 验证

截至 2025 年,全球已有超过 100 个网络运营商和 CDN 加入 MANRS。虽然 MANRS 是自愿性质的,但它正在成为行业事实标准——一些 IXP 要求成员遵守 MANRS 才能接入路由服务器。

六、BGP安全实践#

6.1 前缀列表过滤#

最基本的安全措施:只接受邻居应该通告的前缀。

# 为每个客户配置精确的前缀列表
ip prefix-list CUSTOMER-A seq 5 permit 203.0.113.0/24 le 24
ip prefix-list CUSTOMER-A seq 10 deny 0.0.0.0/0 le 32
# 为每个 Peer 配置前缀列表(只接受其自己的+客户的前缀)
ip prefix-list PEER-B seq 5 permit 198.51.100.0/22 le 24
ip prefix-list PEER-B seq 10 permit 192.0.2.0/24 le 24
ip prefix-list PEER-B seq 15 deny 0.0.0.0/0 le 32
# Bogon 过滤——拒绝不应出现在全球路由表中的前缀
ip prefix-list BOGON seq 5 deny 0.0.0.0/8 le 32
ip prefix-list BOGON seq 10 deny 10.0.0.0/8 le 32
ip prefix-list BOGON seq 15 deny 127.0.0.0/8 le 32
ip prefix-list BOGON seq 20 deny 169.254.0.0/16 le 32
ip prefix-list BOGON seq 25 deny 172.16.0.0/12 le 32
ip prefix-list BOGON seq 30 deny 192.168.0.0/16 le 32
ip prefix-list BOGON seq 35 deny 224.0.0.0/4 le 32
ip prefix-list BOGON seq 40 deny 240.0.0.0/4 le 32
ip prefix-list BOGON seq 45 permit 0.0.0.0/0 le 32
# 应用到 BGP 邻居
router bgp 65001
neighbor 10.0.1.2 prefix-list CUSTOMER-A in
neighbor 10.0.1.2 prefix-list BOGON in

6.2 Max-Prefix 限制#

防止邻居意外通告过多路由(配置错误或被攻击时):

# 限制每个邻居通告的前缀数量
router bgp 65001
# 客户通常只通告少量前缀
neighbor 10.0.1.2 maximum-prefix 10 restart 30
# 最多接受 10 条前缀,超限后断开 30 分钟后自动重连
# Peer 可能通告数千条前缀
neighbor 10.0.2.2 maximum-prefix 5000 threshold-warning 80
# 最多 5000 条,达到 80%(4000 条)时发送警告日志
# Transit 提供商通告全表(约 100 万条)
neighbor 10.0.3.2 maximum-prefix 1200000 threshold-warning 90
Warning

Max-prefix 限制是一把双刃剑。设置过低会导致正常路由被意外丢弃,设置过高则失去保护意义。建议根据邻居类型设置合理阈值,并始终启用 threshold-warning 以便提前发现问题。

6.3 IRR 过滤#

IRR(Internet Routing Registry,互联网路由注册库)是一个公开的路由策略数据库,AS 可以在其中注册自己通告的前缀和策略。IRR 过滤是最早被广泛使用的路由验证方法:

# 从 IRR 生成前缀列表(使用 bgpq3 工具)
# 安装 bgpq3
sudo apt install bgpq3
# 生成 AS64500 的前缀列表
bgpq3 -4 -l CUSTOMER-A AS64500
# 输出:
# ip prefix-list CUSTOMER-A seq 1 permit 203.0.113.0/24
# ip prefix-list CUSTOMER-A seq 2 permit 198.51.100.0/24
# 生成 FRR 格式的前缀列表
bgpq3 -4 -F 'ip prefix-list %s seq %d permit %l/%L\n' -l CUSTOMER-A AS64500
# 生成基于 AS-SET 的前缀列表(包含客户的前缀)
bgpq3 -4 -l PEER-B AS-SET:AS65002:AS-CUSTOMERS
# 自动化:用 cron 定期更新前缀列表
# 0 */6 * * * /usr/local/bin/update-prefix-lists.sh

IRR 的局限:任何人都可以在 IRR 中注册任何 AS 的路由对象——IRR 没有严格的身份验证。这意味着 IRR 数据本身可能被伪造。RPKI 通过密码学签名解决了这个问题,但 IRR 仍然比没有过滤好得多。

6.4 RPKI 过滤#

RPKI 过滤是当前最有效的路由安全措施。部署流程:

# 1. 部署 RPKI Relying Party(验证器)
# 安装 Routinator(NLnet Labs 开发的 RPKI 验证器)
cargo install routinator
# 初始化(同步 RPKI 仓库,首次需要较长时间)
routinator init
# 启动 RPKI 验证器(RTR 协议,端口 323)
routinator server --rtr 127.0.0.1:323 --http 127.0.0.1:9556
# 2. 在 FRR 中配置 RPKI 验证
router bgp 65001
# 配置 RPKI 缓存服务器连接
rpki cache 127.0.0.1 323
# 查看 RPKI 验证状态
show bgp rpki summary
# 查看特定前缀的 RPKI 验证结果
show bgp rpki prefix 203.0.113.0/24
# 3. 基于 RPKI 验证结果设置策略
router bgp 65001
# 对 Invalid 路由降优先级(而非直接丢弃,避免误伤)
neighbor 10.0.1.2 route-map RPKI-FILTER in
route-map RPKI-FILTER permit 10
match rpki invalid
set local-preference 0
# Invalid 路由优先级设为 0,不会被选为最优路径
route-map RPKI-FILTER permit 20
match rpki valid
set local-preference 200
# Valid 路由给予更高优先级
route-map RPKI-FILTER permit 30
# NotFound 路由保持默认优先级

七、动手实践:RPKI验证实验#

7.1 实验拓扑#

在 GNS3 中搭建一个简化的 RPKI 验证环境,模拟前缀劫持和 RPKI 过滤:

graph LR subgraph AS64500["AS64500 — 合法前缀持有者"] R1["R1<br/>203.0.113.1/24<br/>通告 203.0.113.0/24"] end subgraph AS69999["AS69999 — 攻击者"] R2["R2<br/>203.0.113.254/24<br/>也通告 203.0.113.0/24"] end subgraph AS65001["AS65001 — 验证方"] R3["R3<br/>边界路由器<br/>运行 FRR + RPKI"] RP["Routinator<br/>RPKI 验证器<br/>RTR :323"] R3 --- RP end R1 -->|"eBGP<br/>合法通告"| R3 R2 -->|"eBGP<br/>伪造通告"| R3 style AS64500 fill:#e8f5e9,stroke:#2e7d32 style AS69999 fill:#ffebee,stroke:#c62828 style AS65001 fill:#e3f2fd,stroke:#1565c0

7.2 部署 Routinator#

在 GNS3 的 Docker 容器中部署 RPKI 验证器:

# 安装 Rust 和 Routinator
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
cargo install routinator
# 初始化 RPKI 仓库
routinator init --accept-arin-rpa
# 启动验证器(后台运行)
routinator server \
--rtr 127.0.0.1:323 \
--http 127.0.0.1:9556 \
--refresh 600 \
&
# 验证服务运行
curl -s http://127.0.0.1:9556/api/v1/status | jq .
# 检查 "last_update" 和 "serial" 字段
# 手动查询前缀验证状态
routinator vrps --format csv | grep "203.0.113"
# ASN, Prefix, MaxLength, TrustAnchor
# 64500, 203.0.113.0/24, 24, APNIC

7.3 FRR 配置 RPKI 验证#

# R3(AS65001 边界路由器)配置
vtysh
configure terminal
# 配置 RPKI 缓存连接
rpki cache 127.0.0.1 323
preference 100
refresh-interval 600
expire-interval 7200
retry-interval 60
# 配置 BGP 会话
router bgp 65001
bgp router-id 3.3.3.3
# 与合法 AS64500 的 eBGP 会话
neighbor 10.0.13.1 remote-as 64500
neighbor 10.0.13.1 description "Legitimate origin"
# 与攻击者 AS69999 的 eBGP 会话
neighbor 10.0.23.1 remote-as 69999
neighbor 10.0.23.1 description "Potential hijacker"
# 应用 RPKI 过滤策略
neighbor 10.0.13.1 route-map RPKI-POLICY in
neighbor 10.0.23.1 route-map RPKI-POLICY in
# RPKI 过滤策略
route-map RPKI-POLICY permit 10
match rpki invalid
set local-preference 0
route-map RPKI-POLICY permit 20
match rpki valid
set local-preference 200
route-map RPKI-POLICY permit 30
match rpki not-found
set local-preference 100

7.4 验证实验结果#

# 查看 RPKI 缓存连接状态
show bgp rpki cache-server
# Cache Server State Retries Last Refresh
# 127.0.0.1:323 Up 0 2026-05-15 08:30:00
# 查看所有 RPKI 验证结果
show bgp rpki table
# Prefix AS MaxLen Source Validated
# 203.0.113.0/24 64500 24 APNIC Valid
# 查看路由表中的 RPKI 状态
show bgp ipv4 unicast 203.0.113.0/24 detail
# 预期结果:
# 从 AS64500 学到的路由:RPKI Valid, LOCAL_PREF 200 → 选为最优路径
# 从 AS69999 学到的路由:RPKI Invalid, LOCAL_PREF 0 → 不选
# 用 tshark 抓取 RTR 协议交互
sudo tshark -i lo -f "tcp port 323" \
-Y "rtr" -T fields \
-e rtr.pdu_type \
-e rtr.serial_number \
-e rtr.session_id
# 模拟 RPKI 策略变更:撤销 ROA 后观察路由变化
# 在 Routinator 中删除 AS64500 的 ROA,等待刷新
# 观察 AS64500 的路由从 Valid 变为 NotFound

7.5 模拟子前缀劫持#

# 在 R2(攻击者)上通告更长的子前缀
vtysh
configure terminal
router bgp 69999
network 203.0.113.128/25
# 在 R3 上观察路由变化
show bgp ipv4 unicast 203.0.113.128/25
# RPKI 验证结果:Invalid
# (ROA 声明 MaxLength=24,/25 超出范围)
# 验证流量走向
traceroute 203.0.113.1
# 走 AS64500(Valid,LOCAL_PREF 200)
traceroute 203.0.113.129
# 走 AS69999?不!RPKI Invalid,LOCAL_PREF 0
# 但如果 R3 没有配置 RPKI 过滤,/25 会因为最长前缀匹配被选中
# 这就是 RPKI 过滤的重要性

八、本章小结#

概念要点
BGP 信任缺陷无认证、无验证、无策略检查——任何人可以声称任何前缀
前缀劫持通告他人拥有的精确前缀,与合法路由竞争
子前缀劫持通告更长子前缀,利用最长前缀匹配”抢走”流量
AS_PATH 伪造在路径中插入或删除 AS,影响选路决策
路由泄漏违反商业策略通告路由,RFC 7908 定义 6 种类型
巴基斯坦 YouTube2008 年配置错误导致全球 YouTube 断线 2 小时
中国电信泄漏2010 年路由泄漏影响全球 15% 前缀
RPKI基于地址分配层级的签名信任链,验证前缀起源合法性
ROA路由源授权声明:前缀 P 授权给 AS X,MaxLength=L
RPKI 验证状态Valid(匹配 ROA)、Invalid(违反 ROA)、NotFound(无 ROA)
BGPsec逐跳签名验证 AS_PATH,防止路径伪造
BGPsec 部署障碍性能开销大、增量部署困难、商业激励不足
ASPA轻量级 AS_PATH 验证替代方案,声明 Transit 提供商
BGP RolesRFC 9234 邻居角色标记,自动检测路由泄漏
MANRS路由安全四项基本措施:过滤、反欺骗、协调、全球验证
前缀列表过滤只接受邻居应该通告的前缀,Bogon 过滤
Max-Prefix 限制防止邻居意外通告过多路由
IRR 过滤基于公开路由注册库的前缀验证,无密码学保护
RPKI 过滤基于 RPKI 验证结果的路由策略,Invalid 降优先级或丢弃

BGP 的信任缺陷是互联网架构的”原罪”——在信任所有参与者的假设下构建的路由系统,面对恶意行为和配置错误都毫无抵抗力。RPKI 正在逐步修复起源验证的问题,BGPsec 和 ASPA 为路径验证提供了方案,BGP Roles 和 MANRS 在策略层面增加约束。但安全永远是一个过程而非终点——每一层防护都需要持续部署和运营。

数据包在 AS 间的路由安全有了基本保障后,接下来要进入 AS 内部——运营商骨干网如何用 MPLS 标签交换和流量工程调度海量数据流?下一章 运营商骨干网与流量工程 将揭示 ISP 内部的转发机制。


参考#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

BGP安全与路由信任:互联网路由为什么可以被劫持
https://blog.souloss.com/posts/internet-architecture/bgp-security-and-routing-trust/
作者
Souloss
发布于
2022-04-27
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时