摘要
FEAT让 FTP 客户端在不逐条试运行扩展命令的情况下,取得服务器声明支持的扩展清单;OPTS则为尚未执行的目标命令选择行为。- 对实现了
FEAT的合规服务器,成功清单必须完整列出已支持的规范扩展;但500或502不能反证扩展不存在,因为早期服务器可能先实现扩展、后错过清单机制。 - 能力声明、选项接受、身份与权限、命令终局回复、数据连接以及最终文件状态,是六类不同证据。
“试试看”并不是无害的读操作
FTP 的基础命令来自 RFC 959,协议寿命远长于任何一次软件发布。后来出现的新命令、新参数和新安全机制,不可能在同一天进入所有服务器。客户端知道某份规范存在,并不等于知道眼前这台服务器已经实现它。
最直接的探测方式,是把候选命令逐条发出,观察服务器回什么。RFC 2389 指出,这种办法不仅增加流量,还可能产生不希望发生的效果。问题在于命令的语义:它本来是请求服务器做事,而不是请求服务器描述自己。用行动探测知识,会让探测本身成为风险来源。
FEAT 提供了一个独立的描述面。客户端只发送一个不带参数的词,服务器返回所支持扩展的结构化清单。客户端再把这份清单与自己的理解范围比较,决定下一步。公共层只规定清单的外壳;每项扩展仍由自己的规范定义标签、参数和具体效果。
这不是把决定权交给清单,而是让决定发生在行动之前。服务器描述本地能力,客户端自行判断是否采用,真正的命令随后再接受本地策略与运行状态检验。
一个空格为什么值得写进规范
有扩展可列时,服务器以多行 211- 回复开头,每项能力各占一行,并且必须以一个空格起始,最后用 211 End 结束。这个空格不是排版装饰。它保证能力行不会被误判成结束行,为解析器划出明确边界。
首行说明文字可以自由书写,能力行却必须遵守语法。标签往往像命令名,但并非必须如此;它也可以代表某种机制或属性。标签之后的参数由相应扩展规范解释。返回顺序没有含义,同一服务器两次回答时也无需维持同一顺序。
RFC 2389 还要求客户端容忍未知标签。较老客户端看到未来扩展时,不应把整份回复判为错误。它只需忽略自己不理解的部分,继续使用双方都懂的子集。这个约束把协议演进从“全懂或全失败”改成了可选择的兼容。
清单里不需要列出 FEAT 自己;收到非 500、非 502 的回复,已经证明服务器理解它。OPTS 也不列,因为实现 FEAT 的服务器必须同时实现 OPTS。清单只承担特定职责,不重复已经由交互证明的事实。
成功回复可以闭合,失败回复不能反推
RFC 2389 最精细的设计,是对“有”和“没有”采用不同证明标准。
只要服务器实现 FEAT,它就必须把 RFC 959 与 RFC 2389 之外、自己实际支持且有正式文档的 FTP 扩展全部列出。因此,一份合规的成功清单具有完备性:某项扩展若不在其中,客户端可以认为这台服务器不支持它。
但服务器若返回 500 或 502,只能证明它不认识 FEAT,不能证明它没有任何扩展。原因来自部署时间线。许多扩展早于 1998 年出现,旧服务器可能已经实现其中一项,却从未实现后来才定义的清单命令。此时,客户端为了兼容,仍可能单独测试那项旧扩展。
甚至“认识 FEAT,但没有扩展可报”也保留了这种模糊性。规范建议返回单行 211,却允许 500 或 502,因为对客户端而言,这与完全不认识 FEAT 几乎无法区分。
这形成了单向闭合:成功且合规的清单能消除清单范围内的不确定性;没有取得清单,只能留下未知,不能凭空制造“没有”。协议没有让历史沉默承担它从未承诺过的语义。
OPTS 改的是下一步,不是结果
能力并不总是开或关。有些扩展允许客户端选择返回内容或处理方式。OPTS 为这种选择提供统一命令形式:指定目标命令,再附上该命令规范定义的选项。
200 表示目标命令和选项都被识别并可接受;501 表示在状态不变时重复也不会成功的永久错误;451 表示服务器当前的临时条件阻止了接受。无论哪一种,都只说明选项交涉,不说明后续工作已经完成。
RFC 3659 的 MLST 是清楚的实例。服务器可在 FEAT 的 MLST 行中列出它能生成的文件事实,并用星号标明默认返回项。客户端发出 OPTS MLST 后,可以改变后续 MLST 与 MLSD 的事实集合。规范还提醒,一些非默认事实对服务器而言可能很昂贵,不应只为美化显示而随意索取。
于是,“支持某事实”“默认返回它”“客户端请求它”“它适用于这个文件”“服务器实际返回它”成为五个阶段。若系统只保存一个“支持”布尔值,就把选择、成本和具体结果全部抹掉了。
AUTH TLS 出现在清单中,并不等于连接已受保护
RFC 4217 把同一机制用于 FTP over TLS。支持该机制的 FEAT 服务器要列出 AUTH TLS、PBSZ 与 PROT。这些标签告诉客户端:这里存在一条可尝试的安全协商路径。它们并没有建立安全会话。
客户端仍须发送 AUTH TLS,服务器以 234 接受,双方完成 TLS 握手,随后设置保护参数,客户端按策略核验服务器证书身份,并完成所需的 FTP 用户认证。任何一步都可能失败。能力清单无法替证书作证,也不能替本地权限系统同意文件操作。
RFC 7151 定义的 HOST 也显示了相同边界。服务器支持虚拟主机时必须在清单中列出 HOST,但选择主机可能切换认证环境,所选名称仍需与证书身份对应。看到一扇门、选中一扇门、获得进入许可,并不是同一个事实。
IANA 登记的是名称边界,不是优劣裁决
扩展继续增加后,RFC 5797 建立 IANA 的 FTP Commands and Extensions 登记表,目的是避免不同机制占用同一命令或功能名称。登记项记录命令、FEAT 代码、说明、命令类型、实现要求与参考文档;历史项也保留,以免旧名称被重新使用。
RFC 5797 明确说明:登记并不证明一项扩展获得“批准”。满足永久公开规范,或者已经在普遍可获得的客户端和服务器中实现,均可能构成登记依据。表中的小写占位代码用于保留名称,也不意味着服务器应在 FEAT 中返回它们。
因此,登记表解决全局名称冲突;服务器清单描述本地实现;OPTS 记录本次选择;认证和策略决定此人此刻能做什么;命令回复与数据连接说明实际发生了什么。把登记表提升为运行真相,就会让薄协调层越权成为产品裁判。
披露能力,是为了减少更危险的探测
RFC 2389 承认,能力清单可能泄露服务器特征,观察者可据此推断更多信息。没有 FEAT 时,对方也能逐项探测命令,只是这种行为更容易在日志中留下可疑痕迹。作者认为这一区别不足以否定清单机制,同时要求各扩展自行处理其安全问题。
这里的选择不是“全公开”与“全保密”。它是在有限范围内公布稳定、可解析的能力描述,以减少用实际操作探测的必要。描述面提供选择所需的共同语义,执行面继续保留身份、策略、资源和结果的本地控制权。
RFC 2389 的历史意义,也正在这种克制里。它没有宣布“列出来就能用”,而是先回答“服务器声明会说哪种扩展语言”,再让运行中的交互回答“它是否愿意、是否能够、是否真的完成了这次请求”。清单是行动前的证据,不是行动后的凭证。
来源
- RFC 2389 — Feature negotiation mechanism for the File Transfer Protocol
- RFC Editor 的 RFC 2389 记录
- IETF Datatracker 的 RFC 2389 历史记录
- RFC 959 — File Transfer Protocol
- RFC 3659 — Extensions to FTP
- RFC 4217 — Securing FTP with TLS
- RFC 5797 — FTP Command and Extension Registry
- IANA — FTP Commands and Extensions
- RFC 7151 — File Transfer Protocol HOST Command for Virtual Hosts
- Heng Lu — Running-Code Primacy
- Heng Lu — Minimum Initial Specification, Localized Future Decision, and Voluntary Adoption
- Heng Lu — Reality Layers, Symbolic Power, and Clarity
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
