Playwright 启动 Chrome 导致 Windows 账户锁定的排查记录

太阳作者太阳
原创内容采用 CC-4.0 协议发布,转载请注明出处

连续跑了几轮 Playwright 端到端测试后,这台 Windows 电脑突然登不进去了。安全日志显示,本地账户在回到登录界面之前就已经被锁定。当时测试启动的是系统 Edge,切换到 Google Chrome 后,用 Playwright 默认参数只跑一条测试,照样留下了一次 Windows 登录失败。

从安全日志找到锁定来源

2026 年 11 月 12 日 12:59:44 到 13:17:15,Windows 记录了十次针对同一本地账户的密码验证失败。十条记录的调用进程都是 msedge.exe,进程 ID 各不相同。工作站为本机,源网络地址为空,登录类型为 2(交互式),登录进程为 Advapi,子状态为 0xC000006A(密码错误)。微软的 4625 事件说明

第十次失败与 13:17:15 的 4740 账户锁定事件相隔不到 1 毫秒,锁定事件的调用方计算机也是本机。几分钟后,在登录界面进行的验证返回 0xC0000234(账户已锁定)。这台机器的锁定阈值是 10 次,计数重置间隔和锁定时长均为 10 分钟。微软的 4740 事件说明

几次 Playwright 命令与登录失败只相隔数秒。例如,12:59:38 执行 bun run test:e2e,约 6 秒后出现这组记录里的第一次失败。测试配置明确选择了系统 Edge。安全日志足以定位发起验证的进程,现有进程审计记录无法把全部十次失败逐一关联到具体命令。

用 Chrome 做单次对照

把 Playwright 的浏览器通道改为 chrome,用本机 Google Chrome 157.0.8103.39 跑同一条「七天会话与退出确认」测试。两轮各启动一次浏览器,均使用 Playwright 创建的临时配置。

  • 默认启动参数。测试通过,新增一条由 chrome.exe 发起的 4625,子状态为 0xC000006A。没有新增 4740。
  • 额外禁用 AutofillAiWalletPrivatePasses。测试通过,新增 4625 和 4740 均为零。

可在管理员 PowerShell 中先记录开始时间,在平常运行测试的终端中只跑一条用例,退出后回到管理员终端查询。下面的文件和行号对应本次测试,其他项目按实际用例替换。

$start = Get-Date
bun run test:e2e e2e/admin.spec.ts:29
Get-WinEvent -FilterHashtable @{
  LogName = 'Security'
  Id = 4625, 4740
  StartTime = $start
} | Select-Object TimeCreated, Id, RecordId, Message

对照 4625 的调用进程、目标账户和子状态。如果 PowerShell 提示找不到匹配事件,表示这段时间里没有匹配的记录。已有过锁定的机器,单次启动和查看日志就能验证是否还会产生一次失败。

Chromium 启动时为什么会验证空密码

Chromium 的 CheckBlankPasswordWithPrefs() 会在需要重新检查时,把空字符串交给 Windows 的 LogonUser,用交互式登录验证当前本地账户是否为空密码。对设置了密码的账户,这次探测可能记为一次失败。自动填充在浏览器启动期间查询设备验证能力时,可能走到这条代码路径。测试频繁启动新的浏览器进程和临时配置,失败次数就可能累积到锁定阈值。安全日志本身只记录验证结果,空密码探测是由上游源码和单次对照共同支持的解释。Chromium 的根因分析 · Windows 密码检查源码

Playwright 官方排查也在其自带的 Chromium 153 和 156 上复现了新配置启动产生一次 4625。维护者将问题交给 Chromium 跟踪,说明会在上游修复后引入修复。Playwright 工单 #43036 · Chromium 工单 #562403601

临时规避和移除条件

原来的 Playwright 配置

Bluewave 管理端的 playwright.config.ts 原先用下面的 use 配置。browserName 选的是 Chromium 引擎,channel: 'msedge' 指定实际启动本机 Edge。

use: {
  baseURL: 'http://localhost:30013',
  browserName: 'chromium',
  channel: 'msedge',
  viewport: { width: 1440, height: 900 },
  trace: 'retain-on-failure',
},

改用 Chrome 并加上临时规避参数

下面是本次修改涉及的配置。把 defaultDisabledFeatures 放到文件顶层,将新的 use 配置放进原来的 defineConfig(),和已有的测试目录、启动服务及数据库设置一起使用。

import { defineConfig } from '@playwright/test';

const defaultDisabledFeatures = `--disable-features=${[
  'AvoidUnnecessaryBeforeUnloadCheckSync',
  'DestroyProfileOnBrowserClose',
  'HttpsUpgrades',
  'HttpsFirstBalancedModeAutoEnable',
  'LensOverlay',
  'MediaRouter',
  'PaintHolding',
  'ThirdPartyStoragePartitioning',
  'AvoidCorsURLLoaderRestartOnRedirect',
  'TcpPortRandomizationWin',
  'OptimizationHints',
  'NetworkTimeServiceQuerying',
  'AimEnabled',
  'PreconnectToSearch',
  'msForceBrowserSignIn',
  'msEdgeUpdateLaunchServicesPreferredVersion',
].join(',')}`;

export default defineConfig({
  use: {
    baseURL: 'http://localhost:30013',
    browserName: 'chromium',
    channel: 'chrome',
    launchOptions: {
      ignoreDefaultArgs: [defaultDisabledFeatures],
      args: [`${defaultDisabledFeatures},AutofillAiWalletPrivatePasses`],
    },
    viewport: { width: 1440, height: 900 },
    trace: 'retain-on-failure',
  },
});

ignoreDefaultArgs 按完整字符串匹配 Playwright 1.65.0 的默认 --disable-features。args 把原来的 16 项和临时规避项合成一个开关,避免 Chrome 解析多个同名参数时覆盖默认列表。升级 Playwright 时,核对新版生成的默认列表。Playwright 启动选项

什么时候可以移除参数

截至 2026 年 11 月 12 日,Chromium 的 修复补丁 CL 8656602 仍在评审。补丁拟将启动时的验证能力检查限制到确实存在相关 Wallet 私密凭证的情况。Windows Chrome 稳定版 157.0.8103.79 和提前发布版 158.0.8127.19 的源码仍保留启动时的验证能力检查,暂时没有可确认的修复版本。Chrome 157 稳定版公告 · Chrome 158 提前发布公告 · 157 的启动代码 · 158 的启动代码

等修复进入 Windows Chrome 稳定版,确认 Playwright 实际启动了该版本,再用默认参数和全新临时配置跑一次测试。安全日志没有新增这类 chrome.exe 登录失败后,可以删除 launchOptions 和 defaultDisabledFeatures,继续使用 channel: 'chrome'。

重启后的时间变化与浏览器掉登录

为恢复登录,当时用 HotPE 离线清除了 Windows 本地密码。回到 Windows 的那次启动,系统时钟快了八小时,随后 Windows 时间服务通过网络同步校正。此前的 4740 锁定事件发生在时间跳变之前。

恢复登录后,Windows 还记录了 DPAPI 主密钥解密失败。离线重置密码可能使原有的加密登录数据无法读取,这与随后 Chrome 需要重新登录的现象吻合。Edge 中出现的 Chrome 历史则来自此前已启用的「每次启动时导入 Chrome 数据」。排障时看到的九条本地后台访问记录,在两边浏览器的历史数据库中网址和访问时间完全一致,Edge 侧也带有导入来源标记。微软的 DPAPI 与密码重置说明 · 微软的 Edge 启动导入说明