Loading content...
Both SFTP and SCP achieve their security through SSH—they don't implement their own cryptography but rather delegate all security functions to the SSH layer beneath them. This architectural decision means that mastering secure file transfer requires deep understanding of SSH itself.
SSH provides more than just encryption: it handles authentication, key exchange, channel multiplexing, and configuration management. An administrator who understands only SFTP syntax but not SSH key management will struggle to deploy secure systems. A developer who knows the SFTP protocol but not SSH tunneling will miss powerful debugging and deployment patterns.
This page explores the SSH integration layer that powers SFTP and SCP: authentication mechanisms from passwords to certificates, key management best practices, configuration options that affect file transfer, and advanced features like agent forwarding and tunneling.
By the end of this page, you will understand SSH authentication methods and their security properties, how to generate, manage, and protect SSH keys, client and server configuration options affecting SFTP/SCP, SSH agent usage for key management, tunneling techniques for file transfer in complex networks, and security hardening practices for production SSH deployments.
SSH supports multiple authentication mechanisms, each with distinct security characteristics. Both SFTP and SCP inherit whichever authentication method the SSH connection uses.
Authentication Flow Overview:
SSH authentication occurs after the transport layer establishes encryption. The client proposes authentication methods; the server accepts or rejects each attempt until success or connection termination.
| Method | Security Level | Automation Friendly | Use Case |
|---|---|---|---|
| Password | Low-Medium | Poor (requires input) | Interactive human access, legacy systems |
| Public Key | High | Excellent | Automation, servers, standard deployments |
| Certificate | Very High | Excellent | Enterprise environments, centralized management |
| Keyboard-Interactive | Variable | Poor | Multi-factor authentication, OTP systems |
| Host-Based | Low | Good | Trusted networks (NOT recommended) |
| GSSAPI (Kerberos) | High | Good | Enterprise SSO, Active Directory integration |
Password Authentication:
The simplest method—user provides password, server verifies against local database or PAM. Despite simplicity, password authentication has critical weaknesses:
Public Key Authentication:
The gold standard for SSH security. Users possess a private key (never transmitted); servers store corresponding public keys. Authentication proves private key possession without revealing it.
123456789101112131415161718192021222324252627282930313233
Public Key Authentication Process: Client Server │ │ │ ─── SSH_MSG_USERAUTH_REQUEST ─────────────> │ │ method: "publickey" │ │ algorithm: "ssh-ed25519" │ │ public_key: [client's public key] │ │ has_signature: false │ │ │ │ <── SSH_MSG_USERAUTH_PK_OK ──────────────── │ Server confirms key is in authorized_keys │ │ │ [Client signs session_id + request with │ │ private key to prove possession] │ │ │ │ ─── SSH_MSG_USERAUTH_REQUEST ─────────────> │ │ method: "publickey" │ │ algorithm: "ssh-ed25519" │ │ public_key: [client's public key] │ │ has_signature: true │ │ signature: [signed data] │ │ │ │ [Server verifies signature using │ │ stored public key] │ │ │ │ <── SSH_MSG_USERAUTH_SUCCESS ────────────── │ │ │ Security Properties:• Private key NEVER transmitted• Signature includes session_id (prevents replay)• Server must have public key already (authorized_keys)• Compromising server doesn't reveal private keyFor SFTP/SCP servers, disable password authentication entirely: PasswordAuthentication no in sshd_config. This eliminates brute-force attacks completely. All automated file transfer should use key-based authentication; human interactive access can use certificates or jump hosts with stronger authentication.
Proper key management is fundamental to SSH security. Keys must be generated with strong algorithms, protected from unauthorized access, and rotated according to security policies.
Key Algorithm Selection:
| Algorithm | Key Size | Security Level | Recommendation |
|---|---|---|---|
| Ed25519 | 256-bit | Excellent | RECOMMENDED — Best security/size/speed ratio |
| ECDSA | 256/384/521-bit | Good-Excellent | Acceptable. 521-bit for highest security |
| RSA | 2048-4096 bit | Good-Excellent | Use 4096-bit for new keys. Legacy compatible |
| DSA | 1024-bit | Obsolete | AVOID — Deprecated, disabled in modern SSH |
Key Generation Commands:
1234567891011121314151617181920212223242526
# Generate Ed25519 key (RECOMMENDED for most uses)ssh-keygen -t ed25519 -C "user@example.com" # Generate Ed25519 with specific file pathssh-keygen -t ed25519 -f ~/.ssh/deploy_key -C "deployment key" # Generate RSA 4096-bit (for legacy compatibility)ssh-keygen -t rsa -b 4096 -C "user@example.com" # Generate ECDSA 521-bit (high security, slower)ssh-keygen -t ecdsa -b 521 -C "user@example.com" # Generate key without passphrase (for automation - USE WITH CAUTION)ssh-keygen -t ed25519 -f /home/svc/.ssh/backup_key -N "" -C "backup service" # Change passphrase on existing keyssh-keygen -p -f ~/.ssh/id_ed25519 # View key fingerprintssh-keygen -lf ~/.ssh/id_ed25519.pub # Convert key format (OpenSSH to PEM)ssh-keygen -p -m PEM -f ~/.ssh/id_rsa # Generate public key from private key (if .pub lost)ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pubKey File Security:
12345678910111213141516
# Correct permissions for SSH directory and fileschmod 700 ~/.sshchmod 600 ~/.ssh/id_*chmod 644 ~/.ssh/*.pubchmod 644 ~/.ssh/known_hostschmod 600 ~/.ssh/configchmod 600 ~/.ssh/authorized_keys # On servers # Verify permissionsls -la ~/.ssh/# Expected output:# drwx------ 2 user user 4096 ... .# -rw------- 1 user user 464 ... id_ed25519# -rw-r--r-- 1 user user 102 ... id_ed25519.pub# -rw-r--r-- 1 user user 1234 ... known_hosts# -rw------- 1 user user 234 ... configUnattended scripts requiring SFTP/SCP often use passphrase-less keys. This creates risk: anyone accessing the key file gains server access. Mitigate with: restricted command= in authorized_keys, chroot jailing, IP address restrictions (from= option), and monitoring key usage. Consider SSH certificates with short validity for highest-security automation.
The SSH agent provides secure key handling for interactive sessions, avoiding repeated passphrase entry while keeping keys protected. Understanding agent functionality is essential for efficient SFTP/SCP usage.
What the SSH Agent Does:
12345678910111213141516171819202122232425262728293031323334353637
# Start SSH agent (if not already running)eval "$(ssh-agent -s)"# Output: Agent pid 12345 # Add key to agent (prompts for passphrase)ssh-add ~/.ssh/id_ed25519 # Add key with timeout (removed from agent after 1 hour)ssh-add -t 3600 ~/.ssh/id_ed25519 # Add all default keys (~/.ssh/id_*)ssh-add # List keys currently in agentssh-add -l# Output fingerprints and key comments # List keys with full public keyssh-add -L # Remove specific key from agentssh-add -d ~/.ssh/id_ed25519 # Remove all keys from agentssh-add -D # Lock agent (requires password to use keys)ssh-add -x # Unlock agentssh-add -X # Check if agent is runningssh-add -l >/dev/null 2>&1 && echo "Agent running" || echo "No agent" # Use specific key for SFTP connectionsftp -i ~/.ssh/deploy_key user@serverAgent Forwarding:
Agent forwarding allows your local SSH agent to be accessible from remote hosts, enabling multi-hop connections without placing private keys on intermediate servers.
1234567891011121314151617181920212223242526272829303132
Without Agent Forwarding:┌──────────┐ ┌──────────────┐ ┌────────────────┐│ Laptop │ SSH │ Jump Server │ ?? │ Target Server ││ │ ───> │ │ ───> │ ││ [key] │ │ [no key] │ │ authorized_keys│└──────────┘ └──────────────┘ └────────────────┘ Problem: Can't authenticate to target Bad solution: Copy key to jump server (risky!) With Agent Forwarding:┌──────────┐ ┌──────────────┐ ┌────────────────┐│ Laptop │ SSH │ Jump Server │ SSH │ Target Server ││ │ ───> │ │ ───> │ ││ [key] │ + │ [agent fwd] │ │ authorized_keys││ [agent] │ │ │ │ │└──────────┘ └──────────────┘ └────────────────┘ Agent socket forwarded Jump server requests signatures from laptop Key never leaves laptop! Usage:# Enable forwarding for this connectionssh -A user@jumpserver # Then from jumpserver, SFTP to target workssftp user@target:/path/ # Uses forwarded agent # In SSH config:Host jumpserver ForwardAgent yes # Important: Only forward to TRUSTED serversAgent forwarding is convenient but dangerous: any root user on the intermediate server can use your forwarded agent to authenticate as you. Only enable forwarding to servers you fully trust. For untrusted paths, use ProxyJump (-J) which doesn't forward the agent. Modern OpenSSH prefers ProxyJump over agent forwarding for security.
SSH client configuration (~/.ssh/config) dramatically simplifies connection management and enables advanced patterns. SFTP and SCP honor these configurations automatically.
Configuration File Structure:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
# SSH Client Configuration Examples # Global defaults (apply to all hosts unless overridden)Host * ServerAliveInterval 60 ServerAliveCountMax 3 AddKeysToAgent yes IdentitiesOnly yes # Production file serverHost prod-files HostName sftp.production.example.com User deploy Port 22 IdentityFile ~/.ssh/prod_deploy_key Compression yes # Development servers (wildcard pattern)Host dev-* User developer IdentityFile ~/.ssh/dev_key StrictHostKeyChecking no # Only for ephemeral dev environments! UserKnownHostsFile /dev/null # Jump host configurationHost jumphost HostName jump.example.com User admin IdentityFile ~/.ssh/jump_key ForwardAgent no # Security: don't forward from jump # Access internal servers through jump hostHost internal-* ProxyJump jumphost # Modern alternative to ProxyCommand User internal_user IdentityFile ~/.ssh/internal_key Host internal-sftp HostName 10.10.10.50 Host internal-backup HostName 10.10.10.51Compression yes # Specific server with port forwardingHost db-tunnel HostName db.example.com User tunnel_user LocalForward 5432 localhost:5432 IdentityFile ~/.ssh/db_key # SFTP-only configuration (no shell access)Host sftp-server HostName sftp.external.com User sftp_only IdentityFile ~/.ssh/sftp_key RequestTTY no # SFTP doesn't need terminalKey Configuration Options for File Transfer:
| Option | Effect | File Transfer Impact |
|---|---|---|
| IdentityFile | Specifies which private key to use | Essential for multi-key setups |
| IdentitiesOnly yes | Only use explicitly specified keys | Prevents agent key confusion |
| Compression yes | Enable zlib compression | Faster text transfers, avoid for binary |
| ProxyJump host | Route through jump host | Enables firewall traversal |
| LocalForward | Port forwarding | Tunnel SFTP through restricted paths |
| ServerAliveInterval | Keepalive packets | Prevents idle disconnection |
| ConnectionAttempts | Retry attempts | More resilient connections |
| ConnectTimeout | Connection timeout | Fail fast on unreachable hosts |
| StrictHostKeyChecking | Host key policy | Set 'yes' for security (verify new keys) |
Test SSH config changes with 'ssh -v hostname' to see which options take effect. For SFTP, use 'sftp -v hostname'. The -v flag shows configuration parsing, key selection, and authentication attempts. Use -vvv for maximum verbosity when debugging.
SSH server configuration (/etc/ssh/sshd_config) controls authentication, security features, and SFTP-specific options. Proper configuration is essential for secure file transfer services.
Essential Security Configuration:
1234567891011121314151617181920212223242526272829303132333435363738394041
# Core Security SettingsProtocol 2PermitRootLogin noPasswordAuthentication noPermitEmptyPasswords noPubkeyAuthentication yesAuthorizedKeysFile .ssh/authorized_keys # Strong cryptography onlyKexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.comMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com # SFTP Subsystem ConfigurationSubsystem sftp internal-sftp # Connection limitsMaxAuthTries 3MaxSessions 10LoginGraceTime 30 # Idle timeout (disconnect inactive sessions)ClientAliveInterval 300ClientAliveCountMax 2 # LoggingSyslogFacility AUTHLogLevel VERBOSE # Restrict user accessAllowUsers deploy backup_user admin# Or use groups:# AllowGroups sftpusers admins # Chroot configuration for SFTP-only usersMatch Group sftponly ChrootDirectory /data/sftp/%u ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding no PermitTunnel noChroot Jail Configuration:
ChrootDirectory restricts SFTP users to specific directories, preventing access to the broader filesystem:
12345678910111213141516171819202122232425262728293031323334353637383940414243
#!/bin/bash# Setup SFTP-only user with chroot jail # Create group for SFTP-only usersgroupadd sftponly # Create user (no home directory, no shell)useradd -G sftponly -s /sbin/nologin sftpuser # Create chroot directory structure# CRITICAL: Chroot directory and all parents must be:# - Owned by root# - Not writable by anyone except root mkdir -p /data/sftp/sftpuserchown root:root /data/sftpchmod 755 /data/sftpchown root:root /data/sftp/sftpuser chmod 755 /data/sftp/sftpuser # Create writable directory inside chrootmkdir /data/sftp/sftpuser/fileschown sftpuser:sftponly /data/sftp/sftpuser/fileschmod 755 /data/sftp/sftpuser/files # Resulting structure:# /data/sftp/ root:root 755# /data/sftp/sftpuser/ root:root 755 (chroot point)# /data/sftp/sftpuser/files/ sftpuser:sftponly 755 (writable) # User sees:# / (actually /data/sftp/sftpuser)# /files/ (where they can read/write) # Add user's SSH keymkdir /data/sftp/sftpuser/.sshecho "ssh-ed25519 AAAA... user@client" > /data/sftp/sftpuser/.ssh/authorized_keyschown -R sftpuser:sftponly /data/sftp/sftpuser/.sshchmod 700 /data/sftp/sftpuser/.sshchmod 600 /data/sftp/sftpuser/.ssh/authorized_keys # Restart SSH to apply configsystemctl restart sshdThe chroot directory and all parent directories must be owned by root with no group or world write permission. This prevents users from escaping the jail by manipulating directory links. If permissions are wrong, SSH will refuse to complete the login with 'fatal: bad ownership or modes for chroot directory' in logs.
The authorized_keys file controls which public keys can authenticate and can restrict what authenticated users can do. Proper configuration enables secure automation while limiting exposure.
Authorized Keys Format:
1234567891011121314151617
# Basic entry: algorithm key-data commentssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample user@laptop # With options (comma-separated prefix)from="10.10.10.0/24,192.168.1.100" ssh-ed25519 AAAAC3NzaC1... backup-server # Force specific command (great for automation)command="/usr/local/bin/backup-script",no-pty ssh-ed25519 AAAAC3... backup-key # SFTP-only key with restrictionscommand="internal-sftp",no-port-forwarding,no-X11-forwarding,no-pty ssh-ed25519 AAAAC3... sftp-only-key # Full restriction example for automated SFTPfrom="10.0.0.50",command="internal-sftp -d /data/uploads",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAAC3... automated-uploader # Environment variable settingenvironment="DATA_DIR=/var/data",command="/scripts/process.sh" ssh-ed25519 AAAAC3... processor-keyKey Restriction Options:
| Option | Effect | Security Benefit |
|---|---|---|
| from="pattern" | Restrict source IPs/hostnames | Limits where key can be used from |
| command="cmd" | Force specific command instead of shell | Prevents arbitrary command execution |
| no-pty | Disallow terminal allocation | Blocks interactive shell (SFTP doesn't need PTY) |
| no-port-forwarding | Block local and remote forwarding | Prevents tunneling through server |
| no-X11-forwarding | Block X11 display forwarding | Prevents GUI tunneling |
| no-agent-forwarding | Block SSH agent forwarding | Prevents pivoting attacks |
| environment="VAR=value" | Set environment variables | Configure scripts without modification |
| restrict | Apply all restrictions by default | Whitelist approach (deny all, then permit) |
Example: Secure SFTP-Only Key:
12345678910111213141516171819
# Highly restricted automated upload key# - Only from specific IP# - SFTP only, no shell# - No forwarding of any kind# - Chrooted to /uploads directory (-d flag) from="203.0.113.50",command="internal-sftp -d /uploads",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleKeyDataHere automated-upload@supplier.com # What this prevents:# ✗ Connection from any IP except 203.0.113.50# ✗ Interactive shell access# ✗ SSH tunneling/port forwarding# ✗ Agent forwarding (prevents pivoting)# ✗ Access outside /uploads directory # What this allows:# ✓ SFTP operations within /uploads# ✓ Upload, download, list files# ✓ Standard SFTP functionalityModern OpenSSH (7.2+) supports 'restrict' which enables all restrictions by default. Then selectively add back needed capabilities. Example: 'restrict,pty ssh-ed25519...' blocks everything except terminal allocation. This whitelist approach is more secure than blacklisting dangerous options.
SSH tunneling enables file transfer through firewalls, bastion hosts, and complex network topologies. Understanding tunneling patterns is essential for enterprise environments.
ProxyJump: The Modern Approach:
12345678910111213141516171819202122232425
# Access internal SFTP server through jump hostsftp -J jumphost user@internal-server # Multiple jump hosts (A → B → C → target)sftp -J host-a,host-b,host-c user@target # In SSH config (preferred):Host internal-sftp HostName 10.10.10.50 User fileuser ProxyJump jumphost.example.com # Then simply:sftp internal-sftp # ProxyJump with specific user/port on jump host:Host target HostName target.internal ProxyJump admin@jump.example.com:2222 # How ProxyJump works:# 1. SSH to jump host# 2. Jump host opens TCP connection to target# 3. Local SSH client tunnels through to target# 4. Full encryption end-to-end (jump host sees encrypted traffic)Local Port Forwarding:
Port forwarding creates a local port that tunnels to a remote service:
1234567891011121314151617181920212223242526272829303132
Scenario: Access SFTP server behind firewall Network layout:┌──────────────┐ ┌──────────────┐ ┌────────────────┐│ Your Machine │ │ Jump Server │ │ SFTP Server ││ │ │ │ │ ││ │--->│ :22 │--->│ :22 ││ localhost │ │ 1.2.3.4 │ │ 10.0.0.50 ││ :2222 │ │ (accessible) │ │ (internal only)│└──────────────┘ └──────────────┘ └────────────────┘ # Create tunnel (leaves connection open)ssh -L 2222:10.0.0.50:22 user@1.2.3.4 -N # Now connect SFTP through tunnelsftp -P 2222 sftpuser@localhost # Combined as single command (background tunnel):ssh -f -L 2222:10.0.0.50:22 user@1.2.3.4 -Nsftp -P 2222 sftpuser@localhost # In SSH config (automatic):Host sftp-internal HostName localhost Port 2222 User sftpuser LocalCommand ssh -f -L 2222:10.0.0.50:22 jump@1.2.3.4 -N PermitLocalCommand yes # Dynamic forwarding (SOCKS proxy) - less common for SFTP:ssh -D 1080 user@jump# Then configure SFTP client to use SOCKS proxyPrefer ProxyJump for SFTP access through jump hosts—it's simpler, doesn't require port management, and handles connection multiplexing correctly. Use port forwarding only when ProxyJump isn't available (very old SSH versions) or when you need to expose the tunnel to other local applications.
We've comprehensively explored how SFTP and SCP leverage SSH's security infrastructure. This knowledge is essential for deploying and managing secure file transfer in production environments.
What's Next:
The final page of this module examines the security benefits of SFTP and SCP in a comprehensive security context—threat defense, compliance requirements, audit logging, and best practices for enterprise deployments where secure file transfer is mission-critical.
You now understand how SFTP and SCP integrate with SSH's security infrastructure—from authentication and key management through client/server configuration to advanced tunneling. This knowledge enables you to deploy, secure, and troubleshoot SSH-based file transfer in any environment.