В прошлом семестре в качестве домашнего задания по курсу информационной безопасности в Технопарке Mail.Ru нам предложили написать сервис одноразовых ссылок. Подобные сервисы уже существуют, однако мне эта идея показалась интересной как с точки зрения практического применения, так и с точки зрения технической реализации. Задание я выполнил, и, немного доработав систему, выложил в открытый доступ. О том, какие задачи мне пришлось решить и с какими проблемами столкнуться, я расскажу в этой небольшой статье.
О чём речь
Итак, secureshare.pw — сервис одноразовых ссылок, т.е. средство безопасной передачи конфиденциальных данных другому человеку. Суть в том, что секретные данные пользователя сохраняются в базе данных сервера, а пользователю даётся одноразовая ссылка, по которой доступны эти самые данные. Ссылка действительна только для одного (по умолчанию) просмотра, сразу после него данные уничтожаются. Можно не бояться того, что ссылка останется в истории сообщений вашего IM-сервера, в списке отправленных писем, в access-логах сервера, на скриншотах мониторов. К тому времени, когда злоумышленник доберётся до этой ссылки, она будет уже бессмысленна.
Первый подход
Базовый функционал системы очень прост. Всё, что нужно — сохранить данные из формы в базу данных и выдать юзеру ссылку, однозначно идентифицирующую эти данные. Например, добавить в get-параметр primary key. После показа данных выполнить элементарный DELETE-запрос, и готово. После первого подхода система в точности так и работала.
Но как-то это несерьёзно, не так ли?
Второй подход
Ну, давайте подумаем, что тут не так. Первое, что бросается в глаза — primary key прямо в get-параметрах запроса. То есть, если перебирать все числа по очереди, можно насобирать много чужих секретов. Решение достаточно очевидно — использовать вместо числа что-то большое и неподбираемое. Скажем, sha1-хеш (в md5 нашли коллизии и его уже не рекомендуется использовать). Отлично, добавляем в БД новое поле, делаем по нему UNIQUE индекс и генерируем его случайным образом для каждого нового пользовательского секретика. Уже лучше.
Третий подход
Данные в БД у нас хранятся в открытом виде. Нехорошо как-то, это же секрет. Если база утечёт, все наши секреты будут доступны злоумышленнику. Что делать? Не хранить данные в плейн-тексте! Давайте их зашифруем. Выберем стойкий симметричный блочный алгоритм шифрования, а при показе данных будем расшифровывать данные на лету, благо объём сообщений обычно невелик. Теперь, если база утечёт, злоумышленнику придётся ещё попотеть, чтобы достать нужные данные. Неплохо. Но есть серьезное «но». Часто всё-таки хакер либо не имеет вообще никакого доступа к системе, либо имеет полный. В том числе и к исходникам нашего сервиса, осуществляющего расшифровку, в том числе и к ключам шифрования, а тогда все данные у него будут как на ладони — расшифровать их можно будет «одной левой». Получается, что и в шифровании особенного смысла-то нет. Что делать?
Четвертый подход
Каждое пользовательское сообщение шифруется случайно сгенерированным ключом. После шифрования ключ делится на две половинки, одна из которых сохраняется в БД вместе с зашифрованными данными, а вторая половинка встраивается в ссылку, которая отдаётся клиенту. В итоге получается, что расшифровать данные можно будет, только имея обе половинки ключа. Таким образом, базу можно вообще выкладывать в открытый доступ и полностью раскрыть весь алгоритм работы системы — без второй половинки ключа, которая в ссылке у клиента, данные в базе — всего лишь куча мусора. Отлично!
Пятый и заключительный подход
Кажется, всё неплохо. Придумываем название, регистрируем подходящий домен. Им стал secureshare.pw.
Последняя деталь: негоже серьезные вещи по открытому HTTP-протоколу гонять. Нужен HTTPS. Первый шаг прост — не разрешаем пользоваться по HTTP и принудительно редиректим с 80 порта на 443, предварительно настроив на сервере HTTPS. Работает. Но в уголке горит ярко-красная надпись, говорящая о том, что подлинность домена не подтверждена, а Chrome выдаёт навевающий страх красный (в новой версии — жёлтый) экран с предупреждением.
Нехорошо. Надо, чтобы нашу личность подтвердил один из корневых центров сертификации. Пара запросов в поисковике — и находим массу предложений от самых разных компаний. Я выбрал GoDaddy — не слишком сложная процедура получения и адекватные деньги. Для стартапа подойдёт ;-)
В качестве финальных штрихов добавим пару приятных фич — количество показов, прежде чем ссылка удалится из базы (по умолчанию = 1), дата, по достижении которой ссылка самоуничтожится (кронскрипт каждый день), даже если не была просмотрена (по умолчанию неделя), а также подтверждение просмотра (защита от непреднамеренного просмотра и уничтожения данных).
Готово! В нашем распоряжении надёжный сервис, способный передавать вашим друзьям и коллегам только что сгенерированные пароли, паспортные данные и другую конфиденциальную информацию.
Ваши вопросы и предложения, как обычно, велкам. Спасибо за внимание!
Статья написана в рамках конкурса статей студентов проекта Технопарк Mail.Ru.
Автор: jphoenix