适用场景
开发机上装着 IDE、桌面客户端、命令行工具和浏览器扩展,其中不少工具会在升级时夹带 AI 组件,用户既没点过同意,也不清楚它往哪里发数据。这套流程用于定期给开发机做一次体检:列出所有插件与扩展、找出静默安装留下的痕迹、抓取实际出网流量,并把不需要的开关关掉。适合个人开发者、小团队运维,以及需要向公司交付「开发机安全自查记录」的人。文中以社区曾报告的「Postman 桌面客户端更新后出现用户未主动安装的 AI 相关扩展与常驻进程」这类事件作为样例,具体细节以厂商公告和安全社区报告为准,排查方法本身是通用的。
环境与前置条件
- 操作系统:macOS 主流版本、常见 Linux 发行版、Windows 10 及以上均可,具体支持范围以各工具官方文档当前版本为准。
- Shell:macOS 和 Linux 使用 bash 或 zsh;Windows 使用 PowerShell 7 及以上体验更好。
- 运行时:需要 Python 3 用于运行 mitmproxy(可选组件);Node.js 不是必需项。
- 权限:查看本进程网络连接用普通用户即可;抓包、查看系统安装日志、修改防火墙规则需要 sudo 或管理员权限。
- 磁盘:预留 1GB 左右,用于存放抓包文件和历史快照;单次抓包 10 分钟通常只产生几十 MB。
- 依赖工具:
lsof、ss或netstat、tcpdump、jq、find、curl。Linux 上ss属于 iproute2 包;macOS 自带lsof和tcpdump;Windows 建议在 WSL 或 Git Bash 里执行本文的 shell 命令。 - 网络:抓包只在自有设备、自有网络里进行,不要对他人网络或公司生产网段做流量镜像。
分步骤部署
第 1 步:建立基线快照
先记录当前状态,后面所有「异常」都是相对这份基线而言的。
```bash
mkdir -p ~/plugin-audit/$(date +%Y%m%d) && cd ~/plugin-audit/$(date +%Y%m%d)
进程列表(含启动时间)
ps -Ao pid,ppid,user,lstart,command > ps.txt
监听端口(macOS)
lsof -nP -iTCP -sTCP:LISTEN > listen.txt
监听端口(Linux 用这条替换上一行)
ss -tunlp > listen.txt
已建立的外部连接
lsof -nP -i > conn.txt
```
Windows 对应命令:
```powershell
Get-Process | Select-Object Id,ProcessName,StartTime,Path | Export-Csv ps.csv -NoTypeInformation
Get-NetTCPConnection | Export-Csv conn.csv -NoTypeInformation
```
这步在做什么:把「谁在跑、谁在监听、谁连出去了」三件事落成文件。成功标志是三个文件都非空,wc -l ps.txt conn.txt 有输出即可。
第 2 步:盘点插件与扩展清单
```bash
VS Code 扩展(先确认 code 命令在 PATH 里)
code --list-extensions --show-versions > vscode-ext.txt
按安装时间排序,最新的排最前
ls -lt ~/.vscode/extensions | head -30
```
JetBrains 系列看插件目录:
```bash
ls -lt ~/Library/Application\ Support/JetBrains/*/plugins 2>/dev/null
ls -lt ~/.local/share/JetBrains/*/plugins 2>/dev/null
```
浏览器扩展(Chrome 系):
```bash
ls -lt ~/Library/Application\ Support/Google/Chrome/Default/Extensions 2>/dev/null | head -20
ls -lt ~/.config/google-chrome/Default/Extensions 2>/dev/null | head -20
```
目录名是扩展 ID,想确认身份就翻每个目录下的 manifest.json:
```bash
for d in ~/.config/google-chrome/Default/Extensions/*/*/; do
jq -r '"\(.name) \(.version)"' "$d/manifest.json" 2>/dev/null
done
```
清单核对重点:有没有你不认识的扩展 ID、有没有名字里带 AI 但你没装过的条目、版本号和上次记录是否对不上。
第 3 步:找静默安装的痕迹
静默安装通常会在三个地方留痕:文件修改时间、系统安装日志、启动项。
```bash
近 14 天被创建或修改的用户目录(-mtime -14 表示 14 天内)
find ~ -maxdepth 4 -type d -mtime -14 2>/dev/null | grep -v -E 'Cache|cache|node_modules|\.git' | head -50
应用目录里近期变动
ls -lt /Applications | head -20
```
查系统安装日志:
```bash
macOS
grep -i postman /var/log/install.log | tail -50
Linux
grep -i postman /var/log/dpkg.log /var/log/apt/history.log 2>/dev/null | tail -50
```
```powershell
Windows
Get-WinEvent -LogName Application -MaxEvents 500 | Where-Object { $_.Message -like "*Postman*" }
```
查开机自启:
```bash
macOS:用户级 LaunchAgent
ls -lt ~/Library/LaunchAgents /Library/LaunchAgents /Library/LaunchDaemons 2>/dev/null
launchctl list | grep -i -E 'postman|agent|ai'
Linux:systemd 用户单元与 autostart
systemctl --user list-unit-files --state=enabled
ls -lt ~/.config/autostart 2>/dev/null
```
还要看应用包内部有没有夹带别的东西。桌面客户端把扩展或小工具塞进自己的 Contents/Resources 是常见做法:
```bash
ls -la /Applications/Postman.app/Contents/Resources 2>/dev/null | head -30
find /Applications/Postman.app -name "*.vsix" -o -name "*.crx" 2>/dev/null
```
看到 .vsix(VS Code 扩展包)或 .crx(Chrome 扩展包)就是明确信号:应用在替你装插件。这步的成功标志是能说出「哪个文件、什么时间、由谁创建」。
第 4 步:抓出网流量
先看静态快照,成本比较低:
```bash
只看某个进程的连接(-a 表示条件之间取交集)
lsof -nP -i -a -c Postman
所有外部连接,排除本地回环
lsof -nP -i | grep -v '127.0.0.1' | grep -v '\[::1\]'
```
再做动态抓包,先抓 DNS 就能看出它在解析哪些域名:
```bash
sudo tcpdump -n port 53 -w ~/plugin-audit/dns.pcap
跑 3 到 5 分钟,然后 Ctrl+C
sudo tcpdump -nr ~/plugin-audit/dns.pcap | grep -oE 'A\? [a-z0-9.-]+' | sort -u
```
macOS 如果没有 any 伪设备,把命令里的接口写成实际网卡(en0 等),用 ifconfig 查。
想看 HTTPS 请求内容,用 mitmproxy 做本地代理:
```bash
pip install --user mitmproxy # 版本以官方文档当前版本为准
mitmproxy --listen-port 8080
```
另开一个终端,把目标程序指向代理:
```bash
HTTPS_PROXY=http://127.0.0.1:8080 HTTP_PROXY=http://127.0.0.1:8080 open -a Postman
```
首次使用要在系统里信任 mitmproxy 的 CA 证书(访问 http://mitm.it 按提示装)。需要提醒的是:部分客户端做了证书固定(certificate pinning),设了代理也看不到明文,这时退回到 DNS 层和连接层观测即可,能确认「连了谁、连了多少次」已经够用。
判读要点:遥测域名、更新检查域名、AI 服务域名是三类不同性质的流量。遥测是行为数据上报,更新检查只是拉版本号,AI 服务域名意味着你的输入内容可能被发出去。把抓到的域名按这三类归档,记进快照。
第 5 步:关闭配置并做网络层兜底
应用内开关优先。Postman 桌面端的 Settings 里有使用数据上报、自动更新通道、AI 相关功能的开关,具体命名以客户端当前版本为准;找到后逐项关闭并重启客户端复查。VS Code 里禁用可疑扩展:
```bash
code --disable-extension <publisher.extension-id>
确认卸载
code --uninstall-extension <publisher.extension-id>
```
应用内开关关不干净时,用网络层兜底。macOS 和 Linux 都可以先用 hosts 把域名指到黑洞(把占位域名换成第 4 步实际抓到的):
```bash
sudo sh -c 'printf "0.0.0.0 telemetry.example.com\n0.0.0.0 ai.example.com\n" >> /etc/hosts'
```
Linux 用 ufw 按目标 IP 拒绝出站:
```bash
sudo ufw deny out to <目标IP>
sudo ufw status numbered
```
Windows 用 PowerShell 建出站规则:
```powershell
New-NetFirewallRule -DisplayName "Block Postman Telemetry" -Direction Outbound -Program "C:\Path\To\Postman.exe" -Action Block
```
验证部署是否成功
把前面的检查固化成脚本,每次跑一遍:
```bash
cat > ~/plugin-audit/audit.sh <<'EOF'
#!/usr/bin/env bash
set -u
TS=$(date +%Y%m%d-%H%M)
OUT=~/plugin-audit/$TS
mkdir -p "$OUT"
ps -Ao pid,user,lstart,command > "$OUT/ps.txt"
lsof -nP -iTCP -sTCP:LISTEN > "$OUT/listen.txt" 2>/dev/null || ss -tunlp > "$OUT/listen.txt"
lsof -nP -i > "$OUT/conn.txt" 2>/dev/null
code --list-extensions --show-versions > "$OUT/vscode-ext.txt" 2>/dev/null
echo "snapshot -> $OUT"
EOF
chmod +x ~/plugin-audit/audit.sh
~/plugin-audit/audit.sh
```
预期结果是打印出一行 snapshot -> /home/<user>/plugin-audit/<时间戳>,目录里至少 4 个非空文件。
逐项验证:
```bash
1. 插件清单里没有陌生条目
comm -13 <(sort ~/plugin-audit/<旧时间戳>/vscode-ext.txt) <(sort ~/plugin-audit/<新时间戳>/vscode-ext.txt)
无输出 = 没有新增扩展,最理想
2. 目标进程没有连向可疑域名
lsof -nP -i -a -c Postman | grep -v -E '127.0.0.1|\[::1\]'
只应看到你认可的地址,其余为空
3. hosts 拦截生效
ping -c 1 telemetry.example.com
预期解析到 0.0.0.0 或直接失败
4. 防火墙规则在位
sudo ufw status | grep -i deny
```
四项都过,说明体检闭环完成:清单可追溯、连接可解释、拦截可验证。
常见报错与解决
报错:tcpdump: en0: You don't have permission to capture on that device
原因:抓包需要 root 权限或网卡捕获权限。
解决:
```bash
sudo tcpdump -n port 53 -w ~/plugin-audit/dns.pcap
或者给当前用户授予捕获权限(macOS)
sudo chown "$USER" /dev/bpf*
```
报错:lsof: Operation not permitted 或输出为空
原因:在 macOS 上,受系统完整性保护(SIP)限制,普通用户看不到其他用户或其他应用的网络连接;在 Linux 上则是目标进程属主不同。
解决:
```bash
sudo lsof -nP -i -a -c Postman
macOS 另外在「系统设置 → 隐私与安全性 → 完全磁盘访问权限」里给终端授权
```
报错:jq: command not found
原因:缺少 JSON 解析工具,扩展清单解析脚本跑不下去。
解决:
```bash
macOS
brew install jq
Debian/Ubuntu
sudo apt install jq
```
报错:mitmproxy: certificate verify failed 或代理后应用直接断网
原因:没有在系统钥匙串或受信任根证书里安装 mitmproxy 的 CA,或者应用使用了证书固定。
解决:先按 mitmproxy 官方文档安装并信任 CA;仍有问题说明对方做了证书固定,放弃解密,改回 DNS 抓包和连接层观测:
```bash
sudo tcpdump -n 'port 53 or port 443' -w ~/plugin-audit/traffic.pcap
```
报错:VS Code 提示 Extension is not installed 但目录里明明有
原因:扩展目录残留但注册信息已损坏,常见于应用替用户静默安装后又被手工删除。
解决:
```bash
rm -rf ~/.vscode/extensions/<publisher.extension-id>-*
code --list-extensions --show-versions | grep -i <keyword>
```
后续维护
- 备份:把
~/plugin-audit目录整体纳入版本管理或用tar czf定期打包,每次体检的快照都是下一次比对的基准,删掉旧快照就没法做差分。应用配置目录(如~/Library/Application Support/Postman、~/.config/Code/User)单独备份一份,方便出问题时回滚。 - 升级:桌面客户端和 IDE 升级后必跑一次体检脚本,重点看扩展清单的差集。关闭「自动下载大版本更新」,改为手动检查,避免升级时被顺手装上东西。工具版本以官方文档当前版本为准,不要长期停留在无人维护的版本。
- 日志:保留每次的
dns.pcap、conn.txt和脚本输出,统一放进带时间戳的目录。出现异常出网时,靠历史 pcap 能快速判断是新行为还是长期存在。 - 监控:Linux 可以用
systemd定时器每天跑一次快照脚本;macOS 用launchd的StartCalendarInterval;Windows 用计划任务。发现新增扩展、新增自启项、出现未登记域名时输出告警。 - 固化规则:维护一份「允许出网域名清单」,新出现的域名先记录、再判断、最后决定是否加白,避免每次都靠记忆判断。团队场景下把这份清单和体检脚本一起纳入代码仓库,新人入职照着跑一遍即可。
