C#文件上传到FTPES C#如何实现显式或隐式的FTP over SSL/TLS

2次阅读

FTPES是显式TLS加密的FTP协议,客户端先明文连21端口再发AUTH TLS;而隐式FTPS已废弃,需直连990端口并立即ssl握手。.NET的FtpWebRequest仅支持FTPES,关键设置为EnableSsl=true、Credentials非空、UseBinary=true。

C#文件上传到FTPES C#如何实现显式或隐式的FTP over SSL/TLS

FTPES 是什么,和 FTPS 有什么区别

FTPES(FTP over Explicit SSL/TLS)是显式启用 TLS 的方式:客户端先用明文连接 FTP 服务器的 21 端口,再发送 AUTH TLS 命令协商加密;而隐式 FTPS(已基本废弃)要求一建立 TCP 连接就立刻进入 SSL 握手,使用 990 端口。.NET 的 FtpWebRequest 只支持 FTPES,不支持隐式 FTPS —— 所以你根本不用纠结“选哪个”,只要服务器开的是标准 FTPES(端口 21 + AUTH TLS),FtpWebRequest 就能用。

FtpWebRequest 上传文件到 FTPES 的关键设置

核心是三处布尔开关必须设对,缺一不可:

  • EnableSsl = true:告诉 .NET 启用 TLS 协商(触发 AUTH TLS
  • Credentials = new NetworkCredential(...):必须提供凭据,否则 EnableSsl = true 会抛 WebException(错误信息:The remote server returned an Error: (530) Not logged in.
  • UseBinary = true:二进制模式传文件,避免换行符被误转(尤其传 zip、exe、图片时)

示例片段:

FtpWebRequest req = (FtpWebRequest)WebRequest.Create("ftp://example.com/file.txt"); req.Credentials = new NetworkCredential("user", "pass"); req.EnableSsl = true; req.UseBinary = true; req.Method = WebRequestMethods.Ftp.UploadFile;  using (stream reqStream = req.GetRequestStream()) using (FileStream fileStream = File.OpenRead(@"C:localfile.txt")) {     fileStream.CopyTo(reqStream); }

证书验证失败怎么办:跳过或自定义校验

默认情况下,.NET 会严格校验证书链和主机名匹配。常见报错:The remote certificate is invalid according to the validation procedure.。这不是代码写错了,而是服务器用了自签名证书、通配符不匹配,或时间不同步。

生产环境不该跳过,但测试时可临时绕过:

  • 全局禁用(不推荐):ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
  • 按请求粒度控制(较安全):在创建 FtpWebRequest 前,给 req.ServicePoint 绑定回调,只对当前域名生效
  • 更稳妥的做法:实现校验逻辑,比如只接受特定指纹或固定 CN

注意:EnableSsl = true 必须在设置 ServicePoint 回调之后再赋值,否则回调可能不生效。

.NET Core / .NET 5+ 中 FtpWebRequest 的兼容性陷阱

从 .NET Core 2.1 开始,FtpWebRequest 被标记为“仅限 windows”,linux/macOS 上调用会直接抛 PlatformNotSupportedException。这意味着如果你部署在 docker(Linux 容器)或 azure app Service(Linux SKU)上,这段代码会挂掉。

替代方案只有两个现实选择:

  • 改用跨平台 FTP 库,如 FluentFTP(NuGet 包 FluentFTP),它原生支持 FTPES、主动/被动模式、自定义证书验证,API 也比原生更直观
  • 坚持用原生?只能限定部署在 windows Server 或 Windows Container 上,并确保目标框架是 net6.0-windows 或更高

FluentFTP 示例只需两行启 FTPES:

using (var client = new FtpClient("example.com", "user", "pass")) {     client.EncryptionMode = FtpEncryptionMode.Explicit;     client.UploadFile(@"C:localfile.txt", "/remote/file.txt"); }

真正容易被忽略的是:被动模式(PASV)下,FTPES 的数据通道也要加密,而 FtpWebRequest 会自动处理,但 FluentFTP 需显式设 DataConnectionType = FtpDataConnectionType.AutoActive 或依赖服务器配置 —— 这类细节不看文档很容易传一半卡住。

text=ZqhQzanResources