先看结论与判断条件

  • 模型文本不是可信控制指令,系统提示词可以约束回答方向,却不能替代应用侧的确定性安全门禁。
  • URL 校验必须基于标准解析后的结构化字段,而不是前缀匹配、字符串包含或对模型说明的信任。
  • App Links 验证解决域名与应用签名的关联,不会自动完成登录状态、对象归属、金额、角色和一次性授权校验。
  • 路由匹配成功只说明地址能映射到页面,冷启动、返回栈、异常参数和业务动作仍要独立验收。
  • 导出组件与 PendingIntent 会扩大调用和重放边界,不能因为入口来自应用内部的 AI 页面就跳过组件与目标限制。
  • 最安全的执行模型是生成、解析、决策、确认、授权和提交分层,每层只接收上一层的结构化结果。

模型输出只能进入建议通道

当聊天助手返回“打开订单”“进入会员页”或一段 Deep Link 时,模型完成的是文本生成,不是业务授权。输出可能来自不完整上下文、错误理解、外部内容影响或格式漂移。即使地址看起来像应用自己的域名,也可能指向不存在的路由、错误对象或超出当前用户权限的动作。产品应把这段输出标记为 proposal,后续只允许确定性代码读取,不能直接调用系统打开地址。

Firebase AI Logic system instructions 说明系统指令会随请求影响模型行为,同时应用仍需控制输入、输出和工具权限。这个边界很关键:提示词可以要求模型只生成允许域名,却不能保证每次输出都符合要求,也不能处理用户会话、对象归属和一次性业务状态。把提示词当安全边界,会让策略跟随自然语言而漂移,审计时也无法回答哪条代码拒绝了越权地址。

建议通道应保留原始模型文本、模型请求标识、解析结果和拒绝原因,但日志必须避免敏感查询参数。只有解析器输出结构化 action candidate 后,策略引擎才继续判断。若模型返回多个地址、混入说明文字、使用未知 scheme 或无法唯一解析,默认动作应是展示普通文本或要求用户重新选择,而不是猜测最可能的目标。

模型建议与可执行动作的责任差异
阶段输入允许的输出失败时处理
模型生成会话与可公开上下文文本或候选动作保留为文本,不执行
URL 解析单个候选字符串结构化 scheme、host、path、query拒绝歧义或非法格式
路由策略规范化 URL允许的内部动作类型拒绝未知域名和路由
用户确认动作摘要与影响明确同意或取消取消后不提交
业务授权当前会话与对象一次可执行命令返回无权或状态已变化

先做结构化解析,再谈白名单

白名单不能用 startsWith 或字符串包含实现。URL 可能包含大小写差异、编码字符、用户信息、端口、片段、重复查询参数和多次解码后的歧义。可靠流程应先用平台 URL 解析器得到 scheme、host、port、path、query 和 fragment,再按统一规则规范化。解析失败、出现用户名密码段、使用非预期端口或包含 fragment 时,可以直接拒绝,避免后续组件各自解释出不同目标。

scheme 需要按用途分层。面向外部来源的可验证链接优先使用 https 和受控域名;应用自定义 scheme 若确有历史兼容需求,应限制精确值、精确路由和调用来源,不能把任意 host 当作内部命令。对于模型生成的地址,未知 scheme、file、content、javascript 或其他未登记协议都不应进入 Intent。拒绝规则要在创建 Intent 之前运行,避免解析副作用或错误组件匹配。

host 白名单也必须做精确比较。允许 example.com 不等于允许 example.com.attacker.invalid,允许某个子域也不代表允许所有后缀。国际化域名、尾点和默认端口要经过统一规范化后再比较。path 应按解码后的段匹配固定模板,不能让编码斜杠或路径穿越改变路由结构。query 参数则按路由独立声明名称、数量、类型、长度和可选性。

Deep Link 解析层的拒绝条件
字段允许方式需要拒绝拒绝原因
scheme精确允许 https 或登记协议未知及可访问本地内容的协议协议决定调用面
host规范化后精确命中后缀伪装、空 host 与用户信息字符串相似不代表同一域名
port缺省或策略登记端口未登记端口避免指向不同服务入口
path解码后按段匹配模板空段、编码分隔符和未知层级防止路由解释分歧
query路由声明的键与类型重复键、未知键和超长值减少参数走私和歧义
fragment通常不参与动作任何未定义片段避免组件解释不一致

App Links 验证的是关联,不是业务许可

Android App Links overview 说明 App Links 通过 Manifest URL、Digital Asset Links 和应用签名证书建立域名与应用的关联。这能减少受验证 https 链接被其他应用随意接管的问题,也让系统知道哪些链接应交给当前应用。它解决的是系统级关联与路由归属,不会判断链接中的订单是否属于当前用户,也不会验证当前会话是否允许付款、删除或分享。

因此域名验证通过后,应用仍要执行对象级授权。一个指向订单详情的合法链接可能引用别人的订单,一个指向退款页面的合法链接可能超出当前角色,一个优惠领取链接也可能已经过期。服务端应根据当前登录主体、对象状态、操作权限和一次性条件重新决策,客户端路由白名单只负责把请求送到正确的安全检查入口。

Verify Android App Links 提供重置、重新验证和读取各域名验证状态的方法,适合在发布前确认设备上的关联结果。这个状态仍不能替代端到端回归。测试必须覆盖未安装后首次打开、冷启动、后台恢复、已登录和未登录、验证失败、浏览器回退及异常参数。模型生成链接的验收还要增加多地址、说明文字和未知路由输入。

App Links 与业务授权的分工
问题App Links 能回答应用或服务端继续回答证据
域名是否关联应用通过关联文件和签名证书验证确认发布配置属于当前候选域名验证状态
链接映射哪个页面系统选择匹配的应用入口Navigation 解析具体路由路由匹配回执
参数是否可信不能类型、范围、对象存在性校验参数门禁结果
用户是否有权不能会话、角色和对象归属授权服务端授权回执
动作是否仍有效不能状态、时效与幂等检查提交时最新状态

路由匹配和动作执行必须拆开

Navigation deep links 说明深链会匹配路由参数,并影响冷启动与任务返回栈。路由器的职责是把结构化地址映射到页面或导航目标,不应同时完成高风险业务操作。即使链接写着 confirm=true,也只能决定页面展示确认状态,不能在页面创建时自动提交支付、删除、授权或外发数据。导航是用户界面入口,业务命令必须经过另一套明确接口。

路由白名单要面向动作语义设计。只读详情、筛选列表和帮助页面可以在基础校验后导航;会改变服务器状态或暴露敏感信息的路由,应先生成安全预览,展示对象、影响和来源,再要求用户确认;涉及角色、资金、设备绑定或授权变更的动作,必须在提交时重新验证会话并由服务端裁决。模型不能通过 query 参数降低确认等级。

返回栈也是安全体验的一部分。冷启动深链可能绕过用户通常经过的页面,返回键也可能暴露不应出现的上层页面。测试应记录入口、登录中转、确认页、目标页和返回路径。若应用需要先登录,登录完成后只能恢复经过清洗的 action candidate,不应重新执行原始模型字符串,避免会话切换期间地址内容发生未审计变化。

导出组件决定谁能触达入口

Android exported component risk 指出导出组件和 intent filter 会扩大跨应用调用面,需要显式权限和输入校验。一个 Activity 因 Deep Link 而导出后,外部应用也可能直接构造 Intent 到达入口,来源不再只包括浏览器和应用内 AI 页面。因此安全逻辑必须放在被调用组件或其统一策略层,不能只放在聊天界面的点击回调里。

组件清单应记录 exported 值、intent filter、所需权限、允许 action、category、data 约束以及实际业务处理器。能不导出的组件保持不导出,外部入口只负责解析和转发到内部不可导出页面。解析结果应经过不可变数据结构传递,内部页面不要再次从原始 Intent 读取未经校验的 extras、data 或 clipData。

来源判断不能只依赖 referrer、调用包名或界面路径,因为这些信号可能缺失,且不等于业务授权。更可靠的原则是无论谁调用,都执行相同的 URL、路由、参数、会话和对象校验。若某动作只允许应用内部触发,应使用不可导出组件或受权限保护的显式入口,而不是在导出组件里检查一个容易遗漏的布尔参数。

Deep Link 入口组件的最小审查
清单项安全问题可执行决策验证方式
exported外部应用能否直接触达仅保留必要的外部入口检查 Manifest 合并结果
intent filter哪些 action 和 data 会匹配收窄 scheme、host 与 path构造允许和拒绝用例
组件权限调用方是否需要平台权限敏感入口增加适当权限未授权调用应失败
原始 Intent未校验字段会否继续传播入口处转换为清洗对象内部页面拒绝原始 extras
业务处理器导航是否直接触发状态变更拆出确认与授权层冷启动和恢复流程回归

PendingIntent 不能成为绕过通道

PendingIntent security risks 说明可变性、目标组件和一次性标志会影响重放与重定向风险。若应用把模型生成的 Deep Link 包装进 PendingIntent,用于通知、快捷操作或后台回调,原有 URL 门禁仍然必须先执行。PendingIntent 不是可信封装,它只是让另一方在未来以创建者身份触发预先描述的操作。

创建时应优先使用明确目标组件和不可变配置,并按业务需求考虑一次性使用。传入的数据应是已经解析和规范化的 action id,而不是原始 URL。若动作需要最新授权,PendingIntent 触发后仍要读取当前会话和服务端状态,不能沿用创建通知时的权限结论。通知存在时间越长,订单、角色、设备和风险状态越可能变化。

正确 flags 也不能保证返回栈与业务恢复正确。通知点击、AI 页面点击和外部 App Link 可能进入不同任务状态,测试要覆盖应用未运行、后台存活、进程被回收和用户切换账号等场景。任何路径都只能抵达确认或详情入口,不能因为来自 PendingIntent 就自动执行高风险命令。

用策略文件把路由与参数固定下来

实现层可以把允许的 host、path 模板、参数类型、确认等级和所需权限放进版本化策略文件。模型只输出候选 URL,校验器把它转换成 action candidate。策略命中后仍不执行,只返回 route、规范化参数、requiresConfirmation 和 requiredPermission,交给后续页面与业务服务。这样既能审计允许面,也能在模型格式变化时保持确定性。

下面的 Python 代码演示只读校验。它拒绝非 https、用户信息、端口、fragment、未知 host、未知 path、重复参数、未知参数和类型错误,并从策略中读取路由要求。代码不发起网络请求,不创建 Intent,也不执行任何动作。真实 Android 实现应使用平台 URI API和严格的路由对象,服务端授权仍在提交时完成。

错误必须是可观察的失败,而不是悄悄降级到第一个页面。日志可以记录 policy version、route id 和拒绝码,但应对对象 id 和查询值做最小化处理。模型输出包含无法解析内容时,界面可以显示“无法打开该操作”并保留普通文本。不要把失败地址交给通用浏览器作为自动回退,否则未知目标仍可能离开应用安全边界。

校验模型生成 Deep Link 的允许域名、路由和参数类型
from pathlib import Path
from urllib.parse import parse_qs, unquote, urlsplit
import json
import re
import sys

if len(sys.argv) != 3:
    raise SystemExit(2)
policy_path = Path(sys.argv[1])
candidate = sys.argv[2]
if not policy_path.is_file() or len(candidate) > 2048:
    raise SystemExit(2)
policy = json.loads(policy_path.read_text(encoding="utf-8"))
try:
    parsed = urlsplit(candidate)
    port = parsed.port
except ValueError:
    raise SystemExit(3)
if parsed.scheme.lower() != "https":
    raise SystemExit(3)
if parsed.username or parsed.password or port or parsed.fragment:
    raise SystemExit(3)
host = (parsed.hostname or "").rstrip(".").lower()
if host not in set(policy.get("allowedHosts", [])):
    raise SystemExit(3)
path = unquote(parsed.path)
if "//" in path or ".." in path:
    raise SystemExit(3)
route = next((item for item in policy.get("routes", []) if item.get("path") == path), None)
if route is None:
    raise SystemExit(3)
query = parse_qs(parsed.query, keep_blank_values=True)
if any(len(values) != 1 for values in query.values()):
    raise SystemExit(3)
parameter_rules = route.get("parameters", {})
if set(query) - set(parameter_rules):
    raise SystemExit(3)
normalized = {}
for name, rule in parameter_rules.items():
    values = query.get(name)
    if rule.get("required") and not values:
        raise SystemExit(3)
    if not values:
        continue
    value = values[0]
    kind = rule.get("type")
    if kind == "uuid" and not re.fullmatch(r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}", value):
        raise SystemExit(3)
    if kind == "enum" and value not in set(rule.get("values", [])):
        raise SystemExit(3)
    if kind == "integer":
        if not value.isdecimal():
            raise SystemExit(3)
        number = int(value)
        minimum = rule.get("minimum")
        maximum = rule.get("maximum")
        if not isinstance(minimum, int) or not isinstance(maximum, int) or minimum > maximum:
            raise SystemExit(3)
        if number < minimum or number > maximum:
            raise SystemExit(3)
        value = number
    normalized[name] = value
result = {"routeId": route.get("id"), "parameters": normalized, "requiresConfirmation": bool(route.get("requiresConfirmation")), "requiredPermission": route.get("requiredPermission")}
if not result["routeId"] or not result["requiredPermission"]:
    raise SystemExit(3)
print(json.dumps(result, ensure_ascii=False, sort_keys=True))

确认、授权和提交各自解决不同问题

用户确认解决的是意图可见性。确认页应使用应用根据结构化参数重新查询的数据展示对象名称、动作影响和可撤销性,不能直接展示模型生成的描述并把它当事实。用户点确认后,客户端生成一次提交请求,但服务端仍要重新验证会话、角色、对象归属、对象状态和幂等键。确认不能赋予用户本来没有的权限。

授权解决的是当前主体是否可以在当前状态下执行动作。Deep Link 中的 userId、role、price、permission 或 confirmed 参数都不应成为授权依据。对象标识可以帮助定位资源,真正的角色和权限来自服务端会话与策略。若用户在确认期间切换账号、对象状态变化或动作已执行,提交应失败并返回新的可理解状态。

幂等和时效解决的是重复执行。模型可能重复给出同一链接,用户也可能多次点击,PendingIntent 和恢复流程还会增加重放机会。状态变更命令应使用由应用或服务端生成的短期操作标识,并在服务端实现幂等。URL 本身不应携带长期有效的高权限凭据;若业务需要一次性令牌,也要限制受众、动作、对象、时效和使用次数。

高风险动作的分层门禁
门禁核心问题不能替代失败结果
URL 解析地址是否唯一且结构合法域名关联和业务授权拒绝候选
路由白名单应用是否声明该动作参数真实性和对象权限不创建导航动作
用户确认用户是否理解并同意服务端权限取消且不提交
会话授权当前主体是否有权用户确认和幂等返回无权
对象状态动作在当前时刻是否有效链接格式返回状态已变化
幂等控制重复请求会否重复生效权限检查复用已有结果或拒绝

发布前用拒绝用例证明边界

验收不能只测几条正确链接。测试集应包含未知 scheme、后缀伪装域名、用户信息、非预期端口、编码路径分隔符、重复参数、未知参数、类型错误、未登录、无权对象、过期对象、多次点击和进程恢复。每条用例绑定应用候选、策略版本、路由版本和预期拒绝层,才能判断失败是否发生在正确位置。

平台回执也要分开保存。App Links 的域名验证状态证明系统关联,Navigation 测试证明路由和返回栈,组件测试证明外部调用面,业务接口回执证明对象授权与幂等。任何单项通过都不能扩大成整体安全结论。没有真实候选和服务端记录时,只能说明设计方法和待验证范围,不能声称某应用已阻断风险。

准备移动 AI 操作安全评估时,可整理模型可能生成的动作类型、允许域名、路由策略、参数 schema、导出组件清单、确认等级、服务端权限和拒绝用例,再通过御盾中央平台提交需求。评审重点应放在模型建议如何被收窄为可审计命令,而不是继续堆叠提示词。模型输出保持不可信,应用才能在模型升级后继续守住同一业务边界。

事实依据与适用边界

以下内容区分官方事实、本文工程判断和不能外推的范围,避免把设计建议写成未经验证的产品结论。

本文判断事实或工程依据适用限制
系统指令会影响模型行为,但应用仍需控制输入、输出和工具权限。Firebase AI Logic system instructions 说明系统指令随请求影响生成行为及应用侧控制责任。系统指令不能完全阻止越权、泄露或格式漂移,不能作为 Deep Link 执行边界。
Navigation 深链会匹配路由参数,并影响冷启动与任务返回栈。Navigation deep links 描述深链声明、参数匹配和导航行为。路由匹配成功不证明参数可信,也不代表目标业务动作已经授权。
Android App Links 通过域名声明、关联文件和应用签名证书建立应用关联。Android App Links overview 描述 Manifest URL、Digital Asset Links 与签名证书的关联。域名关联不校验登录会话、对象归属、操作权限或动作时效。
设备可以重置、重新验证并读取各域名的 App Links 验证状态。Verify Android App Links 给出验证状态检查和复核方法。系统验证状态不能替代冷启动、返回栈、异常参数和业务授权回归。
导出组件与 intent filter 会扩大跨应用调用面。Android exported component risk 说明 exported 配置、intent filter 与外部调用风险。exported 值只是入口条件,不能单独证明组件输入和业务处理安全。
PendingIntent 的可变性、目标组件和一次性设置会影响重放与重定向边界。PendingIntent security risks 说明相关配置对安全行为的影响。正确 flags 不保证 Deep Link 参数、返回栈、会话授权和状态恢复正确。
模型生成地址应先转换为结构化 action candidate,再进入用户确认和业务授权。工程判断:文本生成、URL 解析、导航和状态变更属于不同信任层,合并执行会让拒绝责任不可审计。分层设计需要在真实应用候选和服务端上验证,本文不提供项目通过结论。
Deep Link 中的角色、价格、权限和确认参数不能作为服务端授权依据。工程判断:客户端地址由外部或模型提供,当前会话、对象归属和状态必须由可信业务系统重新决定。具体授权模型取决于业务,本文不声明任何产品权限能力或风险阻断效果。

工程常见问题

提示词已经要求模型只生成允许域名,还需要代码校验吗?

需要。系统指令只能影响生成行为,不能保证每次输出符合格式与权限要求。应用仍要确定性解析并限制 scheme、host、路由和参数。

App Links 验证通过后,链接是不是就可信了?

不是。验证说明域名与应用签名有关联,不证明参数真实、对象属于当前用户,也不证明当前会话有权执行状态变更。

模型生成的链接只打开详情页,是否可以直接执行?

只读路由仍应经过解析、域名、路径和参数校验。通过后可以导航到详情入口,但页面读取对象时仍要执行当前会话和对象权限检查。

在 Deep Link 中增加 confirmed=true 能否跳过确认页?

不能。确认等级由应用路由策略决定,不能由不可信查询参数降低。高风险动作应使用应用重新生成的摘要取得明确确认。

把地址包装成不可变 PendingIntent 是否就安全?

不够。不可变设置减少后续修改,但创建前仍要校验地址,触发后还要复核当前会话、对象状态、幂等和返回栈。

评估 AI Deep Link 执行边界前应准备哪些材料?

准备模型动作类型、允许域名与路由、参数 schema、导出组件、确认等级、服务端权限、幂等方案和拒绝用例,再通过御盾中央平台提交评估需求。

想用自己的 App 验证?

提交候选包、目标系统和关键业务路径,申请御盾 PoC 与兼容性评估。

继续阅读: 移动 AI 应用的运行时安全边界