AI 产生的文章,仅供参考
Kamailio 使用 STIR/SHAKEN 的流程相对复杂,因为它需要与外部的 STIR/SHAKEN 服务(例如 Secure Telephone Identity (STI) 证书颁发机构 (CA) 和验证服务)进行集成。Kamailio 本身不执行 STIR/SHAKEN 的签名和验证过程,而是充当一个信令代理,将相关信息传递给这些外部服务。
下面是一个详细的 Kamailio 集成 STIR/SHAKEN 的流程概述,并解释了每个步骤中 Kamailio 的作用:
STIR/SHAKEN 概述
在深入 Kamailio 流程之前,先简要回顾一下 STIR/SHAKEN 的核心概念:
- STIR (Secure Telephone Identity Revisited):定义了如何使用数字证书对 SIP 呼叫的 From 字段(即主叫号码)进行签名,以证明其合法性。
- SHAKEN (Signature-based Handling of Asserted information using toKENs):定义了如何将 STIR 签名作为 SIP P-Asserted-Identity (PAI) 头的一部分进行传递和验证。
STIR/SHAKEN 流程涉及的角色:
- Originating Service Provider (OSP):发起呼叫的运营商。负责生成 STIR 签名。
- Terminating Service Provider (TSP):接收呼叫的运营商。负责验证 STIR 签名。
- STI-CA (Secure Telephone Identity Certificate Authority):颁发用于签名的证书。
- STI-VS (Secure Telephone Identity Verification Service):提供签名验证服务。
Kamailio 集成 STIR/SHAKEN 的详细流程
一、 呼叫发起方 (Originating Service Provider) 的 Kamailio 配置
在呼叫发起方,Kamailio 的主要任务是将 SIP 呼叫路由到外部的 STIR/SHAKEN 签名服务,并将签名后的结果(SHAKEN 身份声明)重新插入到 SIP 消息中。
- Kamailio 收到发起呼叫的 INVITE 消息。
- Kamailio 识别需要签名的呼叫:Kamailio 需要通过某种逻辑(例如,基于主叫号码、被叫号码或特定的路由规则)来判断哪些呼叫需要进行 STIR/SHAKEN 签名。
- Kamailio 模块:可以使用
drouting、dispatcher或自定义脚本逻辑来实现。
- Kamailio 模块:可以使用
- Kamailio 将呼叫信息发送到外部 STIR/SHAKEN 签名服务:
- 如何发送:这通常通过 SIP INVITE 的 REFER 方法、HTTP 请求(如果签名服务提供 REST API)或专门的 Kamailio 模块与外部服务进行交互。
- 使用 REFER:Kamailio 可以向签名服务发送一个 REFER 消息,其中包含需要签名的 SIP INVITE 的相关信息。签名服务收到 REFER 后,进行签名,然后将签名后的 INVITE 返回给 Kamailio。
- 使用 HTTP 模块:如果签名服务提供 HTTP/REST API,Kamailio 可以使用
htable或json模块构造 HTTP 请求,将相关呼叫数据发送给签名服务,并解析签名服务返回的响应。 - 自定义模块/脚本:编写一个 Kamailio C 模块或使用
lua模块与签名服务进行更复杂的交互。
- 发送的内容:主要包括主叫号码 (From Header)、被叫号码 (To Header) 和其他必要的 SIP 头信息。
- 如何发送:这通常通过 SIP INVITE 的 REFER 方法、HTTP 请求(如果签名服务提供 REST API)或专门的 Kamailio 模块与外部服务进行交互。
- 外部 STIR/SHAKEN 签名服务的工作流程:
- 接收到 Kamailio 发送的呼叫信息。
- 向 STI-CA 请求证书(如果尚未缓存)。
- 使用私钥和从 STI-CA 获取的证书对呼叫信息进行数字签名。
- 将生成的 SHAKEN 身份声明(通常是一个 JSON Web Token (JWT))封装在 SIP P-Asserted-Identity (PAI) 头中,或者作为新的 SIP 头(例如
Identity头)返回给 Kamailio。
- Kamailio 接收签名结果:
- Kamailio 接收来自签名服务的响应(例如,新的 SIP INVITE 消息或包含 SHAKEN 声明的 HTTP 响应)。
- Kamailio 将 SHAKEN 身份声明插入 SIP 消息:
- Kamailio 解析接收到的 SHAKEN 身份声明。
- Kamailio 将其作为
Identity头字段(通常在 SIP INVITE 消息中)添加到原始的 SIP INVITE 消息中。Identity: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdHRlc3QiOiJBIiwib3JpZyI6eyJ0ZWwiOiIrMSAxMTExNTU1MTIxMiJ9LCJkZXN0Ijp7InRlbCI6WyIrMSAxMTExNTU1MTIyMiJdfSwiaW ... - Kamailio 函数:可以使用
insert_hf()或append_hf()函数来添加Identity头。
- Kamailio 将带有签名的 INVITE 消息转发到下一个跳。
二、 呼叫接收方 (Terminating Service Provider) 的 Kamailio 配置
在呼叫接收方,Kamailio 的主要任务是接收带有 SHAKEN 身份声明的 SIP 呼叫,将其路由到外部的 STIR/SHAKEN 验证服务,并根据验证结果决定如何处理呼叫。
- Kamailio 收到带有
Identity头的 INVITE 消息。 - Kamailio 识别需要验证的呼叫:Kamailio 需要通过检查 SIP 消息中是否存在
Identity头来判断该呼叫是否需要进行 STIR/SHAKEN 验证。- Kamailio 函数:
is_present_hf("Identity")
- Kamailio 函数:
- Kamailio 将呼叫信息发送到外部 STIR/SHAKEN 验证服务:
- 如何发送:同样可以通过 REFER、HTTP 请求或专门的 Kamailio 模块与外部验证服务进行交互。
- 使用 REFER:Kamailio 向验证服务发送 REFER 消息,包含 SIP INVITE 的相关信息(特别是
Identity头)。验证服务进行验证,然后将验证结果(例如,验证通过/失败,Attestation Level 等)返回给 Kamailio。 - 使用 HTTP 模块:Kamailio 构造 HTTP 请求,将
Identity头的内容发送给验证服务。
- 使用 REFER:Kamailio 向验证服务发送 REFER 消息,包含 SIP INVITE 的相关信息(特别是
- 发送的内容:主要包括
Identity头的内容、主叫号码、被叫号码等。
- 如何发送:同样可以通过 REFER、HTTP 请求或专门的 Kamailio 模块与外部验证服务进行交互。
- 外部 STIR/SHAKEN 验证服务的工作流程:
- 接收到 Kamailio 发送的呼叫信息和
Identity头。 - 解析
Identity头中的 JWT。 - 从 JWT 中提取证书信息。
- 向 STI-CA 验证证书的有效性。
- 验证签名是否正确,以及主叫号码是否与签名信息匹配。
- 根据验证结果,生成一个验证报告(例如,Attestation Level A, B, C 或 FAILED)。
- 将验证结果(例如,Attestation Level 和/或详细的错误信息)返回给 Kamailio。
- 接收到 Kamailio 发送的呼叫信息和
- Kamailio 接收验证结果:
- Kamailio 接收来自验证服务的响应。
- Kamailio 根据验证结果处理呼叫:
- Kamailio 变量:将验证结果存储在 Kamailio 伪变量中,例如
$var(stir_shaken_status)。 - 决策逻辑:Kamailio 根据
$var(stir_shaken_status)的值来决定下一步操作:- 验证通过 (Attestation A/B/C):正常路由呼叫。可以在 SIP 消息中添加额外的头(例如
X-Attestation-Level: A)以便下游系统识别。 - 验证失败 (Attestation FAILED):
- 拒绝呼叫 (e.g.,
sl_send_reply("403", "Forbidden"))。 - 将呼叫路由到语音邮件。
- 将呼叫路由到欺诈检测系统。
- 对呼叫进行降级处理(例如,播放警告音)。
- 记录详细的日志。
- 拒绝呼叫 (e.g.,
- 没有
Identity头或无法联系验证服务:视为未验证,根据运营商策略进行处理(例如,路由,但标记为低信任度)。
- 验证通过 (Attestation A/B/C):正常路由呼叫。可以在 SIP 消息中添加额外的头(例如
- Kamailio 函数:使用
if()语句和route()函数进行条件路由。
- Kamailio 变量:将验证结果存储在 Kamailio 伪变量中,例如
Kamailio 配置示例(伪代码,仅供参考,实际配置会更复杂):
呼叫发起方 (OSP) Kamailio.cfg 片段:
# ... 其他 Kamailio 配置 ... loadmodule "xhttp.so" # 假设使用 HTTP 与签名服务交互 loadmodule "json.so" loadmodule "htable.so" route { # 假设你的签名服务是 http://stir_shaken_signer.example.com/sign if (is_from_local_domain() && $rU =~ "^\+1") { # 仅对本地域的E.164号码进行签名 # 构建发送给签名服务的 JSON 请求 # 注意:这里需要你根据签名服务的API来构建请求体 $var(request_body) = "{ \"from\": \"" + $ruri + "\", \"to\": \"" + $fU + "\" }"; # 发送 HTTP POST 请求到签名服务 if (xhttp_post("http://stir_shaken_signer.example.com/sign", "application/json", $var(request_body), "$var(response_code)", "$var(response_body)")) { if ($var(response_code) == "200") { # 解析签名服务返回的 JSON 响应,获取 Identity 头内容 if (json_get("$.identity_header", "$var(identity_value)", $var(response_body))) { # 将 Identity 头添加到 SIP INVITE 消息中 append_hf("Identity: " + $var(identity_value) + "\r\n"); } else { xlog("L_ERR", "STIR/SHAKEN signer: Failed to parse identity_header from response.\n"); } } else { xlog("L_WARN", "STIR/SHAKEN signer: HTTP POST failed with code $var(response_code).\n"); } } else { xlog("L_ERR", "STIR/SHAKEN signer: HTTP POST failed.\n"); } } # 继续路由呼叫 route(NATDETECT); route(RELAY); }呼叫接收方 (TSP) Kamailio.cfg 片段:
# ... 其他 Kamailio 配置 ... loadmodule "xhttp.so" loadmodule "json.so" loadmodule "htable.so" route { # 假设你的验证服务是 http://stir_shaken_verifier.example.com/verify if (is_method("INVITE")) { if (is_present_hf("Identity")) { # 提取 Identity 头内容 $var(identity_header_value) = $hdr(Identity); # 构建发送给验证服务的 JSON 请求 $var(request_body) = "{ \"identity_header\": \"" + $var(identity_header_value) + "\", \"from\": \"" + $fU + "\", \"to\": \"" + $rU + "\" }"; # 发送 HTTP POST 请求到验证服务 if (xhttp_post("http://stir_shaken_verifier.example.com/verify", "application/json", $var(request_body), "$var(response_code)", "$var(response_body)")) { if ($var(response_code) == "200") { # 解析验证服务返回的 JSON 响应,获取验证结果 if (json_get("$.attestation_level", "$var(attestation_level)", $var(response_body))) { xlog("L_INFO", "STIR/SHAKEN verification result: $var(attestation_level)\n"); if ($var(attestation_level) == "A" || $var(attestation_level) == "B" || $var(attestation_level) == "C") { # 验证通过,正常路由 append_hf("X-Attestation-Level: " + $var(attestation_level) + "\r\n"); # 可选:添加自定义头 route(RELAY); } else if ($var(attestation_level) == "FAILED") { xlog("L_WARN", "STIR/SHAKEN verification failed for call from $fU to $rU.\n"); sl_send_reply("403", "Forbidden - STIR/SHAKEN Failed"); exit; } else { xlog("L_WARN", "STIR/SHAKEN unknown attestation level: $var(attestation_level).\n"); # 默认处理,例如继续路由或拒绝 route(RELAY); } } else { xlog("L_ERR", "STIR/SHAKEN verifier: Failed to parse attestation_level from response.\n"); route(RELAY); # 继续路由,但标记为未验证 } } else { xlog("L_WARN", "STIR/SHAKEN verifier: HTTP POST failed with code $var(response_code).\n"); route(RELAY); # 继续路由,但标记为未验证 } } else { xlog("L_ERR", "STIR/SHAKEN verifier: HTTP POST failed.\n"); route(RELAY); # 继续路由,但标记为未验证 } } else { xlog("L_INFO", "No Identity header found for call from $fU to $rU. Routing as unverified.\n"); route(RELAY); # 没有 Identity 头,直接路由 } } # ... 其他路由逻辑 ... }关键考虑事项和注意事项:
- 外部 STIR/SHAKEN 服务的选择:Kamailio 本身不提供 STIR/SHAKEN 签名或验证功能,你需要选择一个或多个符合标准的外部服务提供商或部署自己的 STIR/SHAKEN 签名/验证服务器。
- API 接口:确保 Kamailio 能够与外部 STIR/SHAKEN 服务的 API 进行通信。HTTP/REST API 是最常见的选择,Kamailio 的
xhttp和json模块可以很好地支持。 - 性能:STIR/SHAKEN 签名和验证过程会增加呼叫设置的延迟。确保你的外部服务具有足够的处理能力,并且 Kamailio 与其通信是高效的。
- 错误处理和降级:必须考虑当 STIR/SHAKEN 签名/验证服务不可用或返回错误时如何处理呼叫。通常会有一个降级机制,例如将呼叫标记为“未验证”并继续路由,或者在特定情况下直接拒绝。
- 证书管理:无论是签名方还是验证方,都需要妥善管理 STI 证书。这通常由 STIR/SHAKEN 服务自动处理,但需要了解其工作原理。
- Attestation Level (A/B/C):
- A (Full Attestation):运营商可以验证主叫号码和发起呼叫的客户。最高信任度。
- B (Partial Attestation):运营商可以验证客户,但无法完全验证主叫号码。
- C (Gateway Attestation):运营商仅验证呼叫是否来自其网络。最低信任度。
- Kamailio 在接收方应根据这些级别来制定不同的呼叫处理策略。
- SIP 头修改:除了
Identity头,有时还会涉及其他 SIP 头,例如P-Attestation-Info或自定义的X-头,用于传递额外的 STIR/SHAKEN 相关信息。 - 日志和监控:详细记录 STIR/SHAKEN 签名和验证的成功与失败情况,以及 Attestation Level,对于故障排除和合规性审计至关重要。
- 测试:在生产环境中部署之前,进行严格的测试,包括正常流程、错误情况和性能测试。
总而言之,Kamailio 在 STIR/SHAKEN 架构中扮演着重要的集成点角色。它负责将 SIP 信令流与外部的 STIR/SHAKEN 签名和验证服务连接起来,并根据这些服务的输出进行智能的呼叫路由和处理决策。