How FTP and SFTP Work: File Transfer Protocols Compared
FTP (File Transfer Protocol) is one of the oldest application-layer protocols on the internet, predating the World Wide Web by over a decade. Defined originally in RFC 114 in 1971 and formalized in RFC 959 in 1985, FTP was designed to transfer files between hosts on an early internet where security was not a concern. It uses a distinctive dual-channel architecture -- a control channel for commands and a separate data channel for file content -- that made it uniquely capable for its era but has made it a persistent headache for firewalls, NAT devices, and security engineers ever since.
Despite its age, FTP remains in wide use -- legacy enterprise systems, government agencies, and hosting providers still rely on it. But the protocol transmits credentials in plaintext, its multi-channel design clashes with modern network architectures, and it offers no integrity verification for transferred files. This has driven the development of several successors: FTPS (FTP over TLS), SFTP (SSH File Transfer Protocol, which is not FTP at all), and SCP (Secure Copy). Understanding how each works, what problems they solve, and where they fail is essential for anyone managing file transfer infrastructure.
FTP Architecture: Control and Data Channels
FTP's defining characteristic is its use of two separate TCP connections: the control connection on port 21 and a data connection on a dynamically negotiated port. This was an elegant design in 1985 -- it allowed commands and file data to flow independently, so you could type commands while a large file transfer was in progress -- but it creates significant complexity for every network device that sits between the client and server.
The control connection is established by the client connecting to the server's port 21. This connection persists for the entire FTP session and carries all commands and replies in plaintext ASCII. FTP commands are simple text strings like USER alice, PASS secret123, LIST, RETR report.pdf, and STOR backup.tar.gz. Server replies use three-digit numeric codes followed by text: 220 Service ready, 331 User name okay, need password, 230 User logged in, 150 Opening data connection, 226 Transfer complete.
The data connection is opened for each file transfer or directory listing, used for that single operation, and then closed. This is where the complexity lies: the data connection can be initiated in two fundamentally different modes, and each has different implications for firewalls and NAT.
Active Mode vs. Passive Mode
The data channel can be established in two modes, and the difference between them is the root cause of most FTP connectivity problems.
Active Mode (PORT)
In active mode, the client opens an ephemeral port, sends a PORT command to the server over the control channel announcing its IP address and port number, and then waits. The server initiates the data connection from its port 20 to the client's announced port. The PORT command contains the IP address and port encoded as six comma-separated integers: PORT 192,168,1,50,176,171 means address 192.168.1.50, port 176 * 256 + 171 = 45227.
This worked perfectly in the 1980s when every host had a publicly routable IP address and no firewalls existed. Today it is almost always broken:
- NAT breaks it -- The client behind NAT sends its private IP address (e.g.,
192.168.1.50) in thePORTcommand. The server on the public internet tries to connect back to that private address and fails, because private addresses are not routable. Even if the NAT device rewrites the IP header, thePORTcommand contains the address in the application-layer payload, which NAT does not normally touch. - Firewalls block it -- The server initiates the data connection inward to the client. Client-side firewalls (stateful or otherwise) typically block unsolicited inbound connections. Opening a range of ports for incoming FTP data defeats the purpose of having a firewall.
- Port prediction -- The client must tell the server which port to connect to, which means the firewall must either permit a wide range of incoming ports or use deep packet inspection to parse the PORT command and dynamically open the correct port.
Passive Mode (PASV)
Passive mode reverses the data connection direction. The client sends a PASV command. The server opens an ephemeral port, responds with that port number, and the client initiates the data connection to the server. Since the client initiates both the control connection (to port 21) and the data connection (to the server's ephemeral port), passive mode works through client-side NAT and firewalls without special configuration.
The PASV response format is: 227 Entering Passive Mode (203,0,113,10,204,76), indicating port 204 * 256 + 76 = 52300. The client then connects to 203.0.113.10:52300.
However, passive mode shifts the firewall problem to the server side. The server must open a range of high ports for incoming data connections, and the firewall must permit inbound connections on those ports. Server administrators typically configure a restricted passive port range (e.g., 50000-50100) and open only those ports in the firewall. RFC 2428 introduced the EPSV (Extended Passive) command, which omits the IP address and returns only the port number, allowing it to work with both IPv4 and IPv6.
Why Active Mode Still Exists
Despite being broken by modern network architecture, active mode persists in some legacy environments. Certain mainframe FTP clients default to active mode, and some batch transfer systems from the 1990s were hardcoded to use it. Enterprise networks with permissive internal firewall rules between known subnets sometimes use active mode because it avoids the complexity of configuring passive port ranges on the server. When you encounter FTP connectivity issues, the first question to ask is which mode is in use.
FTP Authentication and the Plaintext Problem
FTP transmits everything on the control channel in plaintext. When a client authenticates, the username and password cross the wire as unencrypted ASCII text:
220 ftp.example.com FTP server ready
USER alice
331 Password required for alice
PASS my_secret_password_123
230 User alice logged in
Any device on the network path between the client and server -- a compromised router, a man-in-the-middle attacker, anyone on the same Wi-Fi network, or a monitoring system at the ISP -- can read the password directly from the packet capture. The password is not hashed, obfuscated, or encrypted in any way. It is transmitted as a literal string in the TCP payload.
This is not a theoretical risk. Packet-sniffing tools like Wireshark can extract FTP credentials from a pcap file in seconds. On shared networks, ARP spoofing or switch port mirroring trivially exposes every FTP session. In data center environments, any network tap or monitoring port captures the credentials. The simplicity of the attack -- no cryptographic skills required, just tcpdump port 21 -A -- makes plaintext FTP unacceptable for any system carrying sensitive data or credentials.
FTP also supports anonymous authentication, where users connect with the username anonymous and conventionally provide their email address as the password. Anonymous FTP was the primary way software was distributed on the internet before the web. Public repositories like ftp.gnu.org and university FTP archives were the original package repositories.
Binary vs. ASCII Transfer Mode
FTP supports two transfer modes that affect how file content is transmitted. Getting this wrong corrupts files -- a mistake that has bitten generations of developers.
ASCII mode (the default in many clients) translates line endings between platforms during transfer. UNIX systems use LF (\n, byte 0x0A), Windows uses CR LF (\r\n, bytes 0x0D 0x0A), and classic Mac OS used CR (\r, byte 0x0D). ASCII mode converts between these conventions based on the operating systems of the client and server. This is useful for plain text files -- scripts, configuration files, HTML -- but will corrupt binary files. A JPEG image, a compiled program, or a ZIP archive transferred in ASCII mode will be silently damaged as the FTP implementation replaces byte sequences that happen to look like line endings.
Binary mode (also called image mode, set with the TYPE I command) transfers files byte-for-byte with no translation. Every byte in the source file is reproduced exactly in the destination file. Binary mode should be the default for all transfers unless you have a specific reason to convert line endings. Modern FTP clients typically default to binary mode or auto-detect the file type, but older clients and scripts may still default to ASCII.
The TYPE command switches modes: TYPE A for ASCII, TYPE I for binary (image). A common pattern in FTP scripts is to issue TYPE I at the beginning of every session to ensure binary mode, regardless of the client's default.
FTP and Firewalls: Deep Packet Inspection
FTP's dual-channel architecture creates a fundamental tension with stateful firewalls. A stateful firewall tracks connections and only allows packets that belong to an established connection or are expected as part of one. But FTP's data channel is a separate TCP connection that appears unrelated to the control channel -- unless the firewall understands FTP.
To handle this, firewalls implement FTP application-layer gateways (ALGs), also called FTP helpers or FTP inspection modules. An FTP ALG performs deep packet inspection on port 21 traffic, parsing the control channel to detect PORT and PASV commands and their responses. When it sees a PASV response containing a port number, it dynamically creates a temporary firewall rule allowing the client to connect to that specific port. When the data transfer completes and the connection closes, the temporary rule is removed.
This works reasonably well in simple topologies, but FTP ALGs introduce their own problems:
- Performance overhead -- The firewall must inspect every packet on port 21 at the application layer, parsing the ASCII protocol for relevant commands. This is orders of magnitude slower than stateful packet filtering.
- Encryption breaks ALGs -- If FTP is wrapped in TLS (FTPS), the firewall can no longer read the control channel. It cannot see the
PASVresponse, cannot determine which port to open, and the data connection is blocked. This is a major reason FTPS adoption has been slow in environments with strict firewall policies. - Security risks -- FTP ALGs that rewrite
PORTcommands or modify IP addresses in the payload have historically been a source of vulnerabilities. A malicious FTP server could craft responses that trick the ALG into opening arbitrary ports on the firewall. - NAT ALG complications -- NAT devices with FTP ALGs must not only track port numbers but also rewrite the IP addresses embedded in
PORTcommands, replacing the client's private address with the NAT's public address. This application-layer rewriting is fragile and fails with encrypted control channels.
Linux's nf_conntrack_ftp kernel module is the canonical FTP ALG implementation. It parses FTP control connections, creates "expectation" entries in the connection tracking table for the anticipated data connections, and handles NAT rewriting for active mode. It can be loaded with modprobe nf_conntrack_ftp and optionally configured with ports=21,2121 to track FTP on non-standard ports.
FTPS: FTP over TLS
FTPS (RFC 4217) adds TLS encryption to the FTP protocol. Unlike SFTP, which is an entirely different protocol, FTPS is regular FTP with a TLS layer wrapped around the control and data channels. It comes in two variants:
Explicit FTPS (FTPES)
The client connects to port 21 in plaintext, then issues an AUTH TLS command to upgrade the control connection to TLS. This is the preferred method because it uses the standard FTP port and allows the server to support both unencrypted FTP and FTPS on the same port.
220 ftp.example.com FTP server ready
AUTH TLS
234 AUTH TLS successful
[TLS handshake occurs]
USER alice
331 Password required for alice
PASS my_secret_password_123
230 User alice logged in
PBSZ 0
200 PBSZ 0 successful
PROT P
200 Protection set to Private
The PBSZ 0 (Protection Buffer Size) and PROT P (Protection level Private) commands tell the server to encrypt the data channel as well. Without PROT P, only the control channel is encrypted and file data still transfers in plaintext -- a common misconfiguration that gives a false sense of security.
Implicit FTPS
The client connects to port 990 and immediately begins a TLS handshake -- no AUTH TLS negotiation. Data connections use port 989 instead of port 20. This was the older approach and is now deprecated in favor of explicit FTPS, but some legacy systems still use it. It wastes a dedicated port pair and does not allow plaintext fallback.
FTPS Challenges
FTPS solves the plaintext credential problem but inherits all of FTP's structural issues and adds new ones:
- Firewall ALG incompatibility -- Once the control channel is encrypted, the firewall cannot parse
PASVresponses to determine data connection ports. FTP ALGs become useless. Administrators must open a static range of passive ports and cannot use dynamic inspection. - Certificate management -- The server needs a TLS certificate, and each data connection technically requires a separate TLS handshake. Certificate validation, expiration, and chain-of-trust management add operational overhead that did not exist with plain FTP.
- Data channel negotiation -- The client must explicitly request data channel encryption with
PROT P. If either side fails to negotiate this correctly, credentials may be protected but file data is not. - NAT complications persist -- The underlying protocol still uses separate data connections. TLS does not eliminate the
PORT/PASVcomplexity -- it makes it harder to debug because you cannot inspect the encrypted control channel without terminating TLS.
SFTP: A Completely Different Protocol
Despite its name, SFTP (SSH File Transfer Protocol) has nothing to do with FTP. It is not FTP tunneled through SSH, not FTP with encryption added, and not a variant of FTPS. SFTP is a binary protocol defined in an Internet Draft (never an RFC -- it has been in draft status since 2001) that runs as a subsystem of SSH. It uses a single TCP connection on port 22 -- the same port as SSH -- and inherits all of SSH's encryption, authentication, and key exchange mechanisms.
How SFTP Works Internally
When you run sftp user@server, the following happens:
- An SSH connection is established to port 22 -- key exchange, host key verification, and user authentication proceed exactly as they would for an interactive SSH session.
- The SSH client requests the
sftpsubsystem. The server starts its SFTP server process (typically/usr/libexec/sftp-serveron OpenSSH) and attaches it to the SSH channel. - The client and server exchange SFTP protocol messages over the SSH channel. These are binary-encoded packets, not ASCII text like FTP commands.
SFTP protocol messages include operations like SSH_FXP_OPEN, SSH_FXP_READ, SSH_FXP_WRITE, SSH_FXP_STAT, SSH_FXP_READDIR, and SSH_FXP_RENAME. Each request carries a unique request ID, and responses reference that ID, allowing multiple operations to be in flight simultaneously (pipelining). This is more capable than FTP -- SFTP can do things like resume interrupted transfers, set file permissions atomically, create symbolic links, and lock files on the remote system.
Why SFTP Is Not FTP
This distinction matters for practical reasons:
- Port -- SFTP uses port 22 (SSH), not port 21 (FTP). If you configure a firewall rule for port 21, SFTP connections will not work.
- Authentication -- SFTP uses SSH authentication: public keys, SSH certificates, passwords (encrypted), or FIDO2 hardware tokens. FTP has its own authentication that sends passwords in plaintext.
- No data channel -- SFTP multiplexes everything over the single SSH connection. There is no active/passive mode distinction, no
PORT/PASVnegotiation, and no firewall ALG required. - Binary protocol -- SFTP commands are binary-encoded packets, not human-readable text. You cannot telnet to port 22 and type SFTP commands.
- No anonymous access -- SSH does not support anonymous authentication. If you need public file access, you need FTP or HTTP, not SFTP.
SFTP Performance Considerations
SFTP has a historical performance problem related to its windowing. The SFTP protocol uses a request-response model where the client sends read or write requests and waits for acknowledgments. The default buffer and request sizes in OpenSSH's SFTP implementation can be small, which means high-latency links suffer from poor throughput -- the client spends more time waiting for acknowledgments than transferring data. The SSH channel's own flow control (window size) adds another layer of potential bottleneck.
Modern OpenSSH (7.0+) and third-party SFTP clients mitigate this with larger buffers and request pipelining. The -B (buffer size) and -R (number of requests) flags to sftp can dramatically improve throughput over high-latency links. For example, sftp -B 262144 -R 256 uses 256 KB buffers with up to 256 outstanding requests, which keeps the pipeline full on links with hundreds of milliseconds of latency.
SCP: Secure Copy
SCP (Secure Copy Protocol) is another file transfer mechanism that runs over SSH. It predates SFTP and is simpler: SCP is essentially the rcp (remote copy) command from the BSD era, wrapped in an SSH tunnel. The original SCP protocol had no formal specification and relied on the behavior of /bin/sh on the remote system to interpret paths and expand globs.
SCP's command syntax is familiar: scp file.txt user@server:/path/ to upload, scp user@server:/path/file.txt . to download, scp -r directory/ user@server:/path/ for recursive copies. Under the hood, SCP launches a remote shell command via SSH, which makes it vulnerable to shell injection if the remote path contains special characters. This is why OpenSSH deprecated the legacy SCP protocol in version 9.0 (April 2022) and replaced it with SFTP as the underlying transfer mechanism, while keeping the scp command-line interface.
The practical differences between SCP and SFTP:
- SCP -- Simple, fast for single files, no resume capability, no directory listing, no file attribute preservation beyond basic permissions, deprecated protocol (OpenSSH 9.0+ uses SFTP internally).
- SFTP -- Full filesystem operations, resume support, better error handling, file locking, symbolic links, and a proper specification. Use SFTP unless you have a specific reason not to.
FTP and NAT: A Case Study in Protocol Misdesign
FTP's interaction with NAT is a canonical example of how embedding IP addresses in application-layer payloads breaks network transparency. The problem is fundamental: FTP transmits network addresses inside the data stream, and NAT only rewrites addresses in IP headers.
In active mode, the PORT command contains the client's IP address and port. If the client is behind NAT, this is a private address like 192.168.1.50. The server receives PORT 192,168,1,50,176,171 and tries to connect to 192.168.1.50:45227 -- an address that does not exist on the public internet. The connection fails.
In passive mode, the PASV response contains the server's IP address. If the server is behind NAT (common in hosting environments), the response might contain a private address. Some FTP servers detect this and are configured with the external IP address to embed in PASV responses, but this configuration is manual and error-prone. In multi-homed environments or cloud deployments where the public IP may change, it becomes a maintenance burden.
NAT ALGs attempt to solve this by rewriting the PORT and PASV payloads. But this introduces its own problems: the ALG must parse the FTP control stream in real time, correctly identify commands within the TCP byte stream (which may be segmented across multiple packets), handle UTF-8 and character encoding edge cases, and maintain synchronization with the connection state. Bugs in FTP NAT ALGs have been a persistent source of CVEs. And as soon as TLS encrypts the control channel, the ALG is blind.
This is why modern protocol design avoids embedding addresses in application-layer payloads. HTTP/2, QUIC, gRPC, and other modern protocols use a single connection and do not encode IP addresses in the data stream. FTP's dual-channel design was reasonable in a simpler era but became an anti-pattern as the internet evolved.
FTP Security Vulnerabilities
Beyond plaintext credentials, FTP has several other security problems that make it unsuitable for sensitive environments:
Bounce Attacks (FXP)
FTP's PORT command allows the client to specify any IP address and port, not just its own. This means a client can tell an FTP server to open a data connection to a third-party host -- effectively using the FTP server as a proxy to scan ports, bypass firewalls, or deliver payloads to internal hosts. This is the FTP bounce attack, described in the 1995 Hobbit paper. While most modern FTP servers reject PORT commands specifying addresses other than the client's, the attack demonstrated a fundamental design flaw: FTP trusted the client to provide honest network addresses.
No Integrity Verification
FTP provides no mechanism to verify that the file received matches the file sent. There is no checksum, hash, or digital signature in the protocol. A man-in-the-middle attacker can modify file content in transit, and neither the client nor server will detect the alteration. SFTP, by contrast, inherits SSH's MAC (Message Authentication Code) which guarantees integrity for every packet.
Directory Traversal
FTP servers that improperly sanitize path arguments can be vulnerable to directory traversal attacks. Commands like RETR ../../../etc/passwd or STOR ../../../tmp/backdoor.sh exploit servers that do not confine access to the FTP root directory. While this is an implementation bug rather than a protocol flaw, the simplicity of FTP's text-based commands makes it easy to probe for such vulnerabilities.
Denial of Service
FTP servers that create a new process or thread for each connection (as was common in older implementations like wu-ftpd) are susceptible to connection flooding. The stateful nature of FTP -- maintaining a persistent control connection per client -- consumes server resources in a way that stateless protocols like HTTP do not. Combined with anonymous access, this makes FTP servers attractive targets for resource exhaustion attacks.
FTP Command Reference
The FTP command set defined in RFC 959 is extensive but built around a few core operations. Understanding these commands helps when debugging FTP issues or reading packet captures:
| USER | Send username for authentication |
| PASS | Send password (plaintext) |
| LIST | List files in current directory (uses data channel) |
| NLST | Name list -- filenames only, no metadata |
| RETR | Retrieve (download) a file |
| STOR | Store (upload) a file |
| DELE | Delete a file |
| MKD | Make directory |
| RMD | Remove directory |
| CWD | Change working directory |
| PWD | Print working directory |
| PORT | Specify client address/port for active mode data connection |
| PASV | Request passive mode (server opens port) |
| EPSV | Extended passive mode (IPv6-compatible) |
| TYPE | Set transfer mode: A (ASCII) or I (binary/image) |
| AUTH | Authenticate security mechanism (AUTH TLS for FTPS) |
| PROT | Set data channel protection level (P for private/encrypted) |
| QUIT | Close the session |
Reply codes follow a structured system: 1xx indicates preliminary positive (action started), 2xx indicates completion, 3xx indicates the server needs more information (e.g., password after username), 4xx indicates transient failure (try again), and 5xx indicates permanent failure (bad command, access denied). The second digit groups replies by category: x0x is syntax, x1x is information, x2x is connections, x3x is authentication, x5x is filesystem.
Modern Alternatives to FTP
FTP's security and architectural shortcomings have driven adoption of several alternatives. The right choice depends on the use case:
SFTP (SSH File Transfer Protocol)
The natural successor for interactive and automated file transfers between servers. Ubiquitous on Linux/UNIX systems (ships with OpenSSH), requires no additional software, and provides strong encryption and authentication. The only downsides are performance overhead from encryption (negligible on modern hardware) and the lack of anonymous access.
rsync
For synchronizing files between systems, rsync is superior to any FTP variant. It computes delta checksums and transfers only the changed portions of files, making it dramatically more efficient for keeping directories in sync. rsync typically runs over SSH and inherits its security properties. The command rsync -avz -e ssh source/ user@server:/destination/ is the standard idiom for efficient, secure file synchronization.
HTTPS-Based Transfer
For distributing files to the public, an HTTPS server (often fronted by a CDN) has entirely replaced anonymous FTP. HTTP supports range requests for resuming downloads, content compression, caching, load balancing, and TLS encryption -- all through a single connection to port 443 that traverses any firewall. Object storage services like S3, Google Cloud Storage, and Azure Blob Storage provide HTTPS-based file hosting with presigned URLs for upload.
Managed File Transfer (MFT)
Enterprise environments that need audit trails, compliance reporting, automated workflows, and guaranteed delivery use MFT platforms. These typically support SFTP, FTPS, HTTPS, and AS2 as transport protocols but add business logic on top: scheduling, notifications, encryption at rest, PGP/GPG signing, and integration with identity providers. Products in this space include GoAnywhere, Axway, and IBM Sterling.
Cloud-Native Approaches
In cloud environments, file transfer is increasingly handled by platform-native services: S3 Transfer Acceleration, AWS Transfer Family (managed SFTP/FTPS endpoints backed by S3), Google Cloud Storage Transfer, and Azure Files. These eliminate the need to manage FTP servers entirely and integrate with cloud IAM, encryption, and logging. The AWS Transfer Family is notable because it provides an SFTP or FTPS endpoint that stores files in S3 -- allowing legacy systems that only speak FTP/SFTP to interact with cloud storage without code changes.
Protocol Comparison Summary
| Feature | FTP | FTPS | SFTP | SCP |
| Port | 21 + data | 21 + data (or 990) | 22 | 22 |
| Connections | 2+ (ctrl + data) | 2+ (ctrl + data) | 1 | 1 |
| Encryption | None | TLS | SSH | SSH |
| Authentication | Plaintext | TLS + plaintext | SSH keys/certs | SSH keys/certs |
| NAT-Friendly | No | Partially | Yes | Yes |
| Firewall-Friendly | No (ALG needed) | No (ALG broken by TLS) | Yes | Yes |
| Resume Support | REST command | REST command | Yes | No |
| Directory Listing | Yes | Yes | Yes | No |
| Integrity Check | None | TLS MAC | SSH MAC | SSH MAC |
| Anonymous Access | Yes | Yes | No | No |
| Status | Legacy | Active | Recommended | Deprecated |
Understanding File Transfer in the Network Stack
File transfer protocols are application-layer protocols that rely on the entire network stack beneath them. An SFTP session from your workstation to a remote server traverses TCP for reliable delivery, IP for addressing and routing, and ultimately BGP for determining the path packets take across autonomous systems. Understanding how these layers interact helps diagnose transfer problems: a slow SFTP transfer might be caused by TCP window scaling issues, packet loss on a congested peering link, or a suboptimal BGP route that sends traffic on a longer path.
You can trace the network path your file transfers take and explore how traffic routes between your systems by using the god.ad BGP Looking Glass. Look up the IP address of your file transfer server to see which autonomous system hosts it, examine the BGP routes advertising its prefix, and understand the peering relationships that determine how your data moves across the internet.