新闻详情

新闻详情

首页 / 资讯中心 / 详情

NPM供应链投毒:隐蔽触发机制与全链路防御实战

发布时间:2026/9/20 2:41:41来源:尧图网络
NPM供应链投毒:隐蔽触发机制与全链路防御实战
npm install 这条命令每个前端和 Node.js 开发者几乎每天都要敲。但你可能没认真想过你装进项目里的每一个字节真的都值得信任吗NPM 供应链投毒正是攻击者看准了这个“默认信任”的缺口把恶意代码伪装成看似正常的依赖混进你的开发环境、构建流程甚至生产服务器。更棘手的是现代投毒早就不是“装了就炸”的粗暴玩法而是通过隐蔽逻辑触发在特定的时间、环境、命令下才释放真正载荷让安全团队和开发者防不胜防。这篇文章我会以攻防双视角把 NPM 供应链投毒的常见手法、隐蔽逻辑触发的设计思路以及防守方从安装到运行的全链路排查方法拆开来讲。内容主要面向前端工程师、Node.js 后端开发者、DevOps 和刚接触供应链安全的安全工程师。我会尽量少讲空话多给能直接落地的检测命令和判断思路也会结合实际踩坑经验说明哪些 npm 报错是环境问题哪些可能是投毒的蛛丝马迹。1. NPM 供应链投毒为什么防不胜防供应链投毒并不是什么新概念但 NPM 生态几乎是为这类攻击“量身定制”的温床。理解这一点是后续所有防御动作的前提。1.1 依赖关系太深没人能肉眼看完全部先看一组数据一个中大型前端项目node_modules 里的文件数量动辄几万到几十万。你以为自己只装了十几个依赖实际上 package-lock.json 里可能躺着上千个包。这还没算间接依赖也就是“依赖的依赖的依赖”。任何一个中间层的小包被攻破整条依赖链上的项目都会遭殃。问题在于绝大多数开发者根本不会去读 node_modules 里的代码。构建工具、Babel 插件、ESLint 规则、PostCSS 插件、构建辅助脚本这些“工具类”依赖平时只负责跑流程谁会逐个去审计它们的源码攻击者很清楚这个盲区他们不挑大包下手专挑那些“小众但被大量项目间接引用”的包或者干脆伪造一个名字相似的新包等着粗心的开发者自己装进来。我见过很多团队package.json 里依赖一长串但 lock 文件从不认真维护甚至有人 .gitignore 里把 package-lock.json 直接忽略了。这种情况下每次 npm install 拉到的依赖版本都是“当时最新的”等于把供应链的稳定性完全交给了 registry 上维护者的自觉性。1.2 postinstall 脚本机制是一把双刃剑NPM 为了支持 native 模块编译和构建后处理提供了 preinstall、install、postinstall 这类生命周期脚本。这意味着一个包在安装时不止是文件被拷贝到 node_modules它还可以执行任意系统命令。举个例子很多 native 模块需要 node-gyp 编译postinstall 是必经之路。但攻击者也可以在这个脚本里写上 curl 下载、解密执行、写计划任务等逻辑。npm 6 及更早版本默认无条件执行生命周期脚本npm 7 之后依然会执行只是部分安装场景下控制台提示更明显。直到 pnpm 10 才默认禁止未白名单的依赖执行构建脚本这是后话。关键在于安装阶段执行脚本是平台提供的合法功能。防御方很难通过“一刀切禁掉所有脚本”来解决问题因为大量正常的包真的依赖这个机制。攻击者只需要把恶意代码伪装成“安装时的一个小步骤”就能在不引起注意的情况下完成首轮载荷植入。1.3 发布门槛低、包名仿冒成本极低任何人都可以在 npm 上注册账号并发布包这个过程通常几分钟就能搞定不需要实名认证也不需要代码审计。npm 官方对恶意包的处理大多是“发现后下架”但下架之前恶意包可能已经被下载了几万次。包名仿冒typosquatting是最常见的套路把 lodash 写成 lodahs把 request 写成 requrst把 angular/core 写成 angualr/core。这类攻击拼的就是“手滑率”——每天都有无数开发者在终端里敲错一个字母然后 npm 就默默把仿冒包装了进来。除了拼写近似还有 Unicode 同形字符攻击用西里尔字母替换相似拉丁字母肉眼几乎无法分辨。真实世界里event-stream 事件是典型的“维护者账号沦陷”案例攻击者通过社交工程拿到维护者权限发布了一个包含恶意模块的新版本专门窃取特定类型钱包的私钥下载量不小。ua-parser-js、coa、rc 等流行包也曾在 2021 年被植入挖矿和密码窃取代码。这些案例都指向同一个事实供应链上的任何一环失守下游所有依赖者都会买单。2. 隐蔽逻辑触发是怎么设计的为什么要搞“隐蔽触发”因为直接投毒的存活时间太短了。一个包装上就执行恶意命令、立刻产生外部连接安全设备、行为监控、甚至细心的开发者都可能马上发现。隐蔽逻辑触发的核心目标是让恶意代码在“不该出现的时间”才出现在“不该出现的机器”上才生效其余情况下表现得像个正常的包。2.1 从触发时机上做文章触发时机是隐蔽性的第一道门槛。常见的思路有三类。一类是环境探测触发。恶意代码先采集运行环境的信息主机名、用户名、MAC 地址、平台类型、是否处于 CI/CD 环境、是否在 Docker 容器里、当前工作目录路径、甚至附近的进程列表。只有当这些信息和攻击者预定义的目标特征匹配时才释放最终载荷。对不匹配的环境代码会表现得完全无害甚至正常执行包本身的功能。这种“定向投放”在渗透测试里叫鱼叉式钓鱼的供应链版在中大型企业内网里尤其有效因为开发机和服务器的主机名、用户名规律相对固定。另一类是延迟触发。攻击者不在 install 阶段立刻动手而是把后门代码藏在包的某个导出函数里或者通过 patch 原型链、劫持 require 等方式让恶意逻辑在开发者运行 npm run build、npm run dev、npm run serve 等命令时才被加载执行。构建过程涉及大量模块加载和代码执行混进去一条异常外联请求很难被肉眼发现。还有一类是时间触发。代码里设置一个定时器可以是安装后 7 天、14 天也可以是指定某个 Unix 时间戳。这样做的目的很简单等开发者最初安装时的警惕期过去等安全扫描的窗口期过去等到大家已经把这个包当成“环境的一部分”之后再动手。2.2 从载荷形态上做文章载荷形态决定了攻击的影响范围和检测难度。第一loader 远程拉取。install 脚本只写一个非常小的 loader可能是几行 Base64 编码的字符串也可能是从环境变量里拼出来的 URL。loader 在触发条件满足时去远程服务器下载真正的恶意模块并执行。这种设计的巧妙之处在于安装时落地的文件非常干净防病毒软件和依赖扫描工具很难从静态特征上发现问题真正的恶意文件从来不在 node_modules 里出现。第二功能前置 逻辑后门。攻击者把包的正常功能做得非常完整README 写得很专业API 用起来也顺手但在某个边缘功能分支里埋了后门。比如一个字符串处理库在遇到特定格式的输入时除了返回处理结果还偷偷把环境变量和当前目录列表发出去。这种包通过常规的代码走查很难发现问题因为整体代码质量高、功能正常恶意逻辑占比极小。第三依赖混淆dependency confusion。这个稍微特殊一点它不直接修改代码而是利用 npm 解析依赖时对版本号的偏好。当企业内部有私有包时如果私有包没有加 scope 前缀且公共 npm 上存在同名包攻击者就可以在公共源上传一个版本号更高的同名包。开发者安装时npm 可能会解析到公共源的“更高版本”从而把企业内部项目里本来用于内网的包替换成了攻击者的恶意版本。这个攻击在 2021 年被系统性地公开研究过很多大厂中招。2.3 从通信方式上做文章隐蔽逻辑触发还有一个绕不开的环节数据回传或指令接收。完全离线、单机自执行的恶意代码相对少见大部分攻击需要和攻击者保持联系因此通信方式的设计直接决定了暴露风险。攻击者偏好低噪音通道。比如通过 DNS 查询传递数据恶意代码把窃取到的信息编码成子域名发往攻击者控制的 DNS 服务器这种流量在传统防火墙里经常被忽略又比如把数据伪装成正常的 HTTPS 请求发送到伪装成统计服务、广告服务的域名再比如利用 GitHub、Gitee 等代码托管平台的 issue 或 release 作为指令通道。这些通信方式都有一个共同特征在流量侧看起来“像正常业务”没有明显的恶意特征。作为防守方你需要记住的是检测隐蔽逻辑触发不能只靠“装完扫一遍”需要把安装时行为、运行时网络连接、进程行为、文件系统变更串联起来看。3. 实战推演一次完整的投毒与触发过程这一节我会以“攻防演练/红队视角”做一个全流程拆解。目的不是教人作恶而是让防守方知道攻击者完整的思考链路才能在关键节点设防。3.1 造一个“看起来正常”的包攻击者的第一步是确定投毒目标。目标可能是某个特定公司的开发者也可能是某一类使用特定框架的人群。之后是包名规划要么仿冒高频依赖要么起一个蹭热点的名字比如紧跟当下流行的 AI 库、组件库、CLI 工具命名。为了让包看起来真实攻击者通常会认真写 README配上有模有样的 API 文档和示例代码甚至伪造 GitHub star 数和历史版本记录。发布时版本号也讲究一般从 1.0.0 开始避免用 0.x 这种“不成熟”的版本号引起怀疑。发布时间也会刻意挑在目标地区的工作日白天让“刚发布就被下载”看起来更自然。下载量造假也是常事。攻击者用一批代理或 CI 任务频繁安装自己的包把周下载量刷到几千甚至几万因为很多开发者选依赖时会参考下载量这个“社会证明”。到了这一步如果目标开发者真的拼错了包名或者被搜索引擎/社区文章推荐了这个仿冒包投毒链路就算成功了一半。3.2 利用 install 脚本布置静态载荷接下来是载荷落地。现代投毒大概率不会在 install 脚本里直接写 curl 下载木马那样太容易被杀。攻击者更常用的方式是做环境判断先让脚本在大多数环境里静静退出只在特定条件下继续。为了帮助你理解检测点我给你看一下这类脚本的典型逻辑结构示意不代表完整恶意代码// scripts/install.js示意代码用于理解检测思路 const os require(os); const fs require(fs); const path require(path); const hostname os.hostname(); const username os.userInfo().username; // 一命中 CI 或常见安全沙箱环境直接退出 if (process.env.CI || process.env.JENKINS_URL || process.env.GITLAB_CI) { process.exit(0); } // 二命中目标信息才执行下一步 if (hostname.startsWith(dev-) || username jenkins || fs.existsSync(/etc/company-agent)) { // 第二阶段载荷可能是从某个位置读取加密负载并解密 const payload fs.readFileSync(path.join(__dirname, .., data, config.bin), utf8); eval(payload); // 示意真实攻击会有更隐蔽的加载方式 }这种代码的安全检测点在哪里几个非常明显的特征install 脚本里出现了 os.hostname()、os.userInfo()、process.env 的异常读取出现了文件读取动态执行的组合出现了 CI 环境变量的特殊判断。任何一条都值得在依赖审计时多看一眼。3.3 触发阶段从安装到真正执行静态载荷落地之后真正的逻辑触发可以发生在任意时机。如果 loader 足够小它可能会被注入到某个正常的导出函数里应用启动时被自动加载。比如攻击者修改一个模块的 index.js在文件顶部加上 require 某个内部模块的逻辑这个内部模块再判断环境后执行恶意分支。触发后的动作通常是信息收集和回传。信息收集包括环境变量里面经常有云厂商密钥、数据库连接串、第三方 API Token、本地配置文件中保存的账号凭据、浏览器保存的密码如果权限允许、内网可达的主机列表等。回传通道会尽量伪装成正常业务流量。站在防御方角度触发阶段是最后一个也是最重要的拦截点。一旦恶意代码真正开始动作行为监控设备如 EDR、HIDS是有机会发现的。这也是为什么我后面会强调运行时监控而不是只依赖安装前扫描。4. 防守方该怎么做从安装到运行的全链路清单了解完攻击者思路下面这套防御清单你可以直接拿去用。我把重点放在“可落地”三个字上每一步都有明确的命令或配置。4.1 安装前锁定依赖、限制脚本第一件事把 package-lock.json 纳入版本管理统一使用 npm ci 安装。npm ci 会严格按照 lock 文件解析版本和 integrity 哈希不会做任何“顺便升级”。这一点能防止同一套代码在不同时间、不同机器上安装到不同版本的依赖。光是这个习惯就能规避大量抢跑型投毒包即恶意版本发布后正常 install 顺便拉取的情况。第二件事合理使用 --ignore-scripts。如果你只是安装纯 JS 依赖可以在 npm install 时加上 --ignore-scripts 跳过生命周期脚本从根上阻断 install/postinstall 阶段执行代码。但要注意某些 native 模块如 node-sass、sharp需要脚本编译这个开关会导致安装失败需要评估项目实际情况。更精细的做法是仅对特定项目设置npm install --ignore-scripts第三件事在 CI/CD 流水线里加入依赖漏洞扫描。npm audit 是最基础的能查已知漏洞库第三方商业/开源扫描工具如 Socket、Snyk、OSV-Scanner能识别依赖是否存在恶意脚本、异常网络访问等行为特征。建议至少跑两层一层是已知 CVE 漏洞库一层是包行为信誉。第四件事如果你用 pnpm建议开启 allow-scripts 管理机制。pnpm 10 默认不会执行未在 pnpm.onlyBuiltDependencies 里声明的依赖的构建脚本并会给出警告。这个特性非常实用等于把“哪些包可以执行脚本”变成了一份显式白名单。{ pnpm: { onlyBuiltDependencies: [esbuild, sharp] } }4.2 安装后审计依赖来源与完整性依赖装好了不等于万事大吉。我建议每次安装后、特别是引入新依赖后做一轮快速的依赖审计以下几个命令比较实用。# 查看某个包为什么被安装、被谁依赖 npm explain package-name # 查看依赖树中该包的实际位置 npm ls package-name # 查看当前项目所有依赖中哪些包自带 install 后脚本 npm query :attr(scripts, [postinstall]) --jsonnpm query 这个命令可能不少人不熟它可以用 CSS 选择器语法查询依赖元数据。上面这条会列出所有带 postinstall 脚本的包是快速排查投毒高危面的一种方式。如果发现某个不起眼的小包居然带 postinstall 脚本你就要多留一个心眼了。除了看脚本还要看 lock 文件里的来源域名。打开 package-lock.json搜索 resolved 字段确认所有包的下载地址都来自预期域名默认是 https://registry.npmjs.org/如果配置了镜像源则是镜像域名。如果混入了一个陌生域名或者某个包的 resolved 指向内网地址、IP 直连地址就要查清楚。完整性校验也不能少。lock 文件里的 integrity 哈希如果和 registry 上拉取到的包不一致说明内容可能在传输途中被篡改或者镜像源同步出了问题。执行以下命令可以验证缓存完整性npm cache verify4.3 运行中行为监控与最小权限安装阶段防住了脚本执行运行阶段的检测同样关键。隐蔽逻辑触发往往发生在应用启动、构建执行、或定时任务触发时这些行为如果没有任何监控你很难发现异常。第一给 Node.js 进程配置最小权限。Node.js 20 之后提供了实验性的权限模型可以限制文件系统读写路径、网络访问、子进程执行等能力。启动时加上一系列 --allow-* 参数把进程权限收窄到业务必需的最小范围。比如node --experimental-permission --allow-fs-read/app --allow-fs-write/tmp /app/index.js这样即使依赖里混入了恶意代码它想读取系统密码文件、想连非预期端口、想 spawn 子进程都会直接被拦截。这个功能目前还在实验阶段生产环境使用前建议充分测试。第二使用运行时行为监控。在服务器或开发机上如果条件允许可以部署轻量 HIDS 或基于 eBPF 的行为监控工具重点关注以下几类行为node 进程突然发起异常域名解析和网络连接node_modules 目录下文件在运行时被修改node 进程尝试读取 /etc/shadow、~/.ssh/id_rsa、~/.aws/credentials 等敏感文件node 进程尝试执行 shell 命令。这些行为单独看可能都不起眼组合在一起就是典型的供应链攻击特征。第三构建环境尽量使用容器隔离。CI 和本地构建默认是不可信环境不要把云厂商密钥、生产环境变量直接暴露给 build 阶段。如果投毒包的目的是偷密钥你的 CI/CD 环境就是它最喜欢的地方。后续开发者变多时才知道构建报错排查成本最高的往往不是代码逻辑而是依赖源不可信。4.4 镜像源与私服的风险管理热词里大量出现“npm镜像源地址”“npm国内镜像源”“npm换源”这背后是很多开发者因为网络原因把 registry 切到了公共镜像或自建私服。这本身是可以理解的操作但有几个风险点需要你注意。第一镜像源的同步机制决定了你拿到的包可能和官方源存在时间差。正常情况下这是无害的但如果你发现某个包在镜像源上的 integrity 哈希和官方源不一致必须立刻停下这可能意味着镜像源被污染或同步缺陷。第二自建私服比如 Verdaccio、Nexus时要特别注意依赖混淆问题。私有包必须使用 scope 前缀例如 yourcompany/xxx并在项目 .npmrc 里显式指定 scope 对应的 registryyourcompany:registryhttps://npm.yourcompany.com/对于没有 scope 的公共依赖统一从官方源或可信镜像同步不要让私服同时承担“公共代理”和“私有仓库”两种角色而不做区分。否则攻击者上传一个高版本的公共同名包你的私服会把这个恶意版本代理给所有内部项目。第三更换 npm 源之后建议清空 npm 缓存再装一次避免本地缓存里的旧包和镜像源的新包混合产生不可预期的问题。命令很简单npm cache clean --force npm install5. 常见 npm 报错与供应链风险的“真假信号”开发过程中经常遇到各种 npm 报错有些纯粹是环境或网络问题有些则可能和供应链风险相关。这里我结合常见热词做一张排查对照表帮你在报错时快速判断“要不要往供应链方向想”。5.1 环境类报错与中毒迹象怎么区分现象常见原因处理建议是否需要警惕供应链风险npm : 无法加载文件 ...npm.ps1因为在此系统上禁止运行脚本PowerShell 执行策略限制以管理员身份执行 Set-ExecutionPolicy RemoteSigned 或使用 cmd 运行不需要但注意不要为了省事设置 Unrestrictednpm WARN deprecated node-domexception1.0.0依赖被上游弃用检查依赖链上哪个包引用了它升级对应包低但长期不升级的依赖意味着维护者不活跃npm ERR! code EUNSUPPORTEDPROTOCOLlock 文件或依赖地址使用了不受支持的协议如 git://检查 package-lock.json 的 resolved 字段改用 https中确认 resolved 域名来源是否异常npm ERR! code ERESOLVE overriding peer dependencypeer 依赖冲突尝试 npm install --legacy-peer-deps但要评估风险中该选项会跳过部分依赖冲突校验可能掩盖恶意依赖npm ERR! code EBUSY文件被占用Windows 常见关闭相关 IDE 和进程删除 node_modules 后重装低npm run dev network: use --host to exposeVite/Webpack dev server 默认监听 localhost如需要局域网访问按提示加 --host不建议长期暴露低但长期暴露开发端口是网络安全风险npm 不是内部或外部命令 / 环境变量 path 配置错误Node.js 未安装或 PATH 未配置重新安装 Node.js 并配置环境变量低但安装源要选官方渠道pnpm: allow-scripts ... not yet covered by allow listpnpm 10 默认阻止依赖执行构建脚本按需把可信依赖加入 onlyBuiltDependencies高这是 pnpm 的安全特性不要为了省事全量放行这张表不是一个绝对的判断标准但它能帮你快速定位遇到报错先解决环境问题然后回头看一眼依赖来源而不是盲目地换源、加 --force、删 lock 文件。5.2 一次模拟应急响应的完整过程假设你在一次依赖升级后发现应用启动阶段出现可疑的外联请求接下来该怎么处理我按实际排查顺序给你演示一遍。第一步确认当前依赖树和可疑包的位置。先用命令找到引入链npm ls suspicious-package npm explain suspicious-package第二步检查可疑包的脚本和入口文件。进入 node_modules/ 目录看 package.json 中的 scripts 字段特别是 install、postinstall、preinstall 和入口文件的 require 逻辑。cat node_modules/suspicious-package/package.json | jq .scripts第三步查看 lock 文件中该包的来源和完整性哈希。grep -A 5 node_modules/suspicious-package package-lock.json重点看 resolved 是否来自预期 registryintegrity 是否和 registry 上的一致。如果 resolved 指向陌生域名立即断网隔离机器。第四步检查运行时的网络连接和进程行为。在 Linux 上# 查看 node 进程建立的 TCP 连接 ss -tnp | grep node # 跟踪进程的文件和网络调用需要 strace strace -f -e tracenetwork,file,process -p pid如果发现 node 进程连接到非预期 IP 或域名优先断开网络并保留现场。第五步确认被投毒后不要只删包了事。你需要做三件事一是从 lock 文件回溯引入时间git log package-lock.json判断影响范围二是检查该包是否在你多台机器或 CI 里被使用统一清理三是排查数据泄露面重点检查环境变量、配置文件中是否包含敏感凭据必要时轮换密钥。第六步修复。升级到安全版本或者移除依赖把该包加入项目的依赖黑名单在 CI 的扫描策略里禁用如果是公共 npm 上的恶意包到 npm 官方渠道举报下架。6. 写在最后的个人体会说句实在话我在实际做安全建设时发现最难防的不是那些一眼假的恶意包而是“功能正常 小动作不断”的灰色依赖。很多团队连 package-lock.json 都不提交更别说对 postinstall 脚本做审计了。供应链安全的本质是把“默认信任”改成“持续验证”这个过程没有银弹只能靠一个个具体动作堆出来。最后再分享一个我自己的习惯每次执行 npm install 之前我都会先看一眼终端里有没有出现奇怪的 warn 或者我没见过的脚本提示每次引入新依赖我会顺手跑一下 npm view scripts 看看它有没有 install 脚本每次构建异常时我会先怀疑依赖源而不是急着换源重装。这些习惯不需要额外工具成本几乎为零但确实能帮你挡住不少低级投毒。如果你觉得自己项目里依赖管理比较混乱我建议从今天开始做三件事把 lock 文件提交进仓库在 CI 里加依赖扫描给项目里的构建脚本加上最小权限。这三件事做完你的供应链风险至少能降一半。剩下的就得靠持续的运行时监控和应急响应能力来补了。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Page Assist 实战指南:3 步把本地 AI 模型装进浏览器侧边栏 2026/9/20 3:29:49

Page Assist 实战指南:3 步把本地 AI 模型装进浏览器侧边栏

Page Assist 实战指南:3 步把本地 AI 模型装进浏览器侧边栏 【免费下载链接】page-assist Use your locally running AI models to assist you in your web browsing 项目地址: https://gitcode.com/GitHub_Trending/pa/page-assist Page Assist 是一个本地 …

阅读更多 →
QQ空间说说备份:用GetQzonehistory免费备份全部历史说说 2026/9/20 3:29:49

QQ空间说说备份:用GetQzonehistory免费备份全部历史说说

QQ空间说说备份:用GetQzonehistory免费备份全部历史说说 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 打开QQ空间网页把说说往早年翻,互动列表只展示有限页数&…

阅读更多 →
Spring AI Alibaba实战:用Java快速构建通义千问AI应用 2026/9/20 3:29:49

Spring AI Alibaba实战:用Java快速构建通义千问AI应用

做后端这么多年,我有个特别明显的感受:Java圈子上手大模型应用的速度,始终比Python圈子慢半拍。不是Java不行,是那时候合适的落地框架太少。直到Spring AI正式进入Spring家族,阿里又在它上面开源了Spring AI Alibaba&a…

阅读更多 →
LibreChat开源对话平台:生产级AI应用基座解析 2026/9/20 3:29:49

LibreChat开源对话平台:生产级AI应用基座解析

1. LibreChat 是什么?一个真正能落地的开源对话平台LibreChat 不是另一个“玩具级”聊天界面,也不是简单套壳 OpenAI API 的前端页面。它是一个完整、可自托管、支持多模型、多后端、带记忆与插件能力的生产级对话平台,核心定位是&#xff1a…

阅读更多 →
Paper Tabs 组件完全指南:基于 Polymer 的 Material Design 选项卡实战解析 2026/9/20 3:29:49

Paper Tabs 组件完全指南:基于 Polymer 的 Material Design 选项卡实战解析

示例工程前端 【免费下载链接】todomvc Helping you select a JavaScript framework - Todo apps for React.js, Angular, Vue and many more 项目地址: https://gitcode.com/gh_mirrors/to/todomvc 点击查看 免费下载 本文以仓库 bower_components/paper-tabs 目录…

阅读更多 →
Trae AI 与 VSCode 接入第三方中转 API 配置指南:多模型调用与报错排查 2026/9/20 3:26:49

Trae AI 与 VSCode 接入第三方中转 API 配置指南:多模型调用与报错排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞