Skip to content
bitzorcas
中EN

Guide

Crawler 安全与浏览器会话

解释当前 Selenium 防腐端口、隐式浏览器状态、SSRF 与脚本风险、取消语义和生产隔离方案。

Last updated

Crawler Port 隔离了 Selenium 类型,但没有自动建立安全浏览器平台。当前接口围绕一个隐含“当前页面”工作,适合受信任的内部自动化原语,不适合直接暴露给多租户请求。

1. 当前四个操作

Port 方法输入输出/作用
OpenUrlAsyncURL、可选 TenantId改变当前浏览器页面
FindElementAsyncID/Name/Class/Tag/CSS/XPath元素文本、标签、属性快照
ScreenshotAsync可选 TenantIdURL、标题、PNG 字节
ExecuteScriptAsync脚本、参数任意脚本返回值

TenantId 不是安全边界:OpenUrl Adapter 没有使用它,Screenshot 只写 Debug 日志。

2. 隐式会话模型

"共享 CrawlingService""租户 B 请求""租户 A 请求""共享 CrawlingService""租户 B 请求""租户 A 请求"OpenUrl(A)OpenUrl(B)Screenshot()可能是 B 页面

Port 没有 browser/session handle,也没有把 open→find→script→screenshot 绑定成原子工作单元。若底层服务是 Singleton,共享 current driver 会产生页面串扰、Cookie 泄露和竞态。

3. 当前打开 URL 的验证

Adapter 只拒绝空 URL。当前没有:

  • http/https scheme allowlist;
  • 域名或租户目标 allowlist;
  • DNS 解析后私网、loopback、link-local 拒绝;
  • 非标准端口策略;
  • 重定向逐跳复验;
  • 用户信息、混淆 IP、DNS rebinding 防护;
  • 下载大小和响应类型限制。

因此直接传入用户 URL 会形成 SSRF 风险,包括云元数据、内网管理面和本机服务。

4. 生产 URL 策略示例

打开策略允许的目标
// ① 解析并规范化;禁止相对 URL、userinfo 和非 HTTP(S)。
Uri target = await urlPolicy.ParseAndValidateAsync(command.Url, cancellationToken);
// ② DNS 解析后的每个地址都必须通过网络范围策略。
await urlPolicy.AssertPublicOrTenantAllowlistedAsync(target, cancellationToken);
// ③ 分配隔离会话后再调用当前 Port;当前 Port 自身不会执行上述检查。
Result opened = await crawler.OpenUrlAsync(
new CrawlerOpenUrlRequest(target.ToString(), trustedTenantId),
cancellationToken);

重定向必须在网络层逐跳验证;只验证初始 URL 不足以阻止跳入私网。

5. 脚本执行边界

ExecuteScriptAsync 只检查脚本非空。没有脚本模板、操作白名单、超时沙箱或返回值大小限制。若脚本来自请求,调用者相当于获得浏览器上下文中的任意代码执行权。

推荐让业务请求选择预注册操作,例如 ReadInvoiceTotal,由服务端映射到固定脚本。参数只允许 JSON 基元和经过验证的 selector,不接受任意脚本文本。

固定脚本目录
// ① 客户端提交操作名和数据,不提交 JavaScript。
CrawlerScriptDefinition definition = scriptCatalog.Get(command.Operation);
// ② 目录定义允许域、参数 schema、最大耗时和输出上限。
definition.Validate(command.Arguments, currentTarget);
// ③ 只有服务端拥有的脚本进入 Port。
return await crawler.ExecuteScriptAsync(
new CrawlerExecuteScriptRequest(definition.Script, command.Arguments), ct);

6. Locator 风险

CSS 与 XPath 可触发昂贵查询;XPath 还可能越过预期区域读取页面敏感内容。应按业务操作限制 locator 类型、长度、数量和查找范围。

FindElementAsync 返回完整 href。带 token 或查询参数的 URL 不应原样进入日志、审计或客户端,应返回规范化/脱敏投影。

7. 返回值可序列化性

Adapter 只把“直接返回的单个 IWebElement”转成字符串。元素集合、字典或嵌套对象仍可能携带 Selenium 类型,导致序列化失败或泄漏实现。

生产边界应只允许显式 JSON schema:字符串、数字、布尔和有界数组。未知对象应拒绝,而不是交给通用序列化器猜测。

8. 取消与超时

同步 Selenium 调用由 Task.Run(..., cancellationToken) 包装。Token 可以阻止任务开始,但任务一旦执行,取消并不会中断 WebDriver 调用。

必须同时配置:

  • WebDriver page-load/script/implicit timeout;
  • 业务工作单元 deadline;
  • 超时后 driver 废弃或恢复策略;
  • 浏览器进程 watchdog;
  • 并发队列和租户配额。

不要把 CancellationToken 参数误写成底层操作可立即取消。

9. 异常映射

Adapter 捕获 WebDriverException、NoSuchElementException、NotFoundException 和 TimeoutException,返回 ProviderFailed,并把原始异常消息放进描述。

调用层需要稳定分类为目标拒绝、导航超时、元素未找到、脚本失败、会话损坏等;原始消息只进入受限诊断日志。未知异常仍由全局异常处理兜底。

10. 会话隔离设计

GA 推荐引入显式会话:

可信 owner 请求

租户配额队列

Browser Session Pool

SessionId + Tenant binding

固定操作目录

销毁 / 清理 Cookie

会话至少绑定 TenantId、ActorId、允许域、创建时间、deadline 和并发所有权。完成后清理 Cookie、local storage、下载、缓存和临时 profile;高敏业务使用一次性容器/进程。

11. 测试矩阵

必须覆盖:

  • loopback、RFC1918、IPv6 local、link-local、元数据地址;
  • 十进制/十六进制 IP、userinfo、重定向、DNS rebinding;
  • 两租户并发 open/screenshot 不串页;
  • Cookie/storage 不跨会话;
  • 超时后 driver 不回到可用池;
  • 任意脚本、超长 selector、巨大输出被拒绝;
  • 元素集合返回被规范化;
  • Provider 错误不向客户端泄露路径/堆栈。

当前源码没有这些测试,因此现阶段只能把 Port 作为受信任内部原语。

12. 运维清单

限制浏览器进程 CPU/内存/文件描述符;固定浏览器与 driver 兼容版本;及时修补;网络出口默认拒绝;下载目录使用隔离临时盘;指标记录队列、活动会话、超时、崩溃和清理失败。

Terminal window
rg -n "OpenUrlAsync|ExecuteScriptAsync|Task.Run|IWebElement" \
src/Platform/ToolConnectors -g '*.cs'

返回 Tool Connectors 总览

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%