"сани летом" или "почему именно сейчас - самый подходящий момент для добавления key pinning на сайт"

Очередной пост в рубрику "на заметку домохозяйке". Для начала - небольшая преамбула, состоящая из нескольких утверждений:

  1. Правительство нашей замечательной страны подумывает о создании государственного удостоверяющего центра, в простонародии известного как CA.
  2. В декабре прошлого года стал общедоступен сервис Let`s Encrypt, позволяющий любому владельцу домена бесплатно получить валидный SSL-сертификат.
  3. В данный момент HPKP (RFC 7469) поддерживается обоими наиболее распространёнными в интернетах браузерами - хромом и фаерфоксом, остальные на подходе.

Переводя на церковно-славянский - происходит ровно следующее: некоторое время назад осознав, что производительность зомбирования через традиционные для ОПГ "Озеро" каналы (телевидение, радио, газеты) достигла своего потолка и пошла на спад, а весь этот ваш интернет дружно ржёт над нескладными речами говорящих голов из новостей, попутно козля их на чём свет стоит и генерируя терабайты фотожаб, причём анонимно и без смс, неким светлым головам пришла гениальная мысль вступить своими грязными копытами на просторы рунета и навести порядок, всячески недопущая и пресекая, превратив и этот последний уголок свободы слова и обмена мнениями в ту же постапокалиптическую радиоактивную пустыню, коей сейчас является остальное информационное пространство России.

Не будем сейчас озвучивать всю летопись борьбы, закрытия и смены владельцев всех нормальных СМИ, зверства Роскомнадзора и прочие радости последних лет, остановимся только на широко известном феномене, который является, наверное, самой большой занозой в заднице "недопущателей" - широком распространении в интернете различных форм шифрования, опять же, опуская в рамках данного повествования различные VPN-туннели, Tor, i2p и прочие PGP, сосредоточившись на наиболее распространённом виде, используемом повсеместно - HTTPS.

Как всем известно - HTTPS представляет собой механизм транспортного уровня, позволяющий обычным нешифрованным данным протокола HTTP передаваться внутри SSL/TLS. В прикладном смысле - это не даёт возможности прочитать содержание вашего трафика, даже будучи способным перехватить его где-то на пути между вами и сервером назначения (как обычно и происходит на железках всяких СОРМ`ов). Для шифрования и последующей расшифровки передаваемых данных необходимы два ключа - публичный (он же открытый) и приватный. Первый общедоступен и является частью SSL-сертификата сервера, второй - располагается на веб-сервере и не должен быть известен никому, кроме владельца. Для того, чтобы клиенту подтвердить валидность отдаваемого сервером сертификата, используется так называемая "цепочка доверия", которая представляет собой подпись сертификата веб-сервера одним из доверенных центров сертификации (тем самым CA), коих довольно немного и чьи сертификаты обычно уже находятся в хранилищах браузеров или ОС у пользователей.

Вот мы и подошли к самому интересному. следите за руками - в данный момент все центры сертификации находятся за рубежом и неподконтрольны правительству нашей прекрасной страны, поэтому выпустить валидный сертификат для интересующих их сайтов они не могут. Зачем выпускать такие сертификаты? Ответ очевиден - чтобы мочь организовать расшифровку любого HTTPS-трафика, поскольку сормовское оборудование, поставленное у провайдеров вразрыв или на которое зеркалируется трафик - классический пример атаки MitM и пока что наступлению оруэлловского 1984 года препятствует только невозможность незаметной подмены SSL-сертификатов.

В этот момент мы незаметно подошли к разгадке того факта, зачем же "светлым головам" понадобился карманный центр сертификации за миллионы вечнозелёных долларов (не будем обращать внимания на их неубедительные отговорки). Всё просто - добившись добавления своего сертификата в хранилища браузеров и операционных систем, у товарищей непущателей появится возможность в любой момент завернуть трафик любого интересующего их человека через свои железки, подсунуть последнему свой сертификат под видом настоящего, а самим спокойно сидеть и разглядывать его пароли и письма в реальном времени. Хочу добавить, что подобное уже происходило с одним из китайских CA, который выпустил сертификаты для гугловских доменов, после чего был дисквалифицирован. Уверен, что наши не наступят на эти грабли и будут использовать свои возможности точечно, для конкретных целей, поэтому и поймать за руку их будет значительно сложнее.

Итого - если российский CA всё-таки будет введён в эксплуатацию и к этому моменту никто не расчехлит долгожданную табакерку, одно лишь наличие HTTPS-соединения с ресурсом, имеющим валидный сертификат перестанет быть гарантом безопасности передаваемых данных.

Цитируя классика - кто виноват и что же делать? Первый вопрос очевиден, сосредоточимся на втором. Немного забегая вперёд, обрадую аудиторию - выход есть и довольно безболезненный (без регистрации и смс!). Для восстановления вселенской справедливости нам понадобятся две составляющих успеха:

  1. Валидный SSL-сертификат для нашего домена, выданный любым неангажированным с ОПГ "Озеро" центром сертификации.
  2. Настроенный на веб-сервере key pinning.

Поскольку мы, как приверженцы открытости и прозрачности во всём, предпочитаем опенсорс и бесплатность, сертификат будем получать у Let`s Encrypt, чем убьём сразу двух зайцев - это бесплатно и может быть легко автоматизировано. Процесс неплохо задокументирован на соответствующем сайте, в этом посте данную тему рассусоливать не будем, возможно когда-нибудь потом.

Относительно key pinning`а, он же HPKP, он же RFC 7469 - это гениальный по своей простоте механизм, заключающийся в следующем: веб-сервер при обращении к нему клиента отправляет в ответе специальные заголовки, унутре которых находятся публичные ключи сертификатов (на самом деле не сами ключи, а их хэшированные подписи) и максимальный срок их действия. Клиент, получив эти подписи, сохраняет их, и в дальнейшем при подключении к данному домену по HTTPS, сравнивает подпись полученного SSL-сертификата с той, из заголовка, а при несовпадении начинаются кровь, кишки, расчленёнка, выражающиеся в отказе от подключения и соответствующем сообщении в браузере, а также (и это меня радует больше всего) опционально - в оповещении владельца домена о попытке подмены с приаттаченными сертификатами плохишей. Таким образом, заблаговременно установив себе HPKP, мы получаем возможность палить контору и сохранять тайну переписки, как и записно в Конституции нашей замечательной страны.

Разумеется, существует нюанс. Нюанс проистекает непосредственно из принципа работы HPKP - если вдруг у вас по какой-то причине изменится подпись сертификата, сайт превратится в тыкву. Простейшим случаем такого поведения является плановый перевыпуск SSL-сертификата домена. Именно поэтому весь интернет рекомендует использовать для формирования подписи ключ не конечного сертификата, а одного из промежуточных (intermediate CA) сертификатов удостоверяющего центра. Более того, в RFC чёрным по белому написано, что использоваться должны хотя бы две подписи - основная, работающая с текущим сертификатом, и резервная, для другого сертификата - это может быть, например, подпись ключа другого CA. Ещё более секьюрным и потенциально отказоустойчивым является альтернативный вариант аж с тремя подписями, первая из которых - так же рабочая, а остальные две - подписи публичных ключей двух других ваших сертификатов, ещё не подписанных никакими CA; при необходимости вы берёте один из двух запасных сертификатов и как обычно делается - подписываете его в любом CA, которому доверяете, а поскольку для HPKP используется подпись публичного ключа, а не самого сертификата - изменения сертификата при подписи в CA ничего не поломают.

В завершение - минутка технических подробностей, как всё это вообще провернуть (только основное):

  1. Берём OpenSSL, наш сертификат (или не наш, а intermediate) и вынимаем из него публичный ключ, формируя его sha256-подпись, закодированную в base64:
    openssl x509 -noout -in certificate.pem -pubkey | openssl asn1parse -noout -inform pem -out public.key
    openssl dgst -sha256 -binary public.key | openssl enc -base64 > public.key.digest
    На выходе получается нечто подобное:
    klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=
  2. Повторяем то же самое для резервных сертификатов.
  3. Добавляем в конфиг веб-сервера соответствующего домена заголовки Public-Key-Pins, установив max-age, не превышающий периода, оставшегося до "протухания" вашего текущего сертификата.
  4. Желающие получать уведомления о происках кровавой гэбни могут также указать в параметре report-uri URL, в который будут прилетать оповещения о безобразиях в формате JSON:
    {
        "date-time": "2014-12-26T11:52:10Z",
        "hostname": "www.example.org",
        "port": 443,
        "effective-expiration-date": "2014-12-31T12:59:59",
        "include-subdomains": true,
        "served-certificate-chain": [
            "-----BEGINCERTIFICATE-----\nMIIAuyg[...]tqU0CkVDNx\n-----ENDCERTIFICATE-----"
        ],
        "validated-certificate-chain": [
            "-----BEGINCERTIFICATE-----\nEBDCCygAwIBA[...]PX4WecNx\n-----ENDCERTIFICATE-----"
        ],
        "known-pins": [
            "pin-sha256=\"dUezRu9zOECb901Md727xWltNsj0e6qzGk\"",
            "pin-sha256=\"E9CqVKB9+xZ9INDbd+2eRQozqbQ2yXLYc\""
        ]
    }
  5. Желающие получать только уведомления, без расчленёнки и криков, могут использовать вместо Public-Key-Pins заголовок Public-Key-Pins-Report-Only.

Как-то вот так, всех благодарю за внимание.