The differences between how SFTP and scp
work in OpenSSH
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 git@github.com).
|
|