Самой обсуждаемой новостью текущей недели в рунете, безусловно, является принятие закона №139-ФЗ и его последствий. В силу того, что наша компания предоставляет услуги хостинга, нам понадобился доступ к полной базе реестра, чтобы своевременно реагировать на добавление ресурсов наших клиентов в базу. Это связанно с тем, что нам необходимо информировать клиентов о блокировке их ресурсов, ведь в случае, например, блокировки по ip сервера веб-хостинга, могут пострадать и остальные, ни в чем не виноватые, клиенты. К сожалению, получение такого доступа оказалось делом не самым очевидным, поэтому мы хотели бы поделиться результатом прохождения данного квеста.
В статье мы бы хотели сфокусироваться на техническом аспекте и избежать обсуждения этическо-политической стороны вопроса, т.к. любой активный пользователь уже успел высказать свое недовольство по данной теме, пожалеть рутрекер с луркоморьем и подумать на тему обхода запрета ресурсов ранее.
В настоящий момент доступ к единому реестру запрещенных ресурсов предполагается двух видов:
Для всех пользователей интернета в виде формы поиска на главной странице реестра. Каждый запрос требует ввода капчи, кроме того, форма, по сути, решает задачу получения информации о блокировке конкретного ресурса, известного заранее, т.к. если сайт забанен по url, то ввод в форму имени домена не даст никакого результата. Пример: ww.xapka.com — пусто, http://www.xapka.com/ — информация о блокировке.
Во втором случае каждый запрос на выгрузку базы необходимо подписывать ЭЦП, в формате PKCS#7 и передавать отвязанную подпись вместе с запросом. В идеале мы представляли себе примерно такой порядок действий: покупаем ЭЦП, берем привычный нам Debian, ставим туда соответствующее ПО для автоматической подписи запросов, пишем скрипт, который общаясь с сервером zapret-info через SOAP формирует запрос, подписывает его, скачивает дамп и рядом эвристических методов проверяет, не относятся ли к нам какие-либо ресурсы из списка.
Казалось бы, все просто, но на деле оказалось несколько сложней и дольше.
ЭЦП
Сервер zapret-info не предоставляет никакой «песочницы», в которой можно было бы протестировать работу скрипта без наличия валидной ЭЦП, поэтому самым первым делом надо озаботиться ее приобритением.
Купить сертификат для создания квалифицированной электронной подписи можно в доверенном удостоверяющем центре. По умолчанию все УЦ для подписывания документов предлагают пользоваться программами из семейства КриптоПРО (КриптоАРМ, cryptcp). К сожалению, пользование этим многообразием программных продуктов омрачает несколько фактов:
Если в состав комплекта ЭЦП входит лицензия КриптоПРО — то скорее всего, она предназначена для Windows.
Сама КриптоПРО ничего не умеет подписывать, а инструменты, которые умеют — требуют отдельной лицензии и покупки.
Возникают еще вопросы про лицензирование (то ли нам нужна лицензия на 1 рабочее место, то ли на 1 сервер).
Поэтому быстрый поиск в интернете навел нас на информацию о том, что с помощью несложных действий с Рутокеном можно научить работать привычный нам OpenSSL. Краткий бриф наших действий такой:
Экспортировать ключ в формате PKCS#12 из криптоконтейнера в Windows с помощью утилиты P12FromGostCSP
Преобразовать его в PEM
Прописать в конфиге openssl.conf параметры
В самом начале, до секций:
и проверить его через форму на госуслугах (раздел «отсоединенная, в формате PKCS#7»). Если подпись проходит проверку — можно двигаться дальше.
Формируем запрос
Тут тоже оказалось не все так гладко, как хотелось бы. Все дело в том, что на любую проблему выдается малоинформативное вида: «Ошибка! Файл запроса не соответствует требуемому формату». Но методом проб и ошибок были выяснены следующие требования к файлу запроса:
Важен точный порядок следования элементов XML-документа, как в примере.
Кодировка xml-документа исключительно windows-1251.
XML declaration string должен полностью соответствовать примеру (т.е. нельзя ни порядок аттрибутов менять, ни лишнего пробела между аттрибутами добавлять, ни двойные кавычки на одинарные поменять).
После формирования запроса подписываем его и получаем подпись. Дальше либо отправляем их через метод SOAP sendRequest(), изначально закодировав в base64 содержание файлов запроса и файла подписи, либо отправляем их через форму. Получаем идентификатор запроса, ждем около минуты и проверяем результат обработки запроса (метод getResult(), либо вторая форма на странице запроса).
Кстати, и тут у нас с первого раза не все прошло так гладко. На странице появилась еще одна надпись:
Ошибка! неверный формат ЭП (информация по обратной связи для разрешения проблем приведена в Памятке оператору связи в разделе www.zapret-info.gov.ru/tooperators/)
Тут уже наши догадки закончились и мы написали на почту поддержки: support@rsoc.ru, откуда через несколько часов пришел ответ, что в алгоритм проверки ЭЦП были внесены корректировки и нам нужно попробовать еще раз. Со второго раза проверка прошла успешно и нам был выдан zip-архив, в котором находились дамп реестра и его ЭЦП.
Автоматизация
После всех описанных действий, никаких проблем с автоматизацией у нас не возникло. Алгоритм работы примерно такой:
1. проверяем, не изменился ли таймстамп базы;
2. если изменился — формируем запрос, генерируем подпись, отправляем запрос;
3. периодически опрашиваем сервис на предмет готовности результата;
4. если результат есть — получаем архив дампа, разархивируем его и проверяем список ресурсов на принадлежность нашим клиентам.
Пара советов:
Для питона самой удобной реализацией SOAP-клиента оказался модуль suds
lxml.builder ставит одиночные в xml declaration string, поэтому у нас генерация xml запроса выглядит как-то так:
from datetime import datetime
from dateutil.tz import tzlocal
from lxml import etree
from lxml.builder import E
request_xml = E.request(
E.requestTime(datetime.now(tzlocal()).isoformat()),
E.operatorName(settings.NETANGELS_OPERATOR_NAME),
E.inn(settings.NETANGELS_INN),
E.ogrn(settings.NETANGELS_OGRN),
E.email(settings.NETANGELS_EMAIL),
)
# Роскомнадзор не умеют работать с одиночными кавычками и utf-8 :-(
request_str = etree.tostring(request_xml, xml_declaration=True, encoding='windows-1251').replace("'", '"')
Выводы
При словах linux в контексте вопроса: «Каким ПО мы можем подписать документ из скрипта?» все удостоверяющие центры впадают в ступор и предлагают ознакомиться с решениями для Windows :-)
Мониторинг реестра запрещенных ресурсов можно и нужно автоматизировать, если ваша деятельность связана с хостингом.
При запуске любых сервисов необходимо предоставлять разработчикам «песочницу», где можно проверить базовую интеграцию с ними.
Иногда задача связанная с работой с государственными структурами может заступориться в совершенно неожиданном месте.