CORS安全配置实战:从漏洞原理到Nginx与后端修复指南
1. 项目概述从一次真实的线上告警说起那天凌晨两点手机突然开始疯狂震动。运维监控系统发来一连串告警提示某个核心业务接口的异常请求量激增。登录服务器一看日志好家伙大量来源不明的域名正在疯狂调用我们的用户信息查询API请求头里带着五花八门的Origin。虽然我们的后端服务有身份验证但前端同事在开发时为了方便调试在Nginx里配了个Access-Control-Allow-Origin: *这个“星号”就像给自家院子开了个没有门卫的大门。攻击者正是利用这一点构造恶意页面发起跨域请求虽然拿不到响应数据因为没带Token但通过请求的耗时和状态依然能侧面探测出用户是否存在等敏感信息。这就是典型的跨域资源共享配置不当引发的信息泄露漏洞也是我们今天要深入讨论和彻底修复的核心。跨域资源共享简称CORS绝不是简单配个响应头就完事了。它是一套由浏览器强制执行的、精细化的安全策略机制用于控制Web应用在不同源之间安全地交换数据。一个配置失误的CORS策略轻则导致信息泄露、功能被滥用重则可能成为攻击者实施CSRF攻击、窃取用户数据的跳板。修复CORS漏洞远不止是把*改成某个域名那么简单它涉及到对业务场景的深刻理解、对安全策略的精准把控以及对Nginx、后端框架等不同层面配置的协同工作。无论你是前端开发者、后端工程师还是运维人员理解并正确配置CORS都是构建现代Web应用不可或缺的安全基本功。2. CORS漏洞核心原理与风险场景深度拆解2.1 CORS机制是如何工作的为什么会有漏洞要修复漏洞首先得明白它为什么会产生。CORS机制的核心是浏览器与服务器之间的一次“预检”握手。当来自https://evil.com的JavaScript代码试图向https://api.your-app.com发起一个带有自定义头如Authorization的POST请求时浏览器不会直接发送这个请求。它会先自动发起一个OPTIONS方法的“预检请求”。这个预检请求的HTTP头里会携带几个关键信息Origin: https://evil.com告诉服务器请求来自哪里。Access-Control-Request-Method: POST告诉服务器实际请求想用什么方法。Access-Control-Request-Headers: authorization, content-type告诉服务器实际请求会携带哪些自定义头。服务器收到预检请求后必须通过响应头来明确表态Access-Control-Allow-Origin: https://your-app.com明确允许哪个源可以访问。这里是漏洞高发区。Access-Control-Allow-Methods: GET, POST, PUT明确允许哪些HTTP方法。Access-Control-Allow-Headers: authorization, content-type明确允许哪些自定义头。Access-Control-Allow-Credentials: true可选是否允许发送Cookie等凭证。如果设置为true那么Access-Control-Allow-Origin不能为*。漏洞产生的根源就在这里如果服务器的响应头配置过于宽松比如Access-Control-Allow-Origin: *允许任意来源访问。这意味着evil.com的预检请求也会通过攻击者可以读取到API的响应内容如果请求不需要凭证。Access-Control-Allow-Origin动态反射了请求中的Origin头且没有严格的白名单校验攻击者可以构造任意Origin服务器都原样返回等于向所有域名开放。Access-Control-Allow-Credentials: true与过于宽松的Origin策略结合这可能导致携带用户Cookie的请求被恶意网站利用引发严重的CSRF或数据窃取。注意即使响应头配置正确如果服务器对Origin头的校验逻辑存在缺陷例如仅检查字符串是否包含某个域名如your-app.com.evil.com也能通过同样会构成漏洞。2.2 那些年我们踩过的坑典型CORS漏洞场景实录在实际开发和运维中CORS问题往往出现在以下几个场景每一个我都亲身经历过场景一开发环境图省事生产环境忘关闭这是最经典的错误。开发时前端在localhost:3000后端API在localhost:8080为了联调方便直接在Nginx或后端代码里配置了Access-Control-Allow-Origin: *。项目上线时所有人注意力都在功能、性能和数据库上这个“临时”配置被原封不动地带到了生产环境。攻击者发现后可以直接在他们的网站上调用你的公开API。避坑技巧建立严格的配置管理清单。开发、测试、生产环境的配置文件必须分离。在构建或部署脚本中加入CORS策略的检查步骤如果检测到生产环境配置了过于宽松的CORS则中断部署并告警。场景二允许多个来源时的正则匹配错误业务需要支持https://app.your-company.com和https://admin.your-company.com两个子域名访问API。开发者写了一个配置检查Origin是否以.your-company.com结尾。这看起来没问题但https://fakeyour-company.com这个域名也能匹配通过因为点号.在正则里是通配符。避坑技巧进行域名校验时一定要进行精确的字符串匹配或使用严格的正则表达式。对于上述场景更安全的做法是维护一个明确的白名单数组检查Origin是否完全等于列表中的某个值或者使用^https://([a-z0-9-]\\.)*your-company\\.com$这类更严谨的正则并对点号进行转义。场景三忽略Vary头导致缓存投毒这是一个高阶但危害巨大的漏洞。假设你的API根据Origin头动态返回不同的Access-Control-Allow-Origin值。如果响应中没有设置Vary: Origin头那么中间的反向代理如CDN、Nginx缓存可能会将第一个请求的CORS响应头缓存起来并返回给后续来自不同Origin的请求。这可能导致一个本应被拒绝的源拿到了允许访问的CORS头。实操心得只要你的CORS策略是动态的即响应头会根据请求内容变化就必须在响应中添加Vary: Origin头。这指示缓存服务器将Origin请求头作为缓存键的一部分确保为不同来源返回正确的CORS头。3. 全方位修复指南从Nginx配置到后端代码修复CORS漏洞需要根据你的技术栈在正确的层面进行配置。下面我将分别从Nginx网关层、常见后端框架应用层两个维度给出详细的、可直接复用的安全配置方案。3.1 Nginx层修复把好网关第一道关在Nginx中配置CORS通常是最直接和高效的方式因为它能统一处理所有到达后端应用的请求。以下是一个生产环境推荐的安全配置示例我将其放在server块或location块中。server { listen 443 ssl; server_name api.your-app.com; # SSL配置关联热词CVE-2016-2183漏洞修复 # 禁用不安全的SSL/TLS协议和弱加密套件这是另一个重要安全点 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; location / { # 1. 处理预检请求 (OPTIONS) if ($request_method OPTIONS) { add_header Access-Control-Allow-Origin https://www.your-app.com always; add_header Access-Control-Allow-Methods GET, POST, OPTIONS, PUT, DELETE always; # 明确列出允许的自定义头不要用‘*’ add_header Access-Control-Allow-Headers DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization always; # 预检请求的缓存时间单位秒。减少不必要的预检请求。 add_header Access-Control-Max-Age 1728000 always; add_header Content-Type text/plain; charsetutf-8; add_header Content-Length 0; return 204; } # 2. 处理实际请求 (GET, POST, etc.) # 动态判断Origin并设置CORS头 # 这里使用map指令定义白名单更清晰 set $cors_origin ; if ($http_origin ~* ^https?://(www\.)?your-app\.com$) { set $cors_origin $http_origin; } if ($http_origin ~* ^https?://admin\.your-app\.com$) { set $cors_origin $http_origin; } # 可以继续添加其他允许的源... # 只有匹配白名单的源才添加CORS头 if ($cors_origin ! ) { add_header Access-Control-Allow-Origin $cors_origin always; add_header Access-Control-Allow-Credentials true always; # 如果需要凭证 add_header Access-Control-Expose-Headers Content-Length,Content-Range always; # 重要添加Vary头防止缓存投毒 add_header Vary Origin always; } # 代理到实际的后端应用 proxy_pass http://backend_server; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }关键配置解析与避坑点always参数Nginx的add_header指令默认只在响应码为200, 201, 204, 206, 301, 302, 303, 304, 307, 308时添加头部。使用always能确保在任何响应码包括4xx, 5xx错误下都添加CORS头这对前端错误处理至关重要。白名单校验逻辑使用map指令或if条件判断来匹配$http_origin。绝对不要使用*。正则表达式要写严谨防止子域名匹配溢出。上面的例子严格匹配your-app.com及其www子域。Access-Control-Allow-Credentials只有当你的前端请求需要携带Cookie、Authorization头等凭证时才设置为true。且此时Access-Control-Allow-Origin必须是一个明确的源不能是*。Access-Control-Expose-Headers默认情况下前端只能访问CORS安全列表中的响应头Cache-Control, Content-Language, Content-Length等。如果你需要让前端访问其他自定义头如X-Total-Count必须在这里明确列出。3.2 后端应用层修复以Spring Boot和Node.js为例有时业务逻辑更复杂需要在应用层动态控制CORS。以下以两种常见后端框架为例。Spring Boot (Java) 安全配置不要使用全局的CrossOrigin(origins *)注解。推荐创建一个安全的配置类。import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import java.util.Arrays; import java.util.List; Configuration public class SecurityCorsConfig { Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); // 1. 不允许使用*设置明确的白名单 // 生产环境建议从配置文件中读取 config.setAllowedOrigins(Arrays.asList(https://www.your-app.com, https://admin.your-app.com)); // 2. 允许的HTTP方法 config.setAllowedMethods(Arrays.asList(GET, POST, PUT, DELETE, OPTIONS)); // 3. 允许的请求头 config.setAllowedHeaders(Arrays.asList(Authorization, Content-Type, X-Requested-With)); // 4. 是否允许凭证Cookie等 config.setAllowCredentials(true); // 如果为true则allowedOrigins不能为* // 5. 暴露给前端的响应头 config.setExposedHeaders(Arrays.asList(X-Total-Count)); // 6. 预检请求缓存时间秒 config.setMaxAge(3600L); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); // 应用到所有API路径 source.registerCorsConfiguration(/api/**, config); return new CorsFilter(source); } }Node.js (Express) 安全配置避免使用cors中间件的默认配置或直接origin: *。const express require(express); const cors require(cors); const app express(); // 定义允许的来源白名单 const allowedOrigins [https://www.your-app.com, https://admin.your-app.com]; const corsOptions { origin: function (origin, callback) { // 注意对于没有Origin头的请求如同源请求、curl、Postmanorigin参数可能是undefined if (!origin || allowedOrigins.indexOf(origin) ! -1) { callback(null, true); } else { console.error(CORS blocked for origin: ${origin}); callback(new Error(Not allowed by CORS)); } }, credentials: true, // 允许携带凭证 allowedHeaders: [Authorization, Content-Type], exposedHeaders: [X-Total-Count], maxAge: 3600 // 预检请求缓存时间 }; // 将CORS中间件应用到所有路由 app.use(cors(corsOptions)); // 或者如果你需要更细粒度的控制可以只应用到特定路由 // app.use(/api/, cors(corsOptions)); app.get(/api/data, (req, res) { res.json({ message: 安全的数据 }); }); app.listen(3000);后端配置核心要点动态Origin校验像Node.js示例那样使用一个校验函数来检查Origin头是否在白名单内。这是最灵活和安全的方式。区分环境开发环境可以放宽限制如允许localhost但必须通过环境变量或配置文件来区分确保生产配置的严格性。日志记录对于被拒绝的CORS请求务必记录日志如Node.js示例中的console.error这有助于安全监控和异常排查。4. 进阶加固与渗透测试自查清单完成了基础配置并不意味着高枕无忧。攻击者的手段在进化我们的防御也需要层层加固。4.1 针对CORS的进阶安全加固措施限制允许的HTTP方法在Access-Control-Allow-Methods中只列出业务实际需要的HTTP方法。例如如果某个端点只提供数据查询那就只允许GET, OPTIONS不要包含POST, PUT, DELETE。限制允许的请求头在Access-Control-Allow-Headers中明确列出前端应用会发送的自定义头。避免使用*。这可以防止攻击者利用一些特殊的请求头进行探测或攻击。谨慎使用Access-Control-Allow-Credentials: true除非前端必须发送Cookie或HTTP认证信息否则不要开启此选项。开启后Access-Control-Allow-Origin必须是一个明确的源且需要更加注意CSRF防护。实施速率限制即使CORS配置正确公开的API也可能被滥用如爬虫、枚举攻击。在Nginx或应用层对API端点实施速率限制基于IP或用户令牌。敏感操作的额外验证对于修改、删除等敏感操作除了CORS和常规认证外应实施二次验证如要求客户端提交CSRF Token对于同源策略失效的场景需设计其他安全机制、短信验证码等。4.2 CORS安全渗透测试自查清单在代码上线前或定期安全审计时你可以使用以下清单进行自我测试。我常用Burp Suite或手工构造请求来完成。测试项测试方法安全预期风险等级Origin反射测试发送一个预检请求Origin头设置为https://attacker.com。检查响应头Access-Control-Allow-Origin是否原样返回了https://attacker.com或通配符*。应返回白名单内的源或拒绝无此头。高危Origin前缀/后缀匹配绕过发送Origin: https://your-app.com.evil.com或Origin: https://evilyour-app.com。应被拒绝。检查后端校验逻辑是否被错误的前缀/后缀匹配绕过。高危空Origin头测试发送预检请求不包含Origin头或Origin: null。通常应被拒绝。但需注意某些本地文件场景。中危凭证与通配符兼容性在配置了Access-Control-Allow-Credentials: true的情况下测试Access-Control-Allow-Origin是否为*。绝对不允许同时存在。浏览器会阻止此类请求。高危HTTP方法覆盖测试发送预检请求Access-Control-Request-Method设置为不常用的方法如PROPFIND,TRACE。响应中Access-Control-Allow-Methods不应包含这些危险方法。中危危险请求头测试发送预检请求Access-Control-Request-Headers包含可疑头如X-Forwarded-Host,X-Custom-IP-Authorization。响应中Access-Control-Allow-Headers不应包含这些头。中危缓存投毒测试从两个不同的合法源A和B顺序发送请求观察CORS响应头是否一致。检查服务器响应是否包含Vary: Origin。应为不同源返回不同的Access-Control-Allow-Origin且响应头包含Vary: Origin。中危实操工具推荐浏览器开发者工具直接查看网络请求的请求和响应头是最直观的方式。Postman/Insomnia手动构造带有自定义Origin头的请求测试API响应。Burp Suite/OWASP ZAP专业的安全测试工具可以自动化进行上述很多测试并能进行更复杂的漏洞挖掘。5. 关联漏洞修复从CORS到更广泛的安全基线在搜索热词中提到了CVE-2010-2730和CVE-2016-2183。这提醒我们安全是一个整体。修复CORS漏洞的同时必须关注其他基础设施的安全。关于CVE-2016-2183(SSL/TLS协议信息泄露漏洞) 这个漏洞与CORS无直接关系但它同样发生在网络传输层且危害巨大。它涉及SSL/TLS协议中使用的DES/3DES密码算法存在弱点。修复方案是在Web服务器如Nginx、Apache的SSL配置中禁用不安全的加密套件。正如我在前面Nginx配置示例中给出的ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;这个配置优先使用前向保密的、强健的加密套件如AES-GCM并排除了DES/3DES等弱算法。定期使用sslscan或testssl.sh等工具扫描你的服务器SSL配置是运维的必要工作。安全是一个链条CORS配置是应用层访问控制的一环SSL/TLS是传输层加密的一环操作系统和软件补丁是基础层的一环。攻击者总会寻找最薄弱的一环进行突破。因此我们的安全实践也必须是体系化的在代码层面做好输入校验、身份认证和授权在配置层面做好CORS、SSL、防火墙规则在流程层面做好代码审计、渗透测试和漏洞扫描。将CORS的安全配置纳入你的应用发布清单和常规安全巡检项让它从“一个容易忘记的配置点”变成“一道坚固的安全门”。

相关新闻

AI Agent开发全栈指南:从理论到工程实践

AI Agent开发全栈指南:从理论到工程实践

1. 项目概述:AI Agent技术全景与学习价值最近半年,AI Agent技术正在以惊人的速度重塑各行各业的工作流程。不同于传统AI模型的单一任务处理能力,具备自主感知、决策和执行能力的智能体正在成为下一代人机交互的核心载体。根据我的项目实践经验…

2026/7/2 23:38:38阅读更多 →
漏洞利用神器mona.py:Immunity Debugger插件核心功能实战指南

漏洞利用神器mona.py:Immunity Debugger插件核心功能实战指南

1. 项目概述:为什么mona.py是漏洞利用领域的“瑞士军刀”如果你在Windows平台下搞过漏洞分析与利用,尤其是和Immunity Debugger打过交道,那你一定绕不开mona.py这个名字。它不是一个独立的软件,而是一个功能极其强大的Python脚本&…

2026/7/2 23:38:38阅读更多 →
AI Agent评估体系构建与实践指南

AI Agent评估体系构建与实践指南

1. AI Agent评估体系构建指南作为一名长期从事AI Agent开发的工程师,我深知评估环节的重要性。调试Agent就像在黑暗中摸索前进,如果没有系统化的评估方法,我们很难判断每一次修改是进步还是退步。本文将分享一套经过实战检验的AI Agent评估方…

2026/7/2 23:38:38阅读更多 →
终极指南:如何使用TradSimpChinese插件快速实现Calibre繁简中文转换

终极指南:如何使用TradSimpChinese插件快速实现Calibre繁简中文转换

终极指南:如何使用TradSimpChinese插件快速实现Calibre繁简中文转换 【免费下载链接】TradSimpChinese Calibre plugin to convert between Traditional and Simplified Chinese 项目地址: https://gitcode.com/gh_mirrors/tr/TradSimpChinese 你是否曾经遇到…

2026/7/3 0:53:45阅读更多 →
数字逃避行为识别与PTSD早期干预系统设计

数字逃避行为识别与PTSD早期干预系统设计

1. 项目概述:当虚拟世界成为心理避难所,我们如何为心灵装上“装甲”?“Armor to the Expanding Virtual Universe”——这个标题乍看像科幻小说的副标题,但背后是一套真实落地、已在三所高校心理咨询中心试运行的心理健康监测系统…

2026/7/3 0:53:45阅读更多 →
数据密集型 MCP Server:PostgreSQL 慢查询分析与自动调优

数据密集型 MCP Server:PostgreSQL 慢查询分析与自动调优

引言:当 AI 遇见 PostgreSQL 性能瓶颈 凌晨三点,告警响了。 生产数据库响应时间从 50ms 飙升到 8 秒,应用全面超时。DBA 被叫醒,打开终端,手忙脚乱地查 pg_stat_activity、看 pg_stat_statements、捞慢查询日志、跑 EXPLAIN ANALYZE……等找到问题根因、写完优化方案,天…

2026/7/3 0:53:45阅读更多 →
终极音乐解锁工具:3分钟打破平台限制,免费拥有你的音乐

终极音乐解锁工具:3分钟打破平台限制,免费拥有你的音乐

终极音乐解锁工具:3分钟打破平台限制,免费拥有你的音乐 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目…

2026/7/3 0:53:45阅读更多 →
Simple Runtime Window Editor:免费工具终极指南,如何突破游戏窗口限制

Simple Runtime Window Editor:免费工具终极指南,如何突破游戏窗口限制

Simple Runtime Window Editor:免费工具终极指南,如何突破游戏窗口限制 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 核心关键词:窗口分辨率调整、游戏hotsampling、进程注…

2026/7/3 0:53:45阅读更多 →
终极指南:使用yuzu模拟器在PC上畅玩Switch游戏的完整教程

终极指南:使用yuzu模拟器在PC上畅玩Switch游戏的完整教程

终极指南:使用yuzu模拟器在PC上畅玩Switch游戏的完整教程 【免费下载链接】yuzu 任天堂 Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/yu/yuzu 想要在电脑上体验《塞尔达传说:旷野之息》、《超级马里奥:奥德赛》等Sw…

2026/7/3 0:48:45阅读更多 →
AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

AI Coding 六个月真实ROI账本:产品经理的血泪教训,研发的冷静忠告

6个月前的2025年12月,Boris Cherny 公开宣布自己卸载了 IDE。一时间,Vibe Coding 成了全行业最热的话题。6个月后,当我们回过头来拉一份真实账本,发现事情远没有"一句话生成一个App"那么浪漫。本文从产品经理和研发两个…

2026/7/2 12:10:34阅读更多 →
审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

审计来了,数据权限全开——审计走了,怎么确保权限全部关掉?

引言:审计结束三个月了,审计员的权限还没关某城商行每年按照监管要求开展至少一次数据安全审计。审计期间,内审部门需要抽样检查各类业务数据——交易流水、客户信息、员工操作日志、权限配置记录。这些数据分布在不同系统中,审计…

2026/7/2 12:10:34阅读更多 →
LV3296与PIC18F45K22的UART通信与USB扩展方案

LV3296与PIC18F45K22的UART通信与USB扩展方案

1. LV3296与PIC18F45K22的硬件搭档解析在嵌入式数据采集系统中,LV3296条形码扫描模块与PIC18F45K22微控制器的组合堪称经典搭配。LV3296作为一款工业级条码扫描头,其核心是一颗高性能CMOS图像传感器,配合专用解码芯片,能自动识别包…

2026/7/3 0:03:41阅读更多 →
AI初创生存指南:6个月完成可信度验证闭环

AI初创生存指南:6个月完成可信度验证闭环

1. 这不是“逆袭指南”,而是一份AI初创公司真实生存手记“How To Beat Odds As an AI Startup?”——这个标题乍看像一句热血口号,但在我带过7个从0到1的AI产品团队、亲手踩过融资失败、技术债崩盘、客户POC卡在最后一公里等23类典型坑之后,…

2026/7/3 0:03:41阅读更多 →
多模态+推理链+RAG 2.0+智能体:工业级AI系统落地四支柱

多模态+推理链+RAG 2.0+智能体:工业级AI系统落地四支柱

1. 这不是又一篇“AI趋势速览”,而是一份实操者手记:当多模态、推理链、检索增强与智能体协作真正撞进工程现场“LAI #73”这个编号本身就像一个暗号——它不属于某家大厂的白皮书,也不是学术会议的议程表,而是长期泡在模型训练集…

2026/7/3 0:03:41阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/2 0:33:58阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/2 1:32:11阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/2 1:50:13阅读更多 →