RFC8470在HTTP中使用早期数据
摘要
使用TLS早期数据会暴露出重放攻击的可能性。本文定义了允许客户端与服务器就早期数据中发送的HTTP请求进行通信的机制。描述了使用这些机制来减轻重放风险的技术。
1. 介绍
TLS 1.3[TLS13]引入了早期数据(也称为零往返时间(0-RTT)数据)的概念。如果客户端最近与同一服务器通信,早期数据允许客户端在连接的第一次往返中向服务器发送数据,而无需等待TLS握手完成。
当与HTTP[HTTP]一起使用时,早期数据允许客户端立即发送请求,从而避免TLS握手所需的一到两次往返延迟。这是一个显著的性能提升;然而,它有很大的局限性。
使用早期数据的主要风险是,攻击者可能会捕获并重放其中包含的请求。TLS[TLS13]描述了可以用来降低攻击者成功重放请求的可能性的技术,但这些技术可能很难部署,并且仍然会留下一些成功攻击的可能性。
请注意,这与自动重试或用户发起的重试不同;重放是由攻击者在客户端不知情的情况下发起的。为了帮助降低HTTP中重放的风险,本文概述了在服务器中控制这些风险的技术,并定义了在早期数据中发送请求时客户端的要求。
本文中的建议也适用于在QUIC[HQ]上的HTTP中使用0-RTT。
2. HTTP中的早期数据
从概念上讲,早期数据与其他应用数据拼接在一起,形成单个流。这可能意味着请求完全包含在早期数据中,或者请求中只有一部分是早期的。在复用协议中,如HTTP/2[RFC7540]或HTTP/QUIC[HQ],多个请求可能在早期数据中部分传递。
本文假设的模型是,一旦TLS握手完成,在该TLS连接上接收的早期数据就不会是该数据的重放副本。然而,需要注意的是,这并不意味着早期数据不会或没有在另一个连接上重放。
3. HTTP服务器支持早期数据
服务器决定在发送TLS会话票据时是否向客户端提供在未来连接上发送早期数据的能力。
TLS[TLS13]要求使用重放检测策略,以降低攻击者成功重放早期数据的能力。这些反重放技术减少了但并没有完全消除数据被重放的机会,并确定了重放次数的固定上限。
当服务器启用早期数据时,可以使用许多技术来降低重放风险:
1.服务器可以拒绝TLS层的早期数据。服务器不能选择性地拒绝早期数据,因此这会导致在早期数据中发送的所有请求都被丢弃。
2.服务器可以选择将早期数据的处理延迟到TLS握手完成之后。通过延迟处理,它可以确保其中的请求只使用成功完成的连接。这为服务器提供了一些保证,即早期数据不会被重放。如果服务器在早期数据中接收到多个请求,它可以根据每个请求确定是否推迟HTTP处理。
3.在判断重放风险太大的情况下,服务器可以通过425(Too Early)状态码(5.2)进行响应,使客户端重试单个请求,而不使用早期数据。
所有这些技术都同样有效;服务器可以使用最适合它的方法。
对于给定的请求,对重放风险的容忍度是特定于操作的资源的(因此只有源服务器知道)。与使用早期数据相关的主要风险在于服务器在处理请求时采取的行动;处理重复的请求可能会导致重复的效果和副作用。[TLS13]的附录E.5还描述了处理重复请求所产生的其他影响。
请求方法的安全性([RFC7231] 4.2.1)是确定这一点的一种方法。然而,一些资源安全的方法也会产生副作用,因此这不能被普遍依赖。
建议源服务器允许资源明确配置请求中的早期数据是否合适。如果没有这些明确的信息,源服务器必须拒绝早期数据,或者实施本文的技术,以确保在TLS握手完成之前不会处理请求。
一个请求可能会在早期数据中部分发送,而请求的其余部分则在握手完成后发送。这并不一定影响对该请求的处理;重要的是服务器何时开始对请求的内容采取行动。任何时候,任何服务器实例都可能在握手完成之前启动处理,所有服务器实例都需要考虑重放早期数据的可能性,以及这可能如何影响处理(见6.2)。
服务器可以部分处理不完整的请求。解析头字段(不执行值)和确定请求路由可能不会产生副作用,但其他操作可能不会。
中间服务器(代理)没有足够的信息来决定是否可以处理早期数据,因此5.2描述了源向他们发出信号的一种方式,即特定请求不适合早期数据。接受早期数据的代理必须实施这一机制。
请注意,服务器不能选择在TLS层选择性地拒绝早期数据。TLS只允许服务器接受所有早期数据或不接受任何早期数据。一旦服务器决定接受早期数据,它必须处理早期数据中的所有请求,即使服务器通过发送425(Too Early)响应来拒绝请求。
服务器可以使用“early_data”TLS扩展的“max_early_data_size”字段来限制早期数据的数量。这可以避免为可能推迟到握手完成的请求提交任意数量的内存。
4. HTTP客户端使用早期数据
希望使用早期数据的客户端在发送TLS ClientHello后立即发送HTTP请求。
从本质上讲,客户端可以控制是否在早期数据中发送给定的请求,从而使客户端能够控制重放的风险。在没有其他信息的情况下,客户端可以在早期数据可用时使用安全的HTTP方法([RFC7231],4.2.1)发送请求,并且不得在早期数据中发送不安全的方法(或安全性未知的方法)。
如果服务器拒绝TLS层的早期数据,则客户端必须像新连接一样重新开始发送。这可能需要使用与早期数据乐观使用的协议不同的协商协议[ALPN]。在早期数据中发送的任何请求都需要再次发送,除非客户端决定放弃这些请求。
自动重试会造成重放攻击的可能性。攻击者截获使用早期数据的连接,并将早期数据复制到另一个服务器实例。第二个服务器实例接受并处理早期数据,即使它不会完成TLS握手。然后,攻击者允许原始连接完成。即使早期数据被检测为重复并被拒绝,第一个服务器实例也可能允许连接完成。如果客户端随后重试在早期数据中发送的请求,则该请求将被处理两次。如果有多个服务器实例将接受早期数据,或者如果同一服务器多次接受早期数据(尽管后者违反了[TLS13]第8节的要求),也可以进行重放。
使用早期数据的客户端必须在收到425(Too Early)状态码后重试请求(见5.2)。
代理在转发请求时不得使用早期数据,除非在前一跳中使用了早期数据,或者它知道可以安全地重试请求而不会产生任何后果(通常使用带外配置)。在没有更好信息的情况下,这意味着只有当请求以早期数据形式到达或在Early-Data头字段设置为1的情况下到达时,代理才能使用早期数据(见5.1)。
5. HTTP早期数据扩展
由于HTTP请求可以跨越多个“跃点”,因此有必要明确告知请求是否已在前一个跃点的早期数据中发送。同样,当不需要早期数据时,有必要有一些明确触发重试的方法。最后,有必要知道客户端是否真的会执行这样的重试。
为了满足这些需求,定义了两种信号机制:
o Early-Data头字段包含在代理可能在完成与其客户端的TLS握手之前转发的请求中。
o 425(Too Early)状态码是为服务器定义的,用于指示由于可能的重放攻击的后果而无法处理请求。
它们旨在更好地协调用户代理和源服务器之间的早期数据使用,以及在存在网关(也称为“反向代理”、“内容交付网络”或“代理”)时。
网关通常没有关于在早期数据中发送给定请求时是否可以安全处理的特定信息。在许多情况下,只有源服务器有必要的信息决定重放的风险是否可接受。这些扩展允许网关与源服务器之间进行协调。
5.1. Early-Data头字段
Early-Data请求头字段指示该请求已经在早期数据中被传送,并且客户端理解425态码。
它只有一个有效值:1。其语法由以下ABNF[ANDF]定义:
Early-Data = "1"
例如:
GET /resource HTTP/1.0
Host: example.com
Early-Data: 1
在完成与其客户端的TLS握手之前转发请求的代理必须在发送请求时将Early Data头字段设置为1(即,如果请求中不存在,则添加该字段)。如果请求可能已经被重放,并且可能已经被它或另一个实例转发,则代理必须使用早期数据头字段(见6.2)。
如果请求中存在此头字段,则代理不得删除该头字段。早期数据不得出现在Connection头字段中。
Early Data头字段不适用于用户代理(即请求的原始发起方)。在早期数据中发送请求意味着客户端理解该规范并且愿意响应425状态码重试请求。在早期数据中发送请求的用户代理不需要包括Early-Data头字段。
服务器无法通过等待握手完成来确保包含Early Data头字段的请求可以安全处理。在上一个跃点的Early-Data中发送了标记为早期数据的请求。必须使用425状态代码拒绝包含Early-Data头字段且无法安全处理的请求。
Early-Data头字段携带一位信息,客户端最多必须包含一个实例。服务器必须将头字段的多个或无效实例视为等效于值为1的单个实例。Early-Data头字段不得包含在响应或请求trailers中。
5.2. 425 (Too Early)状态码
425(太早)状态码表示服务器不愿意冒险处理可能被重放的请求。
期望在早期数据中发送请求的用户代理在接收425响应状态码时重试该请求。用户代理应该自动重试,但任何重试都不能在早期数据中发送。
在所有情况下,代理都可以转发425状态码。如果代理接收和转发的请求包含Early-Data头字段,则代理必须转发425状态码。否则,接收早期数据中的请求的代理可以响应425(状态码自动重试该请求,但它必须等待TLS握手在其接收到请求的连接上完成。
服务器不能假设客户端能够重试请求,除非在早期数据中收到请求或Early-Data头字段设置为1。除非满足其中一个条件,否则服务器不应发出425状态码。
默认情况下,425状态码不可缓存。其有效载荷不是任何已识别资源的表示。
6. 安全考虑
使用早期数据会使客户端面临其请求被重放的风险。重试或重放的请求可能会在服务器上产生不同的副作用。除了这些副作用之外,重放和重试还可以用于流量分析,以恢复有关请求或这些请求所针对的资源的信息。特别是,重放的请求可能会导致不同的响应,即使内容仍然保密,从受保护数据的长度来看,这可能是可以观察到的。
6.1. 网关和早期数据
网关不得转发早期数据中接收到的请求,除非它知道源服务器了解Early-Data头字段并将正确生成425状态码。不确定源服务器是否支持该请求的早期数据的网关应该延迟转发请求,直到与其客户端的TLS握手完成,或者发送425状态码作为响应。
一个网关如果没有至少一个支持Early-Data头字段的潜在源服务器,则需要花费大量精力才能从启用早期数据中获得适度的性能优势。如果没有源服务器支持早期数据,那么完全禁用早期数据会更有效。
6.2. 早期数据的一致处理
对到达早期数据或部分到达早期数据的请求进行一致处理对于避免对重放的请求进行不适当的处理至关重要。如果在TLS握手完成之前处理请求不安全,则服务器的所有实例(包括网关)都需要同意并拒绝请求或延迟处理。
禁用早期数据、延迟请求或拒绝425状态码的请求,都是缓解重放攻击的良好措施。服务器实例可以实现这些措施中的任何一个,并且是一致的,即使不同的实例使用不同的方法。至关重要的是,这意味着可以采用不同的缓解措施来应对其他情况,例如服务器负载(server load)。
如果服务器和任何其他服务器实例可能对如何处理相同的数据做出不同的决定,则在握手完成之前,服务器不得对早期数据采取行动。
6.3. 拒绝服务
接受早期数据会导致重放处理成本高昂的请求,使服务器面临潜在的拒绝服务风险。负载下的服务器应该更喜欢整体拒绝TLS早期数据,而不是接受早期数据并选择性地处理请求。生成503(Service Unavailable)或425状态代码通常会导致客户端重试请求,这可能会导致负载增加。
6.4. 乱序传输
在乱序传递数据的协议中(如QUIC[HQ]),早期数据可能在握手完成后到达。只有当服务器能够依靠其他实例正确处理相同请求的重放时,服务器才可以在握手完成后处理早期数据中接收到的请求。
7. IANA考虑
本文注册了Early-Data头字段,在"Permanent Message Header Field Names"(Message Headers)
头字段名字: Early-Data
应用协议: http
状态:标准
作者:IETF
标准文档:本文
本文注册了425 (Too Early)状态码,在"HTTP Status Codes"(https://www.iana.org/assignments/http-status-codes).
值: 425
描述: Too Early
Reference: 本文
8. 参考文档
8.1. 标准文献
[ABNF] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", STD 68, RFC 5234, DOI 10.17487/RFC5234, January 2008, <Information on RFC 5234 » RFC Editor>.
[HTTP] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing",RFC 7230, DOI 10.17487/RFC7230, June 2014, <Information on RFC 7230 » RFC Editor>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119,DOI 10.17487/RFC2119, March 1997, <Information on RFC 2119 » RFC Editor>.
[RFC7231] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content", RFC 7231,DOI 10.17487/RFC7231, June 2014, <Information on RFC 7231 » RFC Editor>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174,DOI 10.17487/RFC8174, May 2017, <Information on RFC 8174 » RFC Editor>.
[TLS13] Rescorla, E., "The Transport Layer Security (TLS) Protocol Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,<Information on RFC 8446 » RFC Editor>.
8.2. 参考性文献
[ALPN] Friedl, S., Popov, A., Langley, A., and E. Stephan, "Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension", RFC 7301, DOI 10.17487/RFC7301,July 2014, <Information on RFC 7301 » RFC Editor>.
[HQ] Bishop, M., "Hypertext Transfer Protocol (HTTP) over QUIC", Work in Progress, draft-ietf-quic-http-14, August 2018.
[RFC7540] Belshe, M., Peon, R., and M. Thomson, Ed., "Hypertext Transfer Protocol Version 2 (HTTP/2)", RFC 7540, DOI 10.17487/RFC7540, May 2015, <Information on RFC 7540 » RFC Editor>.
相关文章:
RFC8470在HTTP中使用早期数据
摘要 使用TLS早期数据会暴露出重放攻击的可能性。本文定义了允许客户端与服务器就早期数据中发送的HTTP请求进行通信的机制。描述了使用这些机制来减轻重放风险的技术。 1. 介绍 TLS 1.3[TLS13]引入了早期数据(也称为零往返时间(0-RTT)数…...
macOS Big Sur 11.7.9 (20G1426) 正式版 ISO、PKG、DMG、IPSW 下载
macOS Big Sur 11.7.9 (20G1426) 正式版 ISO、PKG、DMG、IPSW 下载 本站下载的 macOS 软件包,既可以拖拽到 Applications(应用程序)下直接安装,也可以制作启动 U 盘安装,或者在虚拟机中启动安装。另外也支持在 Window…...
【LeetCode】62.不同路径
题目 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? …...
使用序列化和反序列化函数archivedDataWithRootObject和unarchivedObjectOfClasses的使用和遇到问题及解决方案
为何archiveRootObject和unarchiveObjectWithFile正常,而archivedDataWithRootObject和unarchivedObjectOfClasses一直报错。 [NSKeyedArchiver archiveRootObject:account toFile:path];和c PPAccountModel *account [NSKeyedUnarchiver unarchiveObjectWithFile:…...
python获取鼠标出颜色
import pyautogui as pg import keyboarddef rgb2hex(r, g, b):return #{:02x}{:02x}{:02x}.format(r, g, b)try:width, height pg.size()print(f"Display resolution: {width} * {height}\n") # 打印屏幕分辨率print(按下shift键打印出鼠标所指位置的颜色......)w…...
Github Flow工作流简单介绍(以部署为中心的开发模式)
前言 这篇文章主要介绍Github Flow的理念,以下内容来源于《Github入门与实践》。 Github Flow是以部署为中心的开发模式,通过简单的规则,持续高速且安全地进行部署。而Gitflow则是以发布为中心的分支管理模型,它提供了一种更灵活…...
selenium浏览器驱动下载
Chrome谷歌浏览器 下载地址:http://chromedriver.storage.googleapis.com/index.html 不同的Chrome的版本对应的chromedriver.exe 版本也不一样,下载时不要搞错了。 如果是最新的Chrome, 下载最新的chromedriver.exe 就可以了。 Firefox火狐浏览器 驱…...
go学习 模块与包 - Init函数 - 如何导入第三方包 - 切片与数组的数据传递方式 - go中文件的读写
目录 包(package)是组织和复用代码的基本单元。 包的种类: 包的导入 包的组成 如下两个文件中定义了A变量和 sc_num变量,他们的首字母开头分别为大写和小写,因此可以说明A变量是公有变量,而sc_num是私…...
2023第五届全国生物资源提取与应用创新论坛即将举办
01、会议背景 为进一步加强生物资源提取行业交流与合作,促进业“产学研用”融合,提升行业科技创新水平,增强行业国际竞争力,中国生物发酵产业协会、浙江科技学院、浙江工业职业技术学院、浙江省农业生物资源生化制造协同创新中心&…...
Socks5代理在爬虫与HTTP应用中的重要性
IP代理的类型及原理常见的IP代理类型有HTTP代理、Socks代理等,本文重点关注Socks5代理。Socks5代理是一种网络协议,可以实现传输层的数据转发,使客户端在不直接连接服务器的情况下与其进行通信。其原理在于接收客户端的请求,然后将…...
二叉树详解
这里写目录标题 前言树型结构(了解)树常见的概念树的表示形式(了解)树的应用 二叉树概念两种特殊的二叉树二叉树的性质(重要)二叉树的存储二叉树的基本操作 前言 本篇博客讲述了以下几个知识点 树的基本概念二叉树概念及特性二叉树的基本操作 树型结构…...
Git的核心概念:探索Git中的提交、分支、合并、标签等核心概念,深入理解其作用和使用方法
🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~ἳ…...
JAVA设计模式——23种设计模式详解
一、什么是设计模式🍉 设计模式(Design pattern) 是解决软件开发某些特定问题而提出的一些解决方案也可以理解成解决问题的一些思路。通过设计模式可以帮助我们增强代码的可重用性、可扩充性、 可维护性、灵活性好。我们使用设计模式最终的目…...
Oracle输出文本平面(CSV、XML)文本数据详细过程
此过程是提供给前端,调用的接口,为报表提供”下载“功能。以下是本人在测试环境的测试,有什么不足的地方,请留言指教,谢谢。 1、测试表 分别对测试表输出csv、xml两种格式文件数据。前期的准备工作。 --在服务器端创建directory,用管理员用户 create or replace directo…...
基于C++的QT基础教程学习笔记
文章目录: 来源 教程社区 一:QT下载安装 二:注意事项 1.在哪里写程序 2.如何看手册 3.技巧 三:常用函数 1.窗口 2.相关 3.按钮 4.信号与槽函数 5.常用栏 菜单栏 工具栏 状态栏 6.铆接部件 7.文本编辑 8…...
【数据分享】全国地级市1999—2020年工业企业数(Shp/Excel格式)
在之前的文章中,我们分享过基于2000-2022年《中国城市统计年鉴》整理的1999-2021年地级市的人口相关数据、各类用地面积数据、污染物排放和环境治理相关数据、房地产投资情况和商品房销售面积、社会消费品零售总额和年末金融机构存贷款余额(可查看之前的…...
设计模式【行为型】-- 责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象依次处理同一个请求,形成一条责任链。当客户端提交一个请求时,请求沿着责任链传递,直到有一个处理者能够处理该请求为止。…...
[Spring] 三级缓存解决循环依赖详解
什么是循环依赖 注册一个bean对象的过程: Spring扫描class得到BeanDefinition – 根据得到的BeanDefinition去生成bean – 现根据class推断构造方法 – 根据推断出来的构造方法,反射,得到一个对象 – 填充初始对象中的属性(依赖注入) – 如果…...
gerrit 从安装到出坑
一般公司在做代码审核的时候选择codereview gerrit来处理代码的入库的问题。 它是通过提交的时候产生Change-Id: If4e0107f3bd7c5df9e2dc72ee4beb187b07151b9 来决定是不是入库,一般如果不是通过这个管理,那么就是我们通常的操作 git add . git comm…...
Java工程师就业前景怎么样?能拿多少工资?
Java软件工程师是指运用Java这个开发工具去完成软件产品的软件程序设计、开发、测试、维护升级等工作的人员。Java程序员可以分为初级、中级、高级、资深等。不同级别的Java程序员,薪资也不一样。 Java除了一般的编程,还可以开发游戏、进行桌面设计、Ja…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
