Wechatsync 安全审计报告

Wechatsync 安全审计报告

审计范围 : @wechatsync/core, @wechatsync/extension, @wechatsync/mcp-server, @wechatsync/cli

审计日期 : 2026-07-24

审计目标: 账号窃取风险、未授权数据上传风险


目录

  1. 项目概述
  2. 认证机制分析
  3. 数据流分析
  4. 账号窃取风险评估
  5. 未授权数据上传风险评估
  6. 外部通信审计
  7. 权限审计
  8. [API 注入面审计](#API 注入面审计)
  9. [CMS 凭证存储审计](#CMS 凭证存储审计)
  10. 综合评分
  11. 安全加固建议

1. 项目概述

文章同步助手 (Wechatsync) 是一款开源免费的 Chrome 浏览器扩展,用于将文章一键同步到知乎、掘金、CSDN、头条等 29+ 平台。

架构组件

bash 复制代码
┌─────────────────────────────────────────────────┐
│                  Chrome 扩展 (MV3)                │
│  ┌──────────┐  ┌───────────┐  ┌──────────────┐  │
│  │Content   │  │Background │  │  Popup/Editor │  │
│  │Scripts   │→ │Service    │←→│  UI           │  │
│  │(DOM处理)  │  │Worker     │  │               │  │
│  └──────────┘  └─────┬─────┘  └──────────────┘  │
│                      │                          │
│              ┌───────┴────────┐                 │
│              │  MCP WebSocket  │                 │
│              └───────┬────────┘                 │
└──────────────────────┼──────────────────────────┘
                       │
              ┌────────┴────────┐
              │  MCP Server     │
              │  (Node.js)      │
              └────────┬────────┘
                       │ stdio/SSE
              ┌────────┴────────┐
              │  Claude Code    │
              └─────────────────┘

┌─────────────────────────────────────────────────┐
│                CLI 命令行工具                      │
│  (独立使用,通过 WebSocket 桥接浏览器 Cookie)       │
└─────────────────────────────────────────────────┘

项目结构

bash 复制代码
Wechatsync/
├── packages/
│   ├── extension/     # Chrome 扩展 (MV3) - 前端界面 + Content Scripts
│   │   ├── src/
│   │   │   ├── background/     # Service Worker (同步调度逻辑)
│   │   │   ├── content/        # Content Scripts (页面交互 + 文章提取)
│   │   │   ├── lib/            # 工具库 (analytics, logger, remote-config 等)
│   │   │   ├── mcp/            # MCP WebSocket 客户端
│   │   │   └── adapters/       # 扩展层适配器 (CMS 适配器等)
│   │   └── public/
│   │       └── inject-api.js   # 注入到所有页面的 JS API
│   ├── core/           # 核心逻辑 (共享)
│   │   └── src/
│   │       ├── adapters/       # 平台适配器基类 + 各平台实现
│   │       │   └── platforms/  # 知乎/微博/掘金等 20+ 平台适配器
│   │       │       └── private/ # Git 子模块: 私有适配器 (审计时为空)
│   │       ├── runtime/        # 运行时抽象 (浏览器/Node)
│   │       └── lib/            # 工具库 (markdown, image 处理等)
│   ├── mcp-server/     # MCP 协议服务器 (Node.js)
│   └── cli/            # 命令行工具

2. 认证机制分析

2.1 公域平台认证

扩展不存储任何平台的用户名和密码。认证机制如下:

typescript 复制代码
// runtime/extension.ts - Chrome 扩展运行时
class ExtensionRuntime implements RuntimeInterface {
  async fetch(url: string, options?: RequestInit): Promise<Response> {
    const response = await fetch(url, {
      ...options,
      credentials: 'include',  // 自动携带浏览器 Cookie
    })
    return response
  }

  cookies = {
    async get(domain: string): Promise<Cookie[]> {
      const cookies = await chrome.cookies.getAll({ domain })
      return cookies.map(c => ({ name: c.name, value: c.value, ... }))
    },
  }
}
机制 说明
Cookie 自动携带 API 请求使用 credentials: 'include',浏览器自动附加已登录平台的 Cookie
Cookie 读取 通过 chrome.cookies.getAll(domain) 检查登录态(仅用于认证状态判断)
无密码存储 知乎、微博、掘金等公域平台不需要也不存储用户密码

2.2 CMS (自建站) 认证

WordPress/Typecho 等自建站需要额外存储凭证:

typescript 复制代码
// background/index.ts
const storage = await chrome.storage.local.get(`cms_pwd_${accountId}`)
const password = storage[`cms_pwd_${accountId}`]
const credentials = { url: account.url, username: account.username, password }
  • 用户名存储在 cmsAccounts
  • 密码以 cms_pwd_{id} 为键存储在 chrome.storage.local
  • 密码以明文存储,未被额外加密

3. 数据流分析

3.1 文章同步数据流

bash 复制代码
┌──────────────┐   postMessage    ┌─────────────────┐   chrome.runtime   ┌──────────────────┐
│  Content      │ ←──────────────→ │  Background      │ ←──────────────→ │  各平台 API      │
│  Script       │  EXTRACT_ARTICLE │  Service Worker  │  fetch+credentials│  (知乎/微博/...)  │
│  (当前页面)    │                 │                  │                  │                  │
└──────────────┘                 └─────────────────┘                  └──────────────────┘
       │                                   │
       │ 读取 DOM                          │  adapterRegistry.get(platformId)
       │ 提取 title, html, markdown, cover  │  adapter.publish(article)
       │                                   │  → 创建草稿
       │                                   │  → 上传图片
       │                                   │  → 更新草稿内容

3.2 关键发现:数据不经过第三方服务器

bash 复制代码
✅  文章内容:         浏览器 → 目标平台 API(直连)
✅  图片上传:         浏览器 → 目标平台图床(直连)
✅  Cookie:           仅用于与目标平台 API 通信
❌  无中间服务器:      数据不经过 wechatsync.com 或任何第三方

4. 账号窃取风险评估

4.1 已排查的风险路径

风险路径 排查结果 证据
向第三方发送 Cookie ❌ 未发现 所有 fetch 调用的目标均为各平台官方 API
存储密码到外部 ❌ 未发现 无将 cms_pwd_* 发送到外部的代码
代码混淆隐藏通信 ❌ 未发现 源码完全开源,无混淆
Base64 隐藏端点 ❌ 未发现 Base64 仅用于图片 data URI 转换
DNS/网络重定向 ❌ 不可行 浏览器环境,无法控制 DNS 解析

4.2 所有外部网络请求白名单

目标 用途 是否含敏感数据
https://www.zhihu.com/api/* 知乎 API 调用 Cookie(同站)
https://zhuanlan.zhihu.com/api/* 知乎专栏 API Cookie(同站)
https://api.zhihu.com/* 知乎 API Cookie(同站)
https://card.weibo.com/* 微博 API Cookie(同站)
https://picupload.weibo.com/* 微博图床上传 图片数据
https://mp.weixin.qq.com/* 微信公众号 API Cookie(同站)
https://www.juejin.cn/* 掘金 API Cookie(同站)
(各平台官方域名) 各平台 API Cookie(同站)
https://www.google-analytics.com/* 匿名使用统计 ❌ 匿名数据(平台ID、成功/失败)
https://wpics.oss-cn-shanghai.aliyuncs.com/* 远程配置拉取 ❌ 只读,仅获取 UI 横幅配置
https://www.wechatsync.com/* 版本更新/欢迎页 ❌ 只读,打开新标签页

4.3 结论:账号窃取风险 --- 🟢 低

没有发现任何窃取账号的代码或机制。

  • 不存储密码(公域平台)
  • 不向第三方发送 Cookie
  • 所有通信直接与各平台官方 API 交互
  • 代码完全开源可审计

5. 未授权数据上传风险评估

5.1 数据上传控制链

bash 复制代码
用户操作触发 ─→ 选择目标平台 ─→ 确认同步 ─→ 执行上传
                                              ↓
                                        默认草稿模式
                                         (draftOnly: true)

5.2 同步触发路径

触发方式 是否需要用户操作 说明
Popup UI 选择平台 ✅ 显式用户操作 默认流程,用户手动选择平台
右键菜单打开编辑器 ✅ 显式用户操作 右键 → 编辑器 → 选择平台 → 同步
编辑器悬浮按钮 ✅ 显式用户操作 点击按钮 → 选择平台 → 同步
window.$poster.addTask() ⚠️ 无用户确认 任意网页可调用(见第 8 节)
MCP Server 调用 ✅ Token 鉴权 需正确的 MCP_TOKEN

5.3 结论:未授权上传风险 --- 🟡 中

  • 默认 UI 路径均有用户确认
  • window.$poster API 注入面是最值得关注的风险(见第 8 节)

6. 外部通信审计

6.1 Analytics 模块 (analytics.ts)

typescript 复制代码
const GA_MEASUREMENT_ID = import.meta.env.VITE_GA_MEASUREMENT_ID || ''
const GA_API_SECRET = import.meta.env.VITE_GA_API_SECRET || ''

// 发送的数据内容:
{
  client_id: "crypto.randomUUID()",    // 匿名随机 ID
  events: [{
    name: "sync_start",
    params: {
      source: "popup|mcp|editor",
      target_count: 3,
      targets: "zhihu,juejin,csdn",     // 仅平台 ID
    }
  }]
}

发送的内容类型:

  • 同步事件(开始/完成/失败)
  • 平台名称(仅 ID,如 "zhihu")
  • 成功/失败计数
  • 耗时段
  • 扩展版本号
  • 里程碑事件(首次同步、多平台等)

不发送的内容:

  • ✅ 不发送 Cookie 或 Token
  • ✅ 不发送文章内容
  • ✅ 不发送用户名或个人信息
  • ✅ 不发送 IP 地址(仅 GA 标准收集)

可禁用: 设置 VITE_GA_MEASUREMENT_IDVITE_GA_API_SECRET 为空即可完全禁用。

6.2 远程配置模块 (remote-config.ts)

typescript 复制代码
const CONFIG_URL = 'https://wpics.oss-cn-shanghai.aliyuncs.com/wechatsync-config.json'
  • 仅获取 UI 横幅列表(标题、描述、链接)
  • 无代码执行风险
  • 6 小时间隔缓存

6.3 版本检查模块 (version-check.ts)

typescript 复制代码
const VERSION_CHECK_URL = 'https://wpics.oss-cn-shanghai.aliyuncs.com/wechatsync-version.json'
  • 仅获取版本号和下载链接
  • 24 小时间隔

7. 权限审计

7.1 Manifest 权限 (MV3)

json 复制代码
{
  "permissions": [
    "storage",          // 存储设置、缓存、历史记录
    "unlimitedStorage", // 大文件存储
    "cookies",          // 读取浏览器 Cookie ★
    "declarativeNetRequest",        // 修改请求头 ★
    "declarativeNetRequestWithHostAccess", // 带主机访问的请求修改
    "scripting",        // 注入脚本 ★
    "tabs",             // 标签页管理
    "alarms",           // 定时任务
    "contextMenus",     // 右键菜单
    "downloads"         // 文件下载
  ],
  "host_permissions": [
    "http://*/*",       // 所有 HTTP 站点 ★★★
    "https://*/*"       // 所有 HTTPS 站点 ★★★
  ]
}

7.2 敏感权限分析

权限 必要程度 实际使用范围 风险
cookies ✅ 必要 仅用于读取各平台 Cookie 以验证登录态 🟡 理论上可读所有站点的 Cookie
declarativeNetRequest ✅ 必要 仅在同步时为特定平台 API 添加请求头 🟢 限定域名 + 限定资源类型
scripting ✅ 必要 注入 reader/extractor 到当前页面 🟢 仅用户操作的页面
<all_urls> ✅ 必要 需在各平台域下发请求 🟡 权限范围过大

7.3 权限最小化建议

当前 <all_urls> 权限是功能必需的(需要向 29+ 不同平台发请求),但存在滥用风险。


8. API 注入面审计

8.1 inject-api.js --- 核心风险点

文件 : packages/extension/public/inject-api.js

该脚本被注入到每一个 HTTP/HTTPS 页面中:

javascript 复制代码
// 注入到所有页面
window.$poster = poster;
window.$syncer = poster;

8.2 暴露的 API 方法

方法 功能 是否需要鉴权 风险等级
getAccounts() 获取已登录平台列表 ❌ 任意网站可调用 🟡 中(泄露登录状态)
addTask(task) 触发文章同步 ❌ 任意网站可调用 🟠 中高(可触发静默同步)
magicCall(data) 调用适配器任意方法 ❌ 任意网站可调用 🟠 中高(通用接口)
uploadImage(data) 上传图片 ❌ 任意网站可调用 🟡 中(消耗带宽/存储)
updateDriver(data) 更新驱动(已弃用) ✅ 域名白名单 🟢 低
startInspect(handler) 启动检查(已弃用) ✅ 域名白名单 🟢 低

8.3 攻击场景

一个恶意网站可以:

  1. 探测已登录平台:

    javascript 复制代码
    $syncer.getAccounts((accounts) => {
      // 获知用户在哪些平台有账号
      console.log(accounts)  // [{type: "zhihu"}, {type: "juejin"}, ...]
    })
  2. 触发静默同步:

    javascript 复制代码
    $syncer.addTask({
      post: { title: "恶意内容", content: "..." },
      accounts: [{ type: "zhihu" }, { type: "weibo" }]
    }, null, () => {})

    会在用户浏览器中创建草稿(但不会自动发布)

8.4 缓解因素

  • 同步默认草稿模式draftOnly: true),不会自动发布
  • 需要目标平台已有登录态 Cookie(用户必须已登录)
  • 敏感 API 有域名白名单限制
  • 该 API 是旧版兼容层,新版编辑器 UI 不依赖它

8.5 结论

这是整个代码库中最大的攻击面。 任何网站都可以:

  • 探知用户在哪些平台有账号
  • 在用户不知情的情况下触发同步操作

但受限于草稿模式和已登录态要求,实际危害有限。


9. CMS 凭证存储审计

9.1 存储方式

typescript 复制代码
// 账户信息
await chrome.storage.local.set({
  cmsAccounts: [
    {
      id: "uuid",
      name: "我的博客",
      type: "wordpress",  // wordpress | typecho | metaweblog
      url: "https://example.com/xmlrpc.php",
      username: "admin",
      isConnected: true,
    }
  ],
  // 密码(独立键存储)
  [`cms_pwd_${accountId}`]: "plain_text_password"
})

9.2 存储位置安全性

维度 评估
访问隔离 chrome.storage.local 仅本扩展可访问
传输加密 ✅ 仅通过 HTTPS 发送到自建站
存储加密 ❌ 明文存储,未使用 Web Crypto API 加密
访问控制 ❌ 扩展内任意代码均可读取

9.3 结论

  • 存储位置受浏览器沙箱保护,其他扩展或网站无法直接读取
  • 扩展内无额外访问控制,任何被注入的恶意代码均可读取密码
  • 建议使用 crypto.subtle.encrypt() 加密存储

10. 综合评分

安全评分卡

评估维度 评分 说明
🔒 账号窃取风险 🟢 不存储凭证、不经第三方服务器、源码开源
📤 数据外泄风险 🟢 数据直发各平台官方 API,无中间人
🪟 API 注入面 🟡 window.$poster 注入所有页面需关注
🔑 权限范围 🟡 cookies + <all_urls> 权限组合
🗄️ CMS 密码存储 🟡 明文存储,无额外加密
📡 远程配置 🟢 仅 UI 横幅,只读
📊 遥测数据 🟢 匿名使用统计,不含敏感数据
🔍 代码透明度 🟢 完全透明 完整开源,无混淆

整体安全评级:🟢 良好

该项目遵循了合理的安全设计原则,没有发现恶意或隐藏的窃取/上传行为。主要风险点属于功能必要的权限和旧版兼容 API。


11. 安全加固建议

11.1 高优先级

1. window.$poster API 加用户确认

  • 文件:inject-api.js + content/api.ts

  • 建议:在 addTaskmagicCall 触发时弹窗询问用户确认

  • 示例:

    typescript 复制代码
    // 在 content/api.ts 的 addTask 处理中
    if (!confirm('文章同步助手要将文章同步到平台,是否继续?')) {
      return sendToWindow({ eventID, result: { error: '用户取消' } })
    }

2. CMS 密码加密存储

  • 文件:background/index.ts
  • 建议:使用 crypto.subtle.encrypt() 加密后再存入 chrome.storage.local
  • 密钥可派生自扩展 ID 或使用 chrome.storage.session 短期存储

11.2 中优先级

3. Content Script API 白名单限制

  • 文件:content/api.ts
  • 建议:对 getAccounts 以外的所有 API 添加域名白名单检查
  • 开源自建站(如 https://github.com/wechatsync/article-syncjs)可提交 PR 加入白名单

4. Cookie 读取最小化

  • 文件:runtime/extension.ts
  • 建议:将 chrome.cookies.getAll 改为精确的 chrome.cookies.get 按需读取
  • 或限定 Cookie 读取域名为已知平台列表,而非任意域名

11.3 低优先级

5. 权限声明细化

  • 建议:在 manifest.json 的 host_permissions 中列出确切域名列表,而非 <all_urls>
  • 但需注意这会在添加新平台适配器时需要更新 manifest

6. 添加安全文档说明

  • 建议在 README 中添加安全审计章节,说明数据流向和隐私保护措施

附录:审计检查清单

  • 所有 fetch 请求目标域名记录
  • Cookie 读取/发送路径检查
  • 凭证存储方式检查
  • 外部服务器通信内容检查
  • Content Script 注入面检查
  • MCP Server 鉴权检查
  • 代码混淆/隐藏通信检查
  • Git 子模块审计(private/ 为空目录)
  • Manifest 权限合理性评估
  • 安装后网络连接审计(首次安装打开 wechatsync.com 欢迎页)

本报告基于 git commit 版本的完整源码审计,不包括构建过程引入的依赖或运行时动态加载的代码。

相关推荐
味悲1 小时前
Linux提权
linux·服务器·安全
万亿少女的梦1682 小时前
基于Spring Boot的游戏交易管理系统设计与实现
java·spring boot·mysql·系统设计·交易管理
闲猫2 小时前
Agent工程实践:从WorkFlow到多Agent协作的落地笔记
java·服务器·前端
笨蛋不要掉眼泪2 小时前
Java虚拟机:常用参数
java·开发语言·python
Mem0rin2 小时前
[MySQL] 聚合函数、分组查询、连接查询
android·mysql
亦暖筑序3 小时前
AgentScope-Java 入门:用 Middleware 审计 Agent 调用
java·ai编程·agentscope
码龙-DragonCoding3 小时前
一键批量提取音频、提取视频
android·音视频·提取
你驴我3 小时前
WhatsApp 消息撤回与编辑的幂等性设计实践
java·服务器·前端·后端·python
祉猷并茂,雯华若锦3 小时前
Win下完美解决Allure报错,生成Web自动化测试报告
android·python·selenium·自动化
青山木4 小时前
Hot 100 ---腐烂的橘子
java·数据结构·后端·算法·leetcode·广度优先