SCP (Secure Copy Protocol) všichni uživatelé unixových systémů znají jako nástroj pro kopírování souborů pomocí SSH. Jmenuje se tak protokol, i samotná utilita, která slouží k přenosu souborů. Obrovskou výhodou je jednoduchost: stačí vám přístup po SSH a můžete přenášet soubory tak jednoduše, jako to děláte na místním disku:
$ scp mistni_soubor.txt vzdaleny_server:/cesta/
Problém je ovšem v tom, jak to celé funguje uvnitř. Přestože navenek jde o prostou a převážně neškodnou utilitu, uvnitř je to vlastně jeden velký nestandardizovaný bastl, který přes terminálové spojení tlačí obsah souborů. Kromě jiného to má svá nezanedbatelná bezpečnostní rizika, o kterých si povíme níže.
Vývojáři OpenSSH každopádně už několik let uživatele varují, že podpora pro SCP se blíží ke konci a v některé z příštích verzí bude utilita scp
interně používat jiný protokol.
Poznámka: pro odlišení budeme protokol označovat jako SCP a utilitu jako scp
; stejně tak SSH je protokol, ssh
je utilita.
Jednoduchý přenos souborů
SCP se mezi uživateli stalo populárním zejména kvůli jednoduchosti a bezproblémovému provozu. Funguje jednoduše všude, kde máte terminálový přístup po SSH. Právě vlastností SSH také SCP využívá pro zajištění bezpečnosti, proto má také v názvu S jako Secure. Ovšem ve skutečnosti se o bezpečnost SCP vůbec nezajímá, veškerou autentizaci, autorizaci a šifrování nechává čistě na SSH.
Protokol SCP vychází ze staršího protokolu RCP (Remote Copy), který sloužil pro snadný přenos souborů po síti. Na rozdíl od něj ale SCP balí veškerou komunikaci do bezpečného spojení vytvořeného zmíněným SSH. Důležité také je, že ani RCP, ani jeho následovník SCP nejsou nijak standardizovány a na rozdíl od SSH nemají třeba vlastní RFC. Používáme je jednoduše ze zvyku: někdo zabalil RCP do SSH a fungovalo to dobře.
Funkce SCP je velmi jednoduchá a přímočará: po připojení k serveru je možné nahrát či stáhnout soubor a volitelně přenést i jeho základní vlastnosti jako jsou časové značky nebo oprávnění. Neprobíhá přitom žádná sofistikovaná komunikace, prostě se jen do SSH tlačí data unixovou rourou.
Od SSH přes SCP k RCP
V celé komunikaci jsou zapojeny dva programy: sshd
a scp
. První jmenovaný je démon (chcete-li služba), který poslouchá ve výchozím stavu na TCP portu 22 a přijímá spojení od klientů. Tím může být utilita ssh
používaná pro terminálové spojení nebo naše scp
pro přenos souborů.
Když zavoláme utilitu scp
, dojde k otevření nového SSH spojení a na druhé straně je pak také spuštěna utilita scp
. Té jsou ovšem předány nedokumentované parametry -t
nebo -f
. Jako to nebo from. Tím utilitě na druhé straně říkáme, jestli bude data přijímat nebo odesílat. Kromě toho jsou tu ještě parametry -d
a -r
, které říkají, že cíl je adresář nebo že zdroj je adresářový strom. Všimněte si, že přenos je z principu vždy jednosměrný, už na začátku musíme určit směr toku dat.
Jakmile jsou takto proti sobě otevřeny dvě instance utility scp
, mohou spolu začít komunikovat. Nemají k dispozici jiný kanál než ten přes SSH, používají proto ke komunikaci standardní vstup a výstup. Tím jsme získali kanál, kterým můžeme přenášet data pomocí protokolu RCP. Jak prosté.
Přenos pomocí RCP
Dále už se používá protokol RCP, který je velmi jednoduchý a má řadu omezujících vlastností. Především je sekvenční, umí tedy provádět v jednu chvíli právě jednu operaci. Zároveň je synchronní, před započetím nové akce musí být ta předchozí dokončena.
Protokol samotný je velmi prostý, příkaz je označen jedním písmenem, za kterým mohou následovat parametry a volitelně také data. Možné příkazy jsou:
C
– vytvoř souborD
– vstup do adresářeE
– opusť poslední adresářT
– nastav následujícímu souboru atributy
Přímo za příkazem pak obvykle následují parametry jako velikost souboru, název adresáře, časové značky pro zapsání a podobně. V případě vytváření souboru pak následuje rovnou tělo přenášeného souboru s daty.
Jako odpovědi jsou odesílány stavové bajty, které značí, jak akce dopadla:
0x00
– akce dopadla dobře0x01
– varování s textem určeným pro uživatele0x02
– chyba způsobující odpojení, opět může být doplněna textem
Vyzkoušíme si to
Funkce utility scp
se dá hezky jednoduše vyzkoušet a ověřit. Nepoužijeme přitom vůbec SSH, klienta bude jednoduše simulovat naše klávesnice. Můžeme rovnou spustit scp
v serverovém režimu a nechat si poslat na standardní výstup data určená pro přenos souboru. Protože vynecháme SSH, objeví se nám vše podstatné rovnou na obrazovce.
$ scp -qpf soubor.txt < /dev/zero T1646303542 0 1646303542 0 C0644 15 soubor.txt Obsah souboru!
Stejně tak můžeme vyzkoušet nahrání souboru. Tady ovšem musíme emulovat tu upovídanější stranu a sdělit jí, co budeme nahrávat. Stačí vlastně na vstup zkopírovat to, co nám vypsal první příkaz:
$ scp -qt soubor.txt T1646303542 0 1646303542 0 C0644 15 soubor.txt Obsah souboru!
Můžete zkusit přenést i jednoduchou adresářovou strukturu. V adresáři pokus
je soubor soubor.txt
a další podadresář test
obsahující soubor soubor2.txt
. Komunikace pro jejich přenos bude vypadat takto:
$ scp -qprf pokus/ < /dev/zero T1646303954 0 1646303955 0 D0755 0 pokus T1646303859 0 1646303900 0 C0644 15 soubor.txt Obsah souboru! T1646303963 0 1646303954 0 D0755 0 test T1646303963 0 1646303963 0 C0644 15 soubor2.txt Druhý soubor! E E
Kde je problém?
Tohle celé vypadá jako jednoduchý a dobrý přístup, ale jen na první pohled. Prvním problémem je sekvenčnost přenosu souborů, která způsobuje velikou režii a SCP se tedy nehodí pro přenos většího množství souborů. Zkušený admin vám řekne, že je mnohonásobně rychlejší nejdřív soubory zabalit pomocí utility tar
, přenést jeden velký soubor a na druhé straně si ho rozbalit. Nehledě na to, že je tak možné použít kompresi a tím přenos proti SCP ještě několikanásobně zrychlit.
Druhý problém spočívá v tom, že scp
zneužívá běžného terminálového přenosu. Ten je původně určen pro interakci s uživatelem a také se s ním tak pracuje. Pokud server vkládá do komunikace nějaké vlastní uvítací hlášky, utilita scp
to vyhodnotí jako chybu. Poslání prázdného řádku na konci takové informace dokonce běh zasekne, protože utilita bude čekat na dokončení obsahu domnělého chybového hlášení.
Problémem jsou také nejrůznější implementační chyby. Před časem se například přišlo na desítky let starý problém, který zákeřnému serveru umožňoval podvrhovat při přenosu klientovi vlastní soubory, které si nikdy nevyžádal. Mohl tak třeba klientovi podstrčit vlastní verzi souboru .ssh/authorized_keys
a tím si zajistit zpětný přístup.
Další známá chyba zneužívá toho, jak je při nahrávání souboru spuštěna utilita scp
na druhé straně. Název souboru je předáván jako její parametr, jak jsme to mohli vidět v příkladech nahoře. Potíž je, že do tohoto procesu je zapojen shell, který má samozřejmě tendenci obsah řádky před spuštěním interpretovat.
Co se stane, kdy se do názvu souboru dostanou třeba zpětné apostrofy? Ještě před spuštěním utility se provede příkaz, který je mezi nimi uzavřen. Na vzdáleném stroji je tak možné spouštět vlastní příkazy. Můžete si to snadno vyzkoušet:
$ scp soubor.txt root@192.168.1.208:'`touch /root/exploit2.sh`/root/soubor.txt'
Samozřejmě nejde jen o apostrofy, stejně tak bude fungovat i konstrukce $()
a cokoliv dalšího, co bude ochoten shell zpracovat. Navíc chyba není opravená a nikdy nebude, protože by to znamenalo zásah do podstaty fungování SCP a tím bychom přišli o zpětnou kompatibilitu.
Co místo scp
Nepříjemné je, že scp
nemá žádnou rovnocennou náhradu. Máme k dispozici sftp
a rsync
, ani jedno ale není tak jednoduché a přímočaré jako klasické scp
. V případě sftp
je potřeba se naučit složitější syntaxi a rsync
zase není ve většině distribucí předinstalovaný. Nezapomeňte, že utility musejí být k dispozici na obou stranách – u klienta i na serveru.
Pokud se chcete protokolu SCP zbavit už teď, nejjednodušší je scp
nahradit právě utilitou rsync
. Její syntaxe je velmi podobná, má výrazně vyšší výkon a netrpí výše zmíněnými bezpečnostními problémy. Do konfigurace svého shellu (třeba ~/.bashrc
) si můžete přidat alias, který zajistí volání rsync
místo původního scp
.
alias scp='rsync -a'
Naštěstí se řešení už blíží, před časem vznikla nová implementace příkazu scp, která interně využívá SFTP. Zbavuje se tedy problematického principu používaného pro přenos souborů a zároveň zachová jednoduchou obsluhu pro uživatele. Dočkáme se jí v OpenSSH snad už docela brzy.