Урок №10 1979–2017 20 мин
Хеши: отпечатки данных
Функция, которая превращает что угодно в короткую строку — и не позволяет вернуться назад. На ней держатся пароли, загрузки и подписи. Разбираемся, как её обманывают и как защищаются.
В этом уроке
- что такое хеш и чем он отличается от шифра
- лавинный эффект: одна буква меняет половину битов
- как хранят пароли и как их подбирают по словарю
- зачем нужна соль и что такое радужные таблицы
- что такое коллизия и почему MD5 и SHA-1 сломаны
Июнь 2012 года. На форуме взломщиков появляется файл: шесть с половиной миллионов строк, в каждой — сорок шестнадцатеричных знаков. Это хеши паролей пользователей LinkedIn. Самих паролей в файле нет — сайт их не хранил. И всё же уже через несколько дней значительную часть паролей подобрали и выложили открытым текстом.
Как можно «расшифровать» то, что не было зашифровано? Почему сайт хранил не пароли, а какие-то хеши? И что он сделал не так? Чтобы ответить, разберёмся с самой полезной функцией в криптографии — той, которая ничего не прячет, а только оставляет отпечаток.
Отпечаток данных
Хеш-функция берёт любые данные — слово, книгу, фильм на десять гигабайт — и выдаёт строку фиксированной длины. Эту строку называют хешем (от англ. hash — «мешанина, фарш»). Например, у функции SHA-256 хеш всегда занимает 256 битов, то есть 64 шестнадцатеричных знака. Вот хеш слова «пароль»:
2dbc574daca52689a24fb60e835f8c19a36400830df7350859dd32d1abaaec5d
Хорошая хеш-функция обладает четырьмя свойствами:
- Детерминированность. Одни и те же данные всегда дают один и тот же хеш — на любом компьютере, в любой день.
- Необратимость. По хешу нельзя восстановить данные. Как по фаршу не собрать котлету обратно в кусок мяса.
- Лавинный эффект. Измените хоть один бит на входе — и хеш станет совершенно другим.
- Стойкость к коллизиям. Практически невозможно найти два разных входа с одинаковым хешем.
Хеш — не шифр. У шифра есть ключ, и с ключом всё возвращается обратно. У хеша ключа нет, и обратно не возвращается ничего. Он нужен не чтобы прятать, а чтобы узнавать. Скачали программу — сравнили её хеш с тем, что напечатан на сайте автора: совпало, значит, ни один байт по дороге не испортился и не подменён. На хешах держатся системы контроля версий вроде Git, цифровые подписи и блокчейны. Посчитать хеш чего угодно можно в утилите «Хеш онлайн».
Лавинный эффект
Самое удивительное свойство — лавина. Хеш похожих текстов не похож ни капли. Поменяли «9» на «8» — и перевернулась примерно половина из 256 битов, причём заранее не скажешь, какие именно.
Почему ровно половина? Потому что так ведёт себя случайность. Если хеш выглядит как случайная строка, то каждый бит нового хеша совпадает со старым с вероятностью ½ — как монетка. Из 256 монеток орлом ляжет около 128. Если бы перевернулось сильно меньше — скажем, 10 битов, — по хешу можно было бы судить, насколько похожи входы, и это стало бы зацепкой для взломщика.
SHA-256 слова «кот» начинается с одних знаков. Что можно сказать о SHA-256 слова «кит»?
В хорошем хеше каждый бит зависит от каждого бита входа. Одна буква — и перемешивается всё: хеши «кот» и «кит» так же непохожи, как хеши «кот» и «Война и мир».
Как хранят пароли
Вы регистрируетесь на сайте и придумываете пароль. Хранить его как есть было бы опасно: любой, кто доберётся до базы данных — взломщик, нечестный сотрудник, вор резервной копии, — увидит пароли всех пользователей. А люди, увы, используют один пароль везде.
Поэтому сайт хранит не пароль, а его хеш. Когда вы входите, сайт хеширует то, что вы набрали, и сравнивает с хешем в базе. Совпало — пароль верный. Самого пароля сайт не знает и узнать не может: хеш необратим. Утечёт база — утекут только хеши.
Но необратимость не значит, что пароль не подобрать. Взломщик не может пройти от хеша к паролю, зато может пойти от пароля к хешу: взять вероятный пароль, посчитать хеш и сравнить. А пароли у людей поразительно одинаковые: «123456», «qwerty», «password» годами возглавляют списки самых частых. Достаточно один раз посчитать хеши для словаря популярных паролей — и затем просто искать готовые хеши в утёкшей базе.
В утёкшей базе нашлась ещё одна строка, без соли. Пароль директора — одно из слов словаря выше. Посчитайте хеши словаря и найдите, какое слово дало этот хеш:
378a50d244b6ee8166778f54e2a5d4c518d02354d5a0ff1a0937885c1b4e06c7
Нажмите в виджете «Посчитать хеши словаря». Под каждым словом появятся первые десять знаков его хеша.
Ищите слово, хеш которого начинается с 378a50d2.
Это зайчик: SHA-256 этого слова начинается с 378a50d244. Чтобы его найти, не понадобилось ничего «расшифровывать»: мы посчитали хеши двух десятков слов и сравнили.
Настоящие словари взломщиков содержат миллиарды слов — все пароли из прошлых утечек, имена, даты, слова с цифрами на конце. Видеокарта считает миллиарды хешей SHA-256 в секунду. Поэтому пароль, который хоть раз кто-то придумал до вас, почти бесполезен.
Если посчитать хеши заранее для огромного числа паролей, таблица получится гигантской. В 2003 году Филипп Ошлен придумал, как хранить её в сотни раз компактнее, ценой небольших вычислений при поиске. Такие таблицы назвали радужными. Их можно скачать готовыми для популярных хеш-функций — и находить пароль по хешу почти мгновенно.
Именно это и случилось с LinkedIn: пароли хранились как хеши SHA-1 без всякой защиты от готовых таблиц. Каждый простой пароль находился поиском по уже посчитанному.
Соль
Защита от готовых таблиц удивительно простая. Перед хешированием к паролю каждого пользователя приписывают соль — случайную строку, свою у каждого. В базе хранят соль и хеш от «соль + пароль». Соль не секретна, она лежит рядом с хешем. Но она делает две важные вещи.
Во-первых, готовые таблицы становятся бесполезными: никто не считал заранее хеш «7f3a» + «qwerty». Во-вторых, у двух пользователей с одинаковым паролем теперь разные хеши, поэтому взломщику приходится перебирать словарь для каждого отдельно. Эту идею использовали ещё в Unix конца 1970-х годов: её описали Роберт Моррис и Кен Томпсон в статье 1979 года о безопасности паролей.
В утёкшей базе 1000 пользователей, у каждого своя соль. У взломщика словарь из 10 000 паролей. Сколько хешей ему придётся посчитать, чтобы проверить весь словарь против всех пользователей? (А без соли хватило бы 10 000.)
Соль у каждого своя, значит, хеш «соль + пароль» для одного пользователя бесполезен для другого.
Для каждого из 1000 пользователей нужно заново прогнать 10 000 слов: 1000 × 10 000 = 10 000 000 хешей. Соль увеличила работу ровно во столько раз, сколько пользователей в базе.
Заметьте, что соль не спасает слабый пароль: «123456» найдётся первой же попыткой даже с солью. Она защищает от оптовой атаки — когда одна таблица ломает миллионы пользователей разом.
Второй приём — сделать каждую попытку дорогой. SHA-256 создан, чтобы быть быстрым, и это плохо для паролей: быстрый хеш — быстрый перебор. Для паролей придумали нарочно медленные функции: bcrypt (1999), scrypt (2009), Argon2 (победитель конкурса 2015 года). Одна проверка у них занимает, скажем, десятую долю секунды. Пользователь при входе этого не заметит, а взломщик со словарём из миллиарда слов застрянет на годы. Утилита «Шифрование AES по паролю» использует для того же PBKDF2 — 250 000 повторов SHA-256.
Хеш не расшифровывают — его подбирают: считают хеши вероятных паролей и сравнивают. Соль заставляет подбирать для каждого пользователя отдельно, медленный хеш делает каждую попытку дорогой. А от длинного случайного пароля не спасает только честный перебор, на который не хватит жизни.
Коллизии и дни рождения
Хешей SHA-256 — 2256 разных, число из 78 цифр. А возможных входов бесконечно много. Значит, у каких-то разных входов хеши обязательно совпадают. Такое совпадение называется коллизией. Они существуют у любой хеш-функции; вопрос лишь в том, можно ли их найти.
Тут помогает задача о днях рождения. Сколько человек надо собрать, чтобы с вероятностью больше половины у двоих совпал день рождения? Не 183, а всего 23. Ведь мы ищем совпадение любой пары, а пар среди 23 человек уже 253. Для хешей правило такое: у хеша длиной k битов коллизия находится примерно за 2k/2 попыток — корень из числа всех возможных хешей.
Для полного SHA-256 это 2128 попыток — больше, чем все компьютеры Земли успеют за время существования Вселенной. А вот у старых функций нашлись обходные пути, гораздо быстрее перебора.
- MD5 (1991, 128 битов). В 2004 году группа китайского математика Ван Сяоюнь показала, как быстро строить коллизии. Сейчас обычный ноутбук находит их за секунды. В 2012 году вредоносная программа Flame использовала коллизию MD5, чтобы подделать цифровой сертификат Microsoft.
- SHA-1 (160 битов). В 2017 году Google вместе с голландским институтом CWI опубликовал два разных PDF-файла с одинаковым SHA-1. Проект назвали SHAttered.
- SHA-256 и его родственники. Ни одной коллизии не найдено, ими пользуются повсюду.
Что даёт коллизия злоумышленнику? Представьте: вы подписываете хеш безобидного договора, а у мошенника заготовлен второй договор с тем же хешем. Подпись подходит к обоим. Поэтому сломанной хеш-функции больше нельзя доверять подписи и сертификаты, даже если пароль по её хешу всё ещё не восстановить.
Что значит «MD5 сломан»?
Сломан он в смысле коллизий: для MD5 известны способы построить два разных входа с одинаковым хешем гораздо быстрее перебора. Для проверки случайных ошибок он ещё годится, а для подписей и защиты от подделки — нет.
Что взять с собой
- Хеш — отпечаток данных фиксированной длины. Его нельзя обратить, и он меняется целиком от любой правки (лавинный эффект: около половины битов).
- Сайты хранят хеши паролей, а не пароли. Но хеши подбирают: считают хеши словаря и сравнивают. Простой пароль находится мгновенно.
- Соль — случайная строка у каждого пользователя. Она обесценивает готовые и радужные таблицы и заставляет перебирать для каждого отдельно. Медленные хеши (bcrypt, scrypt, Argon2) делают каждую попытку дорогой.
- Коллизии есть у любого хеша, но у хорошего их не найти: для k битов нужно около 2k/2 попыток. MD5 и SHA-1 сломаны, SHA-256 — нет.
И у шифров, и у хешей до сих пор оставалась одна общая проблема: как вообще договориться о секрете с человеком, которого вы никогда не видели? Тысячи лет считалось, что никак. Дальше: открытый ключ →
Утилиты урока
Всё из урока — в рабочем виде: вставьте свой текст.