Содержание
SSH
– Почему неуловим Неуловимый Джо?
– Да потому, что он никому не нужен!
— Важный принцип практической криптографии
Сегодняшняя лекция посвящена сугубо практическим аспектам работы с darcs, но большая её часть – чистейшая теория. Дабы вы понимали, что почему бубном нужно трясти именно в такой последовательности.
Немного истории
(Я не обещаю, что всё правда было именно так, но примерно так оно и было).
В давние времена компьютеры были большие, а люди умные.В те времена особо богатый университет мог позволить себе целый компьютер. Компьютеры были очень большие. И кроме одного компьютера университет мог себе позволить много-много пар дисплей + клавиатура. Такие пары назывались терминалами.
Между компьютером и каждым терминалом была протянута сеть: каждое нажатие на клавиатуре шло по сети в компьютер, каждая буква, которая должна была быть отображена на экране, шла по сети к дисплею.
В те времена уже была сеть INTERNET (тогда она обязательно писалась всеми заглавными буквами: на многих клавиатурах того времени не было кнопки Shift, и все буквы всегда были заглавными), и иногда людям требовалось работать на компьютере соседнего университета. Для этого создали пару программ: telnet-сервер и telnet-клиент. telnet-клиент вёл себя точно так же, как терминал, только обменивался не с локальным компьютером, а через интернет с другим компьютером.
Тут маленькое полезное лирическое отступление. Подавляюще большая часть интернета сейчас (и в те времена тоже) основана на протоколе TCP (Transmission Control Protocol). Об этом протоколе полезно знать самую-самую его суть: за что он отвечает? Он отвечает за то (и только за то), чтобы между одной программой на одном компьютере и другой программой на другом компьютере установить обмен потоком байт. Компьютеры на концах потоков идентифицируются IP-адресом, программы – числом, которое стали называть портом.
Так вот, telnet на самом деле безо всяких хитростей устанавливал TCP-соединение и что ему набирают на клавиатуре, то и шлёт, что ему приходит по сети, то и рисует на экране. (Потом telnet'ом начали пользоваться и для того, чтобы отлаживать работу других сетевых протоколов. Это свойство этой программы оказалось настолько полезным, что она дожила до наших дней).
Сначала это казалось самым простым и самым удобным решением, но что-то людям не нравилось, им хотелось сделать, чтобы им не нужно было набирать каждый раз логи и пароль – или что уж, не знаю, по правде, – но придумали на смену telnet программу и протокол RSH (Remote SHell). Делало оно почти то же самое: обычным текстом по обычному TCP-соединению слало логин, пароль, команды пользователя, ответы программ с той стороны.
А потом настала эпоха хакеров, которым очень понравилось, что люди шлют пароли обычным текстом и их так легко читать.
И люди стали придумывать, как от них защищаться, и одним из методов защиты было шифрование соединений RSH. Протокол, который делал это шифрование, а также и программу, которая реализует этот протокол, назвали SSH (Secure SHell).
Об алгоритмах шифрования
Примерно в те времена, о которых идёт речь (впрочем, и вовсе с самого появления компьютеров), криптография переживала бурный подъём. Предлагалось много способов шифрования, люди открывали много механизмов атак и выдумывали, как с ними бороться.
Выявились два основных подхода к шифрованию: шифрование с открытым ключом, и шифрование с симметричным ключом.
Шифрование с симметричным ключом
У вас есть пароль (P), и есть функции шифрования и дешифрования, у которых один и тот же пароль является параметром (EP и DP). Эта пара функций обладает простым свойством: для любого сообщения M всегда DP(EP(M)) = M. Если P' != P, то и DP'(EP(M)) != M – т.е. расшифровать сообщение можно только тем же самым ключом. И других способов расшифровать сообщение нету, если ключ утерян, то это навсегда.
Такой тип шифрования применяют, когда нужно хранить на диске какие-нибудь данные, чтобы их не украли. Если вы где-нибудь видите шифровалку файлов, зашифрованную файловую систему или хранение ключа с пассфразой (см. ниже), знайте, это симметричный алгоритм шифрования.
Этот метод используется во многих разных шифрах, самые популярные: AES, Blowfish, DES. (Перечисляю их с тем, чтобы вы понимали, что этот подход к шифрованию не есть описание конкретного алгоритма; о надёжности шифра говорят в применении к конкретному шифру, а не к подходу).
Шифрование с открытым ключом
Этот тип шифрования используют для обмена сообщениями. Кроме SSH, о котором дальше, этим методом шифруют сообщения почты (умные слова GPG или PGP), да и много вообще чего.
Для этого типа шифрования каждый участник создаёт для себя пару из открытого (public) и закрытого (private / secret) ключей: P и S. (Мы будем вести себя так, будто открытый и закрытый ключ – это функции. На самом деле, сами ключи – это параметры к функциям). Эти два ключа обладают следующим свойством: они взаимно обратны, т.е. для любого сообщения M верно, что P(S(M)) = M и S(P(M)) = M. Кроме того, важно, что имея P угадать S невозможно.
Представим себе двух участников: Alice & Bob, у каждого есть свой закрытый ключ, а публичные ключи они выложили в сеть или просто обменялись ими. Т.е. у Alice есть два своих ключа и один ключ Bob: PA, SA, PB, а у Bob, соответственно, два своих и один Alice: PB, SB, PA.
Теперь, чтобы зашифровать сообщение Бобу, Алиса может применить к нему открытый ключ Боба: M' = PB(M). Такое сообщение сможет прочитать только Боб (точнее, только тот, у кого есть закрытый ключ Боба): SB(M') = SB(PB(M)) = M
У шифрования с открытым есть и ещё одно применение, не менее важно: оно позволяет человеку (скорее, конечно, компьютеру) доказать, что он обладает закрытым ключом, никому этот закрытый ключ не показывая. Это называется подписью.
Например, Алиса может поступить так: вместо того, чтобы отправить Бобу своё сообщение, зашифровать его своим закрытым ключом и послать. M' = SA(M). Получив сообщение M' , Боб может легко убедиться, что его могла послать только Алиса, а заодно вообще прочитать: M = PA(M'). (Обычно поступают несколько хитрее, и ради подписи шифруют не само сообщение, а его контрольную сумму – тогда подпись получается короче; само сообщение в таком случае шлют открытым текстом рядом с подписью).
У подписи есть один недостаток: если нехороший человек подслушает подписанное сообщение и повторит его дословно (включая подпись), то такое сообщение тоже будет выглядеть как подписанное и достоверное. Когда это кажется неприемлемым, в подписываемое сообщение включают точное время его отправления.
Отсюда рождается третье применение шифрования с открытым ключом, которое и интересует в первую очередь нас: аутентификация. Если Alice хочет доказать (что уж там далеко за названием ходить) Kodomo, это это именно она, то она может инициализировать примерно такой диалог:
- Alice: Я Alice!
Kodomo: докажи! (Вот тебе случайное число и точное время: 547873 = M)
Alice (шифрует: SA(M) = M' ): M'
Kodomo (проверяет PA(M') = 547873): Ок, ты Alice.
Наиболее заметные для нас алгоритмы шифрования с открытым ключом – это RSA, DSA и Diffie-Helman. Вроде бы, сейчас DSA считается более надёжным, поэтому именно его я предлагаю использовать. (На самом деле, это совершенно всё равно. Ни пароли у большинства из вас не шибко криптоустойчивые, ни данных, ценных взломщикам, у вас скорее всего никогда не будет. Криптоустойчивость алгоритма шифрования едва ли будет самым слабым местом)
Автоматическая аутентификация в SSH
Протокол SSH стал широко распространённым потому, что в нём предусмотрено несколько очень хороших вещей. Из них нам более всего интересно, что он позволяет выбирать механизм, которым мы будем аутентифицироваться, т.е. доказывать серверу, что мы – это мы.
Различимых с точки зрения пользователя механизмов аутентификации есть два: когда мы вводим пароль, или когда мы даём SSH-клиенту закрытый ключ, а серверу – открытый, и они сами между собой договариваются.
Чтобы использовать аутентификацию по ключам, их нужно сначала сгенерировать. В UNIX это делается командой ssh-keygen, в Windows – puttygen.
Человек, имеющий доступ к закрытому ключу, фактически сразу получает доступ ко всем местам, где находится открытый ключ. Поэтому как правило, закрытый ключ хранится в зашифрованном виде (его шифруют по симметричной схеме). Поэтому при создании ключа генератор спросит пассфразу – и всякий раз при его использовании SSH-клиент тоже будет спрашивать пассфразу, чтобы его расшифровать.
После создания ключа, нужно сообщить SSH-серверу, что человеку, доказавшему обладание закрытым ключом от открытого ключа, можно доверять работать с нашими правами. Для этого публичный ключ нужно положить в ~/.ssh/authorized_keys (~ – это домашняя диркетория; .ssh – это директория со служебными данными SSH, скорее всего, она у вас уже создана; authorized_keys – это текстовый файл, в котором на каждой строке лежит по одному публичному ключу). SSH-сервер – это довольно параноидальная программа. Она считает, что если у вас посторонний человек может читать или писать её служебную информацию, то этой служебной информации доверять нельзя. Поэтому может оказаться полезно сказать chmod -R go-rwx ~/.ssh (сменить права: рекурсивно (-R) у группы (g) и постороних (o) отнять (-) права на чтение (r), запись (w), исполнение (x) с директории ~/.ssh и её содержимого).
После этих процедур, если ssh-клиент знает, где лежит наш закрытый ключ, он будет пытаться использовать его при всяком логине (и, если это ему удалось, пароль с вас спрашивать не будет).
SSH-агент
SSH-клиент может самостоятельно провести все необходимые для этого переговоры, а может делегировать их специальной программе: SSH-агенту.
Изначально SSH-агенты создавались для ситуаций, когда мы заходим по SSH на одну машину (положим, на kodomo) оттуда на другую (положим, на kodomo-count) – чтобы при втором соединении мы могли использовать для своей аутентификации тот же закрытый ключ, не вынося его за пределы нашего компьютера, и, соответственно, оставаясь спокойными за его судьбу.
Однако у SSH-агента есть и ещё одно полезное свойство: это программа, которая может висеть в фоне в компьютере, и хранить в памяти закрытый ключ в расшифрованном виде (вспоминаем, что мы шифровали ключ прежде, чем сохранять его на постоянном носителе). Соответственно, сколько бы раз подряд ни протребовалось использовать этот ключ, пассфразу от него с нас спросят только один раз.
В Linux SSH-агент зовётся ssh-agent (и пользоваться им слегка нетривиально – см. подсказку к заданию, а ещё лучше man ssh-agent), в Windows он зовётся pageant, и он имеет дружелюбную иконку в трее, с простой и понятной менюшкой.
Darcs
Наконец, для чего был весь этот сыр-бор, вся эта чужеродная теория?
Всё это было ради того, чтобы научить вас работать с darcs, когда нам требуется установить соединение между двумя компьютерами – например, между домашним компьютером и kodomo.
Репозитории darcs умеют обмениваться друг между другом новостями. Вы это пробовали делать на втором занятии, когда говорили darcs push и darcs pull. Вы это наблюдали со стороны, читая мои письма, в которых я рассказывал, что же мне выдал очередной darcs pull в моей копии вашего репозитория.
Обмениваться изменениями darcs умеет кучей разных способов: по SSH, по HTTP, по FTP, по почте, и просто смотреть в соседнюю директорию (т.е. по файловой системе). Увы, на практике из всех этих методов удобен фактически только один: по SSH. (Остальные либо требуют очень уж много пляски с бубном – я говорю про почту и FTP, – либо позволяют только вытягивать изменения, но не отправлять – HTTP, – либо имеют много проблем с правами и ограничивают работу одним компьютером – файловая система).
Чтобы работать по SSH, нужно указывать darcs путь следующим образом: user@host:path. user@host – это то, что darcs сообщает SSH о том, куда он хочет соединиться. path – это путь, начиная с собственной домашней директории.
Например, чтобы присоединиться к своему репозиторию (user me, путь ~/Term3/Python/3), нужно сказать: darcs get me@kodomo.fbb.msu.ru:Term3/Python/3; если этот же самый me захочет присоединиться к моему репозиторию с решениями задач, то он может сделать это так: darcs get me@kodomo.fbb.msu.ru:~dendik/wx/python/3. При последюущих push и pull имя репозитория указывать, как водится, не надо.
Весь же сыр-бор про SSH был вот почему. Для любой, даже самой простой операции, darcs нужно скопировать порядка десяти файлов – и на каждое это действие он устанавливает новое SSH-соединение. Если бы вы работали с SSH по-старинке через пароли, то это было бы очень хорошей тренировкой рук.