ftp&ftps使用问题总结

1.  前言

在使用FTP/FTPS协议进行文件传输时,有一些特性可能会让人疑惑而导致问题,本文进行了总结。

2.  FTP说明

FTP协议的原始规范由Abhay Bhushan撰写,并于1971年4月16日发布为RFC 114。

2.1  FTP传输模式

wiki“File Transfer Protocol”关于ftp的主动模式与被动模式说明如下:

FTP可以以主动或被动模式运行,从而确定数据连接的建立方式。在这两种情况下,客户端从一个随机的,通常是非特权的端口N创建一个TCP控制连接到FTP服务器命令端口21。

在主动模式下,客户端开始侦听来自端口M上的服务器的传入数据连接。它发送FTP命令PORTM,通知服务器它正在侦听哪个端口。然后,服务器从其端口20(FTP服务器数据端口)向客户端发起数据通道。

在客户端位于防火墙后并且无法接受传入TCP连接的情况下,可能会使用被动模式。在此模式下,客户端使用控制连接向服务器发送PASV命令,然后从服务器接收服务器IP地址和服务器端口号,客户端然后使用它来打开数据连接一个任意客户端口到服务器的IP地址和服务器端口号。

被动模式又称为防火墙友好FTP(Firewall-Friendly FTP)。

使用主动模式FTP时,客户端需要监听端口供服务端访问,不便于使用;使用被动模式FTP时,只需要客户端访问服务器的端口,服务器不用访问客户端的端口,更加适合实际使用场景。

以下仅讨论FTP被动模式。

2.2  FTP端口

FTP使用的端口分为命令端口与数据端口,默认命令端口为21,默认数据端口为20。

通过FTP进行文件传输时,文件内容通过数据端口进行传输。

当FTP客户端与服务器之间存在防火墙时,命令端口与数据端口均需要允许访问,才能进行FTP文件传输。

命令端口由FTP服务器监听,可以telnet连接成功;数据端口无法通过telnet连接成功。

在某些型号的防火墙配置允许21端口通信后,会自动允许对应连接的20端口通信。

2.3  FTP数据表示方法

wiki“File Transfer Protocol”关于FTP数据表示方法说明如下:

FTP存在四种数据表示方法:

ASCII模式:用于文本。 如果需要,将数据从发送主机的字符表示转换为传输前的“8位ASCII”,并且(如有必要)将数据转换为接收主机的字符表示。 因此,此模式不适用于包含纯文本以外的数据的文件。

图像模式(通常称为二进制模式):发送机逐字节发送每个文件, 收件人收到字节流时收到它。(对于FTP的所有实现,建议使用图像模式支持)。

EBCDIC模式:用于使用EBCDIC字符集的主机之间的纯文本。

本地模式:允许具有相同设置的两台计算机以专有格式发送数据,而无需将其转换为ASCII。

通常使用二进制模式,不会对传输的文件内容进行修改。

ASCII模式会对传输文件内容中的回车换行符进行替换,导致文件内容被修改。

2.4  FTP被动模式

2.4.1  传输过程

FTP被动模式文件传输过程如下:

l  FTP客户端连接FTP服务器的命令端口,FTP服务器向FTP客户端返回数据端口及数据传输IP;

l  FTP客户端连接上一步获取的数据传输IP的数据端口,进行数据传输。

FTP客户端可以通过向FTP服务器发送PASV命令进入被动模式;FTP服务器可以决定FTP客户端进行数据传输时连接的IP与端口。

2.4.2  访问示例

2.4.2.1     Linux ftp命令

使用Linux ftp命令连接ftp服务器时,访问示例如下:

ftp> open xx.xx.xx.xx 9501

Connected to xx.xx.xx.xx (xx.xx.xx.xx).

220 Serv-U FTP Server v15.0 ready...

Name (xx.xx.xx.xx:app): user

---> USER user

331 User name okay, need password.

Password:

---> PASS XXXX

230 User logged in, proceed.

---> SYST

215 UNIX Type: L8

Remote system type is UNIX.

Using binary mode to transfer files.

ftp> ls

ftp: setsockopt (ignored): Permission denied

---> PASV

227 Entering Passive Mode (yy,yy,yy,yy,50,202)

2.4.2.2     Filezilla Client

使用Filezilla Client连接ftp服务器时,访问示例如下:

状态:   正在连接 127.0.0.1:21...

状态:   连接建立,等待欢迎消息...

响应:   220-FileZilla Server 0.9.60 beta

响应:   220-written by Tim Kosse (tim.kosse@filezilla-project.org)

响应:   220 Please visit https://filezilla-project.org/

命令:   USER test

响应:   331 Password required for test

命令:   PASS ****

响应:   230 Logged on

状态:   已登录

状态:   读取目录列表...

命令:   PWD

响应:   257 "/" is current directory.

状态:   列出“/”的目录成功

状态:   读取“/”的目录列表...

命令:   TYPE I

响应:   200 Type set to I

命令:   PASV

响应:   227 Entering Passive Mode (127,0,0,1,48,57)

命令:   MLSD

响应:   150 Opening data channel for directory listing of "/"

响应:   226 Successfully transferred "/"

状态:   列出“/”的目录成功

响应:   421 Connection timed out.

状态:   连接被服务器关闭

2.4.3  PASV命令回应

FTP客户端通过被动模式连接FTP服务器后,会向服务器发送PASV命令。

FTP服务器对于PASV命令的回应为“A1,A2,A3,A4,a1,a2”格式,其中包含了服务器返回的数据传输IP及数据端口,如“访问示例”部分黄色背景的内容。

“A1,A2,A3,A4”为服务器向客户端返回的数据传输IP,对应IP为“A1.A2.A3.A4”。如返回“127,0,0,1”,则对应的数据传输IP为“127.0.0.1”。

“a1,a2”为服务器向客户端返回的数据端口,将a1的十六进制作为高位与a2的十六进制作为低位进行拼接,拼接结果的十进制数值,为数据端口。如返回“48,57”,48=0x30,57=0x39,0x3039=12345,则数据端口为12345。

2.4.4  FTP跨局域网配置

当FTP客户端与服务器不在同一个局域网时,使用被动模式传输时配置需要进行调整,否则无法传输。

2.4.4.1     客户端不配置NAT

当FTP客户端不配置NAT时,FTP客户端直接访问FTP服务器的外网IP。此时FTP服务器需要将数据传输IP设置为FTP服务器的外网IP,不能设置为FTP服务器的局域网IP。

网络环境如下所示:

访问过程如下所示:

2.4.4.2     客户端配置NAT

当FTP客户端配置NAT时,FTP客户端只能访问在客户端NAT后的IP,无法直接访问FTP服务器的外网IP。此时FTP服务器需要将数据传输IP设置为客户端NAT后的IP,不能设置为FTP服务器的外网IP,也不能设置为FTP服务器的局域网IP。

网络环境如下所示:

访问过程如下所示:

2.4.5  FTP服务器被动模式配置

以FileZilla Server为例,对FTP服务器被动模式配置进行说明。

FileZilla Server的“Passive mode settings”配置中,可设置被动模式数据端口范围,数据传输IP,如下图所示,设置数据端口为2121,数据传输IP为“192.168.201.25”。

“Don't use external IP for local connections”选项是否钩选视情况而定。如果在通信时FTP服务器获取的FTP客户端IP为外网IP,则上述选项可以钩选;如果在通信时FTP服务器获取的FTP客户端IP为服务器局域网IP,则上述选项不能钩选。

3.  FTPS说明

3.1  FTPS与FTP对比

FTPS协议为FTP协议的扩展,通信数据通过SSL/TLS协议进行加密,其他特性与FTP协议一致。

FTPS服务器需要配置SSL密钥与证书。

FTPS协议与SFTP协议为不同的协议。

3.2  隐式ftps与显式ftps

wiki“FTPS”关于隐式ftps与显式ftps说明如下:

隐式方法要求从连接开始建立传输层安全性,从而破坏与非FTPS感知客户端和服务器的兼容性,但显式方法使用标准FTP协议命令和回复来升级纯文本连接到加密的一个,允许单个控制端口用于为FTPS感知和非FTPS感知的客户端提供服务。

隐式FTPS配置不支持协商。客户端将立即使用TLSClientHello消息来挑战FTPS服务器。如果FTPS服务器未收到这样的消息,服务器应该删除连接。

在显式模式(也称为FTPES)中,FTPS客户端必须“明确地请求”FTPS服务器的安全性,然后加强为双方同意的加密方式。如果客户端不要求安全性,则FTPS服务器可以允许客户端以不安全的方式继续或拒绝连接。

如果FTPS服务器仅允许FTPS连接,则FTP客户端在连接时需要选择隐式FTPS;如果FTP服务器允许FTP与FTPS连接,则FTP客户端在连接时可选择显式FTPS。

4.  FTP Java实现说明

4.1  被动模式设置

当使用org.apache.commons.net提供的FTP功能时,若需要使用被动模式,则需要在进行文件传输操作之前调用FTPClient类的enterLocalPassiveMode方法,使FTP客户端使用被动模式。

在以上方法中,会将__dataConnectionMode变量设置为PASSIVE_LOCAL_DATA_CONNECTION_MODE。

以上方法的注释如下:

Use this method only for data transfers between the client and server. This method causes a PASV (or EPSV) command to be issued to the server before the opening of every data connection, telling the server to open a data port to which the client will connect to conduct data transfers.

5.  常见异常分析

5.1  生产环境未添加数据端口策略

假如需要以客户端身份访问合作方的FTP服务器,由于测试环境的DMZ服务器访问公网端口无限制,因此可能导致漏掉对生产环境ftp服务器数据端口增加防火墙策略,需要进行检查。

5.2  FTP服务返回局域网IP

FTP客户端与FTP服务器不在同一个局域网,使用Linux的ftp命令登录FTP服务器,登录成功,但执行ls命令显示“Connection refused”,如下所示:

ftp> ls

227 Entering Passive Mode (192,168,0,16,193,82).

ftp: connect: Connection refused

ftp> ls

227 Entering Passive Mode (192,168,0,16,193,83).

ftp: connect: Connection refused

ftp> ls

227 Entering Passive Mode (192,168,0,16,193,84).

ftp: connect: Connection refused

ftp> ls

227 Entering Passive Mode (192,168,0,16,193,85).

ftp: connect: Connection refused

可以看到服务器返回的数据传输IP为“192.168.0.16”,为FTP服务器的局域网IP,说明FTP服务器配置的数据传输IP错误,需要进行修改。

5.3  FTP服务器未限制数据端口范围

使用Linux的ftp命令登录FTP服务器,登录成功,但服务器每次返回的数据端口不相同,如下所示:

ftp> ls

227 Entering Passive Mode (xx,xx,xx,xx,50,201)

ftp> ls

227 Entering Passive Mode (xx,xx,xx,xx,50,202)

之后返回的数据端口都次都加1

可以看到服务器返回的数据端口分别为“50,201”“50,202”等。

50=0x32,201=0xC9,0x32C9=13001。

50=0x32,202=0xCA,0x32CA=13002。

即服务器返回的数据端口分别为13001、13002等。

对以上操作进行抓包,结果分别如下,可以看到FTP客户端分别访问了FTP服务器的13001、13002等端口。

14:31:41.056265 IP [client ip].36918 > [server ip].9501: Flags [P.], seq 17:23, ack 50, win 115, length 6

14:31:41.090168 IP [server ip].9501 > [client ip].36918: Flags [P.], seq 50:102, ack 23, win 64208, length 52

14:31:41.090260 IP [client ip].36918 > [server ip].9501: Flags [.], ack 102, win 115, length 0

14:31:41.090315 IP [client ip].56974 > [server ip].13001: Flags [S], seq 1440044607, win 14600, options [mss 1460,sackOK,TS val 136313463 ecr 0,nop,wscale 7], length 0

14:31:54.087262 IP [client ip].36918 > [server ip].9501: Flags [P.], seq 29:35, ack 217, win 115, length 6

14:31:54.122054 IP [server ip].9501 > [client ip].36918: Flags [P.], seq 217:269, ack 35, win 64196, length 52

14:31:54.122122 IP [client ip].36918 > [server ip].9501: Flags [.], ack 269, win 115, length 0

14:31:54.122163 IP [client ip].44644 > [server ip].13002: Flags [S], seq 1338001892, win 14600, options [mss 1460,sackOK,TS val 136326495 ecr 0,nop,wscale 7], length 0

以上现象说明FTP服务器未限制数据端口范围,需要进行修改。

5.4  FTPClient类未设置使用被动模式

在Java代码中使用org.apache.commons.net的FTP功能进行文件上传,调用FTPClient类的storeFile方法进行文件上传后一直不返回。

调试发现依次进入storeFile、__storeFile、_storeFile、_openDataConnection_方法。

在_openDataConnection_方法中,执行了以下方法:

if (__dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE)

...

ServerSocket server = _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress());

...

socket = server.accept();

客户端启动了Socket监听,说明FTP客户端以主动模式运行。

ACTIVE_LOCAL_DATA_CONNECTION_MODE从变量名看是主动模式,根据该变量找到PASSIVE_LOCAL_DATA_CONNECTION_MODE变量,从变量名看是被动模式,根据“__dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE”找到enterLocalPassiveMode方法,该方法为进入被动模式。当__dataConnectionMode变量为PASSIVE_LOCAL_DATA_CONNECTION_MODE时,在_openDataConnection_方法中,会进入被动模式的处理流程,代码略。

因此当需要使用被动模式时,在进行文件传输操作之前需要调用FTPClient类的enterLocalPassiveMode方法。

6.  参考资料

File Transfer Protocol ­ Wikipedia

https://en.wikipedia.org/wiki/File_Transfer_Protocol

Active FTP vs. Passive FTP, a Definitive Explanation

http://slacksite.com/other/ftp.html

FTPS ­ Wikipedia

https://en.wikipedia.org/wiki/FTPS

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页