The differences between how SFTP and scp work in OpenSSH

July 29, 2017

Although I normally only use scp, I'm periodically reminded that OpenSSH actually supports two file transfer mechanisms, because there's also SFTP. If you are someone like me, you may eventually wind up wondering if these two ways of transferring files with (Open)SSH fundamentally work in the same way, or if there is some real difference between them.

I will skip to the end: sort of yes and sort of no. As usually configured, scp and SFTP wind up working in the same way on the server side but they get there through different fundamental mechanisms in the SSH protocol and thus they take somewhat different paths in OpenSSH. What happens when you use scp is simpler to explain, so let's start there.

How scp works is the same as how rsync does. When you do 'scp file apps0:/tmp/', scp uses ssh to connect to the remote host and run a copy of scp with a special undocumented flag that means 'the other end of this conversation is another scp, talk to it with your protocol'. You can see this in ps output on your machine, where it will look something like this:

/usr/bin/ssh -x -oForwardAgent=no -oPermitLocalCommand=no -oClearAllForwardings=yes -- apps0 scp -t /tmp/

(This is how the traditional BSD rcp command works under the hood, and the HISTORY section of the scp manpage says that scp was originally based on rcp.)

By contrast, how SFTP works is that it is what is called a SSH subsystem, which is a specific part of the SSH connection protocol. More specifically it is the "sftp" subsystem, for which there is actually a draft protocol specification (with OpenSSH extensions). Since the client explicitly asks the server for SFTP (instead of just saying 'please run this random Unix command'), the server knows what is going on and can implement support for its end of the SFTP protocol in whatever way it wants to.

As it happens, the normal OpenSSH server configuration implements the "sftp" subsystem by running sftp-server (this is configured in /etc/ssh/sshd_config). For various reasons it does so via your login shell, so if you peek at your server's process list while you're running a sftp session, it will look like this:

 cks   25346 sshd: cks@notty
  |    25347 sh -c /usr/lib/openssh/sftp-server
   |   25348 /usr/lib/openssh/sftp-server

On your local machine, the OpenSSH sftp command doesn't bother to have its own implementation of the SSH protocol and so on; instead it runs ssh in a special mode to invoke a remote subsystem instead of a remote command:

/usr/bin/ssh -oForwardX11 no -oForwardAgent no -oPermitLocalCommand no -oClearAllForwardings yes -oProtocol 2 -s -- apps0 sftp

However, this is not a universal property of SFTP client programs. A SFTP client program may embed its own implementation of SSH, and this implementation may support different key exchange methods, ciphers, and authentication methods than the user's regular full SSH does.

(We ran into a case recently where a user had a SFTP client that only supported weak Diffie-Hellman key exchange methods that modern versions of OpenSSH sshd don't normally support. The user's regular SSH client worked fine.)

So in the end, scp and SFTP both wind up running magic server programs under shells on the SSH server, and they both run ssh on the client. They give slightly different arguments to ssh and obviously run different programs (with different arguments) on the server. However, SFTP makes it more straightforward for the server to implement things differently because the client explicitly asks 'please talk this documented protocol with me'; unlike with scp, it is the server that decides to implement the protocol by running 'sh -c sftp-server'. OpenSSH sshd has an option to implement SFTP internally, and you could easily write an alternate SSH daemon that handled SFTP in a different way.

It's theoretically possible to handle scp in a different way in your SSH server, but you would have to recognize scp by knowing that a request to run the command 'scp -t <something>' was special. This is not unheard of; git operates over SSH by running internal git commands on the remote end (cf), and so if you want to provide remote git repositories without exposing full Unix accounts you're going to have to interpret requests for those commands and do special things. Github does this along with other magic, especially since everyone uses the same remote SSH login (that being

Written on 29 July 2017.
« Our (Unix) staff groups problem
Some terrible article page design elements on the modern web »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sat Jul 29 01:06:13 2017
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.