ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

@eggjs/security 安全插件完全指南:Egg 应用的 Web 安全防护、CSRF 与 XSS 过滤实战

@eggjs/security 安全插件完全指南:Egg 应用的 Web 安全防护、CSRF 与 XSS 过滤实战 后端Web框架【免费下载链接】egg Born to build better enterprise frameworks and apps with Node.js Koa. https://307.run/eggcode项目地址https://gitcode.com/gh_mirrors/eg/egg点击查看免费下载eggjs/security是 Egg 框架内置的 Web 安全插件默认开启、零配置即可为应用提供 CSRF/CTOKEN 防跨站、安全重定向、XSS 过滤 Helper、Web 安全响应头与 HTTP 方法限制等一整套防护能力。本文以 plugins/security/README.zh-CN.md 为骨架结合插件源码逐项拆解每一项防护的配置方式、底层实现原理与适用场景帮助你理解安全插件到底做了什么并能按业务需要精准地开启、关闭或裁剪某一项安全策略。一、插件定位与快速上手eggjs/security位于仓库 plugins/security 目录是 Egg 默认加载的安全插件因此绝大多数场景下无需任何配置即可生效。在 Egg 应用中你可以直接修改config/config.js或 TypeScript 项目中的config/config.default.ts来调整其行为exports.security { xframe: { value: SAMEORIGIN, }, };1.1 关闭某项安全防范安全插件默认启用一套完整的防护集合。如果某项防护与你的业务冲突例如需要被第三方以 iframe 嵌入页面而关闭xframe只需将该配置项的enable设为falseexports.security { xframe: { enable: false, }, };从源码 plugins/security/src/app/middleware/securities.ts 可以看出插件启动时会把各项安全中间件 compose 成一个统一的security中间件其中每一项若enable false都会被直接跳过。同时源码也给出了一个兼容性提示老版本可能使用config.security.xframe false这种写法当前版本会打印警告推荐一律使用{ enable: false }的对象形式。1.2 match 与 ignore按路径精准控制安全插件的每一项子配置都支持match与ignore两个路由匹配选项取值可以是字符串路径、正则表达式、函数或它们的数组。例如只对/example路径开启 CSPexports.security { csp: { match: /example, // match: /^\/api/, // support regexp // match: ctx ctx.path.startsWith(/api), // support function // match: [ ctx ctx.path.startsWith(/api), /^\/foo$/, /bar], // support Array policy: { //... }, }, };再如忽略/example路径上的xframe防护以便合作商户能够嵌入本页面exports.security { xframe: { ignore: /example, // ignore: /^\/api/, // support regexp // ignore: ctx ctx.path.startsWith(/api), // support function // ignore: [ ctx ctx.path.startsWith(/api), /^\/foo$/, /bar], // support Array // ... }, };注意如果同时配置了match和ignore以match为准ignore会被忽略。这一逻辑在源码 plugins/security/src/app/middleware/securities.ts 中有明确实现二者同时存在时输出 warning 并清空ignore。另外顶层config.security.match/config.security.ignore已不推荐使用源码会提示请在各项子配置上设置。从实现上看每项配置最终都会通过pathMatching(opt)来自eggjs/path-matching包编译成匹配函数注入到对应中间件选项中中间件通过checkIfIgnore(opts, ctx)判断当前请求是否命中放行条件见 plugins/security/src/lib/utils.ts。二、全局配置模型默认开启哪些中间件安全插件的全部配置项定义在 plugins/security/src/config/config.default.ts使用 zod 做运行时校验并给出默认值。最核心的两个全局配置是domainWhiteList安全域名白名单默认[]用于安全重定向、shtml的 href/src 域名校验等场景protocolWhiteList协议白名单默认[]会与内置的http、https、file、data合并后用于surl校验defaultMiddleware默认启用的安全中间件列表默认值为csrf, hsts, methodnoallow, noopen, nosniff, csp, xssProtection, xframe, dta既可传逗号分隔的字符串也可传数组。在 plugins/security/src/app/middleware/securities.ts 中插件遍历defaultMiddleware从lib/middlewares/index.ts见 plugins/security/src/lib/middlewares/index.ts按名称取出对应中间件工厂逐个 compose 成一个总中间件。这意味着你可以在defaultMiddleware中整体增删中间件也可以靠单项的enable开关控制。值得说明的是当前源码中hsts的enable默认值为falseconfig.default.ts即Strict-Transport-Security 头默认不输出需要 HTTPS 站点按需开启而 README 中hsts 默认开启的描述相对旧版本而言已过时本文统一以当前仓库源码为准。三、CSRF 与 CTOKEN跨站请求伪造的防范3.1 基本用法ctx.csrfCSRF跨站请求伪造的防范思路是在写请求中校验一个只有本站页面才能拿到的 token。插件通过ctx.csrf暴露 token一般配合 POST 表单使用——页面渲染时将ctx.csrf作为表单隐藏域或 query string 渲染到页面上key 为_csrf提交表单时携带该 token 即可通过校验。formData 上传时使用 csrfform methodPOST action/upload?_csrf{{ ctx.csrf | safe }} enctypemultipart/form-data title: input nametitle / file: input namefile typefile / button typesubmit上传/button /form从源码 plugins/security/src/app/extend/context.ts 可以看到ctx.csrf并非直接返回 secret而是基于csrf库用 secret 生成一个加了随机盐的 token——这是为了抵御 BREACH 类攻击避免 token 与 secret 完全一致被暴力探测。3.2 CTOKENAjax 场景的防跨站对于 Ajax 请求页面拿不到隐藏域插件提供了 ctokencookie token方案插件会把一个随机 secret 种到 cookie 中前端发起 Ajax 时以ctoken为字段名携带该值即可。ctoken 的获取与校验由以下方法承担文档明确约定这些是插件内部方法使用者不要调用ctx.ctoken获取 ctoken 的逻辑内部使用ctx.setCTOKEN()设置 ctoken 的逻辑内部使用ctx.assertCTOKEN()ctoken 校验逻辑内部使用。一个关键的域名设计是ctx.setCTOKEN()会把 cookie 设置到主域名下以支持主域名下不同子域名应用间的互相调用。例如在A.xx.com域种下 ctokencookie 会设置到xx.com域上之后在B.xx.com域可以利用该 ctoken 发起请求当 A 域通过 jsonp 请求 B 域时B 域同样可以验证 ctoken。token 存在哪个 cookie、存什么字段等细节都可以通过上述接口扩展定制。3.3 csrf 配置项全解完整的csrf配置项及默认值如下与 config.default.ts 中 zod schema 完全对应exports.security { csrf: { type: ctoken, // 可以是 ctoken / referer / all / any默认为 ctoken useSession: false, // 如果设为 truesecret 将存储在 session 中需启用 session 插件否则启动报错 ignoreJSON: false, // 如果设为 true将忽略 json 请求已标记为不安全不建议使用 cookieName: csrfToken, // csrf 的 token 在 cookie 中存储的 key 名称支持字符串数组便于平滑迁移 cookie 名 sessionName: csrfToken, // csrf 的 token 在 session 中存储的 key 名称 headerName: x-csrf-token, // csrf token 在 header 中的名称 bodyName: _csrf, // csrf token 在 body 中的名称支持字符串数组 queryName: _csrf, // csrf token 在 query 中的名称支持字符串数组 rotateWhenInvalid: false, // csrf invalid 时刷新 token用于同域名下多个业务 token 可能互相影响的情况 refererWhiteList: [], // referer 白名单仅 type 为 referer 时生效 supportedRequests: [ // 支持的 url path pattern 和方法按名单由上至下匹配 url path 正则 // 建议在自定义时配置 {path: /^\//, methods:[POST,PATCH,DELETE,PUT,CONNECT]} 为兜底规则 { path: /^\//, methods: [POST, PATCH, DELETE, PUT, CONNECT] }, ], // 以下为源码中可选的进阶配置 // cookieDomain: undefined, // 可为字符串或 (ctx) string默认以安全方式自动设置 // cookieOptions: { signed: false, httpOnly: false, overwrite: true }, }, };其中supportedRequests是最灵活的开关methods可以为空数组如果把supportedRequests配置为[{ path: /^\//, methods: [] }]则等效于关闭 csrf 防御。csrf 中间件的匹配流程见 plugins/security/src/lib/middlewares/csrf.ts先检查 ignore再确保 secret 存在然后按supportedRequests逐条匹配path与method命中才执行ctx.assertCsrf()。3.4 四种校验类型与底层校验逻辑type支持ctoken、referer、all、any四种取值校验逻辑集中在 plugins/security/src/app/extend/context.ts 的assertCsrf()中ctoken校验请求携带的 token从 query → body → header 依次查找与 cookie/session 中的 secret 是否匹配不通过则抛 403referer校验Referer/Origin头是否落在refererWhiteList与当前 host 构成的域名白名单内allctoken 与 referer 两者都校验任一失败即 403any两者任一通过即放行都失败才 403。token 的查找顺序为 query、body、header对应queryName、bodyName、headerName。此外ensureCsrfSecret()负责在首次请求时生成并种下 secret存 cookie 或 sessionrotateCsrfSecret()可在用户登录等时机主动轮换 secret当校验失败且配置了rotateWhenInvalid: true时也会自动轮换避免同域多业务 token 相互影响。四、安全重定向safe redirect开放重定向Open Redirect是一种常见的 Web 漏洞攻击者构造跳转到钓鱼站点的链接诱导用户。安全插件覆盖了默认的ctx.redirect方法让所有跳转都经过安全域名判断ctx.redirect(url)如果目标 url 不在白名单内则禁止跳转ctx.unsafeRedirect(url)绕过安全校验的原始跳转不建议使用。使用ctx.redirect前需要在应用配置中声明安全白名单以.开头exports.security { domainWhiteList: [.domain.com], // 安全白名单以.开头 };特别要注意如果没有配置domainWhiteList或数组为空则默认对所有跳转请求放行行为等同于ctx.unsafeRedirect(url)同时域名和 url 检查不区分大小写。也就是说白名单为空即放行是为了兼容旧应用一旦你配置了白名单安全检查即生效。重定向的具体实现见 plugins/security/src/app/extend/response.ts以/开头的相对路径视为站内跳转直接放行但//开头会被归一化为//\形式会走后续检查防止协议相对跳转绕过非相对路径解析 URL仅允许http:/https:协议若配置了非空domainWhiteList则通过ctx.isSafeDomain()校验 hostname生产环境下不通过会记录告警并重定向到/非生产环境直接抛 500 便于暴露问题。ctx.isSafeDomain(domain)ctx.isSafeDomain(domain)用于判断某个域名是否为安全域名安全域名即上面domainWhiteList中配置的域名。源码实现位于 plugins/security/src/lib/utils.ts比较时统一转小写、忽略大小写白名单项若包含*则按通配符匹配如*.domain.com普通项自动补.前缀后做后缀匹配且刻意避免wwweggjs.com误匹配eggjs.com这类前缀相似域名。五、JSONP 接口防护JSONP 依赖在页面中动态插入script执行回调若回调函数名可控极易造成 XSS。Egg 的 jsonp 防护在 context 层实现使用jsonp-body模块防御内容包括callback 函数名长度限制最长 50 个字符limit可配置callback 函数名字符白名单只允许[、]、字母、数字、_、$、.防止一般 XSS、UTF-7 XSS 等攻击默认的 callback 参数名为_callback可改名。六、安全 Helper 全家桶XSS 过滤与命令注入防护插件在ctx.helper上注册了一组安全过滤函数统一声明在 plugins/security/src/lib/helper/index.ts。它们解决不同场景下的注入问题注意并不是任何时候都要用最重的过滤按输出位置选择最合适的 helper 才是最佳实践。6.1.escape()HTML 实体转义对字符串做 HTML 实体转义是安全性最高、最基础的 XSS 过滤方式const str scriptalert(abc) /script; console.log(ctx.helper.escape(str)); // gt;lt;scriptgt;alert(quot;abcquot;) lt;/scriptgt;lt;在 nunjucks 等模板引擎中默认会做 escape无需显式调用只有在你手工拼接 HTML 字符串时才需要显式使用。6.2.surl()URL 过滤用于在 HTML 标签中需要解析 URL 的地方如a href、img src其他地方不允许使用。模板中要输出的变量应包裹helper.surl($value)不使用 surla href$value /output:a hrefhttp://www.domain.comscript /使用 surla hrefhelper.surl($value) /output:a hrefhttp://www.domain.comlt;scriptgt; /特别需要注意在需要解析 url 的地方surl 外面一定要加上双引号否则不会被当作属性分隔符处理反而会导致 XSS 漏洞。从源码 plugins/security/src/lib/helper/surl.ts 看surl 会先校验协议相对路径放行绝对路径的协议必须命中白名单默认http、https、file、data加自定义protocolWhiteList非白名单协议直接返回空字符串随后把、、、转义为 HTML 实体。6.3.sjs()JavaScript 字符串转义用于在 JS包括onload等事件属性中输出变量。它会对变量中的所有非白名单字符做 JAVASCRIPT ENCODE转义为\x形式防止 XSS 攻击也确保输出在 JS 中语义正确const foo hello; // 未使用 sjs console.log(var foo ${foo};); // var foo hello; // 使用 sjs console.log(var foo ${this.helper.sjs(foo)};); // var foo \\x22hello\\x22;6.4.shtml()富文本过滤当需要把包含 HTML 的富文本如用户输入的帖子内容直接输出到模板中时使用shtml。它允许输出白名单内的 HTML tag同时执行 XSS 过滤剔除非法脚本// js const value a hrefhttp://www.domain.comgoogle/ascriptevilcode…/script; // 模板 html body${helper.shtml($value)}/body /html; // a hrefhttp://www.domain.comgoogle/alt;scriptgt;evilcode…lt;/scriptgt;这是一个非常复杂的安全处理过程对服务器处理性能有一定影响如果不是输出 HTML请勿使用。shtml 基于xss模块在其默认白名单规则基础上增加了针对域名的过滤源码见 plugins/security/src/lib/helper/shtml.ts默认规则仅放行白名单内的 tag 与属性如a标签默认只保留href、title等有限属性自定义过滤项通过whiteList覆盖例如只支持a标签、且除title外其他属性全部过滤whiteList: { a: [title]; }属性级自定义可通过onTagAttr(tag, name, value, isWhiteAttr)回调定制某个 tag 属性的处理逻辑插件内置的域名校验会作为兜底逻辑保留域名过滤href/src属性会校验其 hostname 是否在config.security.domainWhiteList中不在则属性被清空。config.helper.shtml.domainWhiteList已过时请使用config.security.domainWhiteList代替。注意 shtml 的白名单是严格的除了过滤 XSS 风险字符串外不在默认规则中的 tag 和 attr 都会被过滤掉。例如html/html标签不在白名单中输出为空常见的data-xx自定义属性也会被过滤。因此shtml 的适用场景一般是来自用户的富文本输入论坛、评论系统等切忌滥用。如果业务本身不支持 HTML 内容输入直接使用escape即可既快又安全。6.5.spath()路径安全校验把输入字符串用作 path 路径时必须用spath做安全检验路径不合法时返回null。不合法路径包括使用..的相对路径目录穿越使用/开头的绝对路径以上试图通过 url encode 绕过校验的结果字符串内部会先做decodeURIComponent再判断见 plugins/security/src/lib/utils.ts 的isSafePath。const foo /usr/local/bin; console.log(this.helper.spath(foo2)); // null6.6.sjson()JSON 输出转义在 JS 中输出 JSON 时若未转义易被利用为 XSS 漏洞。sjson会对 JSON 做编码遍历 JSON 的 key将 value 中所有非白名单字符转义为\x形式同时保持 JSON 结构不变。若需要在模板中输出一个 JSON 字符串给 JS 应用使用请使用${this.helper.sjson(变量名)}进行转义scriptwindow.locals ${this.helper.sjson(locals)};/script该处理过程较复杂、性能损耗较大应尽量避免使用——能提前序列化并单独转义的部分尽量在业务层处理。6.7.cliFilter()远程命令执行防护远程命令执行RCE漏洞的典型场景是用户通过浏览器提交的参数被直接拼进系统命令服务器端未做过滤攻击者可借此执行任意命令、入侵服务器。如果用户可控变量是命令中的参数直接用cliFilter过滤修复前cp.exec(bash /home/admin/ali-knowledge-graph-backend/initrun.sh port);修复后cp.exec(bash /home/admin/ali-knowledge-graph-backend/initrun.sh this.helper.cliFilter(port));如果业务需要在参数中添加白名单之外的字符可以将用户输入按该字符分割并对每一段分别调用过滤函数。如果用户可控变量是命令本身而非参数则应与开发协商修改功能或直接下线该功能——此时任何过滤都无法保证安全。6.8.escapeShellArg()POSIX shell 参数转义对单个 shell 参数做 POSIX 转义给字符串增加一对单引号并对已存在的单引号做引用/转码处理从而安全地把它拼接进 shell 命令字符串const ip 127.0.0.1 cat /etc/passwd; const cmd ping -c 1 this.helper.escapeShellArg(ip); console.log(cmd); //ping -c 1 127.0.0.1 cat /etc/passwd如果可以应优先使用child_process.execFile()或child_process.spawn()的参数数组形式彻底避免字符串拼接。这个 helper 只用于 POSIX shell 命令字符串里的单个参数不适用于 Windowscmd.exe或 PowerShell 转义。6.9.escapeShellCmd()命令行整体转义从输入的命令行中直接删除危险字符#;|*?~^()[]{}$;, 0x0A 和 0xFFconst ip 127.0.0.1 cat /etc/passwd; const cmd ping -c 1 this.helper.escapeShellCmd(ip); console.log(cmd); //ping -c 1 127.0.0.1 cat /etc/passwd可以看到、分号等分隔符被剔除命令被打散成无法注入的形式。相比escapeShellArg它更激进但可能改变参数含义适用于需要保留整条命令字符串的场景。七、Web 安全响应头由中间件批量注入插件以中间件形式位于 plugins/security/src/lib/middlewares在响应阶段统一注入安全响应头。下面按 README 顺序逐一说明并标注当前源码中的默认值与配置入口。7.1 HSTSStrict-Transport-SecurityHSTS 强制浏览器只通过 HTTPS 访问本站。按当前源码默认enable: false需要 HTTPS 站点手动开启README 中默认开启的描述对应旧版本如果是纯 HTTP 站点则务必保持关闭。maxAge默认一年即365 * 24 * 3600includeSubdomains默认false设为true时规则同样适用于所有子域名。实现见 plugins/security/src/lib/middlewares/hsts.ts响应头格式为strict-transport-security: max-agemaxAge[; includeSubdomains]。7.2 CSPContent-Security-PolicyCSP 默认关闭enable: false。需要开启时必须和安全工程师共同确定策略主要配置项为policy策略对象key 为指令名value 可为字符串、字符串数组或布尔值。源码还支持reportOnly仅上报不拦截与supportIEIE 兼容两个可选开关。此外插件在 context 上提供了ctx.nonce随机 16 位字符串可用于 CSP 的 nonce 机制放行内联脚本见 plugins/security/src/app/extend/context.ts。exports.security { csp: { enable: true, policy: { default-src: self, // img-src: [*, data:], }, }, };7.3 X-Download-Options: noopen默认开启禁用 IE 下载框中的 Open 按钮防止 IE 下下载文件默认被打开而触发 XSS。对应中间件 plugins/security/src/lib/middlewares/noopen.ts。7.4 X-Content-Type-Options: nosniff默认开启禁用 IE8 的 MIME 自动嗅探功能。例如响应声明text/plain却可能被当成text/html渲染——尤其当本站点服务内容未必可信时nosniff 可以防止这类降级攻击。对应中间件 plugins/security/src/lib/middlewares/nosniff.ts。7.5 X-Frame-Options默认值SAMEORIGIN只允许同源页面把本页面当作 iframe 嵌入。value可配置为DENY、SAMEORIGIN或ALLOW-FROM https://example.com。实现见 plugins/security/src/lib/middlewares/xframe.ts。7.6 X-XSS-Protection默认开启value默认为1; modeblock即 README 中close默认false所对应的输出。开启后浏览器会在检测到反射型 XSS 时拦截页面渲染。7.7 补充referrerPolicy 与 dta除 README 列出的响应头外当前源码还默认启用了两个值得了解的中间件referrerPolicy默认enable: false输出Referrer-Policy头默认值no-referrer-when-downgrade用于控制浏览器在跳转时携带多少来源信息保护隐私与防信息泄露dta默认enable: true自动拦截目录穿越Directory Traversal Attack请求基于isSafePath判断路径是否包含..穿越或编码绕过见 plugins/security/src/lib/middlewares/dta.ts。八、其他防护与扩展能力8.1 请求方法限制插件默认禁止TRACE与TRACK两种 HTTP 方法对应 OWASP 的 Cross Site Tracing 攻击命中时直接返回 405。实现见 plugins/security/src/lib/middlewares/methodnoallow.ts以 Node 内置METHODS为基准剔除TRACE/TRACK后构建安全方法映射表。8.2 crossdomain.xml 与 robots.txtcrossdomain.xml、robots.txt默认都不由本插件输出业务系统可自行添加如涉及敏感信息需要咨询项目安全工程师确认策略。8.3 SSRF 防护与 safeCurl源码扩展当前源码在配置模型中新增了ssrf配置config.default.ts用于服务端请求外发时的 SSRF 防护支持ipBlackListIP 黑名单支持精确 IP 或 CIDR 网段如127.0.0.0/8ipExceptionList从黑名单中豁免的 IPhostnameExceptionList豁免的 hostname 列表checkAddress自定义校验函数(address, family, hostname) boolean优先级最高。黑名单/豁免逻辑在 plugins/security/src/lib/utils.ts 的preprocessConfig中预编译为checkAddress先查 hostname 豁免再查 IP 豁免命中黑名单即拒绝默认放行。与之配套的是 context 与 application 上的safeCurl()方法见 plugins/security/src/app/extend/context.ts 及 plugins/security/src/lib/extend/safe_curl.ts对应用外发请求做安全包装。九、实践建议与总结默认值即安全基线csrf、xframe、nosniff、noopen、xssProtection、dta、methodnoallow默认开启不建议整体关闭hsts、csp、referrerPolicy按站点协议与业务需求显式开启。按路径精细控制善用各项子配置的match/ignore字符串、正则、函数、数组例如仅对支付/登录接口严格校验 CSRF对第三方嵌入页面放行xframe。输出场景决定过滤方式模板变量默认逃逸拼接 HTML 用escapeURL 属性用带双引号的surlJS 内输出用sjs富文本才考虑shtml注意其白名单严格性与性能开销文件路径用spath命令参数用cliFilter/escapeShellArg/escapeShellCmd并优先使用execFile/spawn的参数数组形式。安全重定向必须配置白名单domainWhiteList为空时ctx.redirect会退化为放行所有外链务必按[.yourdomain.com]的格式显式声明。关注版本差异README 中的部分描述如 hsts 默认开启与当前源码默认值存在出入实际行为以 plugins/security/src/config/config.default.ts 的 zod schema 为准。eggjs/security的价值在于开箱即用的安全基线 精细可裁剪的配置面它把 CSRF/CTOKEN、安全重定向、XSS 过滤、安全响应头、方法限制、目录穿越与 SSRF 防护等常见 Web 威胁统一收敛到一套配置模型与一组 Helper 中。理解每个配置项的默认值与底层实现就能在保证安全的前提下为业务定制最合适的防护策略。延伸阅读插件主文档plugins/security/README.zh-CN.md默认配置与类型定义plugins/security/src/config/config.default.ts中间件组装逻辑plugins/security/src/app/middleware/securities.ts安全中间件实现目录plugins/security/src/lib/middlewares安全 Helper 实现目录plugins/security/src/lib/helpercontext 扩展csrf/ctoken/非ceplugins/security/src/app/extend/context.ts安全重定向实现plugins/security/src/app/extend/response.ts赞分享后端Web框架【免费下载链接】egg Born to build better enterprise frameworks and apps with Node.js Koa. https://307.run/eggcode项目地址https://gitcode.com/gh_mirrors/eg/egg点击查看免费下载相关推荐Egg 安全插件 eggjs/security 完整指南从 CSRF 防御到 SSRF 防护的源码级解析Egg 安全插件 eggjs/security 完整指南从 CSRF 防御到 SSRF 防护的源码级解析 eggjs/security 是 Egg 框架内后端Web框架eggjs/jsonp 插件完全指南在 Egg 应用中实现 JSONP 支持与安全防护eggjs/jsonp 插件完全指南在 Egg 应用中实现 JSONP 支持与安全防护 导读 JSONPJSON with Padding是解决浏览器跨后端Web框架CANN/asc-devkit SIMT规约求和APIasc\_reduce\_adda nameZH CN_TOPIC_0000002516816303 /a 产品支持情况a namesectio后端Web框架上一篇深入理解Adagrad优化算法原理与实现下一篇Python数据科学手册NumPy入门指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进