ЭЦП в браузере: проблемы, решения, личный опыт

в 10:56, , рубрики: crypto, java, openssl, stunnel, web-разработка, гост, информационная безопасность, криптография, Песочница, плагины, электронная подпись, эцп, метки: , , , , , , , , , ,

ЭЦП в браузере: проблемы, решения, личный опыт

Те, кто хоть раз сталкивался с необходимостью реализовать электронную цифровую подпись в браузере, хорошо знают, какая это головная боль для разработчика, и особенно для веб-разработчика, который успел привыкнуть к открытым стандартам, правилу, что его ПО одинаково хорошо работает во всех браузерах и ему все равно, какая ось стоит у пользователя, ну и прочим прелестям веба.

На самом деле сегодня ситуация с ЭЦП в браузере все же не так печальна как еще несколько лет назад, но она все же далека от идеала. Тема эта также несколько раз поднималась на хабре, например, здесь и здесь.

Под катом рассказ о самой проблеме, о том, как эту проблему можно решить, о том, как я ее решал, а также личные впечатления о том, как обстоят дела с ЭЦП в Беларуси.

Суть проблемы и что с ней будет завтра

Проблема довольно тривиальна: хотите реализовать ЭЦП на клиенте в браузере, думаете использовать для этого свой любимый javascript? Ничего не выйдет, и все потому, что браузеры просто не предоставляют API для работы с сертификатами, токенами, подписью и тд. и тп… Как должен выглядить этот механизм в мечтах любого веб-разработчика? Наверное как-то так:

		//получить список сертификатов пользователя
		window.crypto.getCertificates(options);
		//подписать какую-то строку
		window.crypto.signText(text, options);
		ну и так далее...
		

Да, а еще было бы здорово, чтобы все это поддерживало отечественные ГОСТы… ну, это я уж совсем размечтался. К сожалению, ничего подобного в современных браузерах вы не найдете. Есть, конечно, робкие попытки реализовать что-то похожее у Mozilla, но предупреждение в заголовке статьи весьма печалит:

ЭЦП в браузере: проблемы, решения, личный опыт

Кстати, если кто-то пытался использовать этот API, отпишитесь, весьма интересно.
Также есть упоминание Crypto в репозитории W3C. Скорее всего работа там началась совсем не так давно, материала там сейчас немного, но последнее обновление было недавно, так что работа идет:

ЭЦП в браузере: проблемы, решения, личный опыт

Будет ли все это доведено до ума, а самое главное, когда это случится, сегодня вам, наверное, никто не скажет. Так что же остается делать разработчикам, которым надо здесь и сейчас?

Костыли

Хочу сразу оговориться, ЭЦП в браузере — это, пожалуй, один из немногих случаев когда разработчик просто вынужден использовать различные ухищрения и костыли, я перечислю наиболее популярные из них:

Давайте рассмотрим недостатки каждого из них, достоинства описывать не буду, имхо, у всех костылей оно одно — “ну, оно же работает”.

ActiveX

Используется в 99% случаев, когда необходимо реализовать ЭЦП в браузере, не стесняются его использовать банки, торговые площадки и прочие серьезные организации. На мой взгляд, сейчас это худший из вариантов, почему?
Вы привыкли использовать для работы свой любимый FF или Chrome? — Забудьте! ActiveX работает только в IE.
Не любите копаться в настройках браузереа? — А придется! Перед тем как все заработает, вам изрядно придется покопаться в настройках безопасности вашего IE.
А может быть вы такой продвинутый, что у вас стоит Win7, да еще и x64, а может вы еще и IE9-10 себе поставили? — Очень зря, скорее всего у вас ничего не получится.
Шутки шутками, а ведь Microsoft объявила, что поддержка CAPICOM прекращена и далее компонент разрабатываться не будет и последняя версия CAPICOM, которая официально поддерживается, была в Windows Vista.

Плагины к браузерам

Если чего-то нет в браузере, но оно вам очень нужно, выход есть — напишите свой плагин. Основная проблема здесь в том, что если вы хотите, чтобы это работало во всех браузерах, вам придется написать плагин под каждый из них. Есть еще проблема с поддержкой — никто не гарантирует, что ваш плагин будет работать в новой версией браузера (или старой), вспомните ситуацию с FF, когда Mozilla перешла на ускоренный выпуск версий. Ну и еще проблема с тем, что вам этот плагин как минимум придется поставить. Подробнее об этом решении можно найти здесь.

Java applet

Все вроде бы не так уж плохо, и код написан один раз, и работает во всех браузерах, и даже настраивать ничего не надо. Но если у вас не установлена JRE, ничего не будет. Чаще всего работает в связке с OpenSSL, хотя, используя JNI, можно много чего прикрутить. Да, чтобы все работало, сам апплет должен быть подписан.

Туннель

Относительно новый способ, работает по принципу прокси, основная идея в том, что особым образом сформированный POST-запрос при отправке на сервер проходит через туннель, тот подписывает данные из этого запроса, подставляет подписанные данные в поле запроса вместо данных и все отправляется дальше на сервер и туда уже приходят данные с ЭЦП. Принцип довольно простой, но эффективный. У этого способа имеется практическая реализация. Подробнее можно почитать здесь. Чтобы все это работало, на клиенте собственно должен быть установлен этот туннель, хотя можно запустить и с флешки.

Как видите, решения есть, хотя каждое из них имеет определенные ограничения и оговорки, я намеренно не касался таких проблем как работа в различных операционных системах, поддержка ГОСТов, работа на мобильных платформах — здесь проблем еще больше, а ведь это тоже очень важно.

Личный опыт

Да, мне тоже “повезло” заниматься реализацией ЭЦП в браузере. Сам я работаю в одной минской компании, занимающейся биржевой торговлей, и однажды потребовалось срочно реализовать поддержку ЭЦП в браузере в одной из торговых систем. Скажу честно, сначала хотел поступить как и 99% в такой ситуации и задействовать ActiveX. Но, постепенно погружаясь в проблему, стал осознавать, что это обернется сначала головной болью для пользователей, а затем и для меня как разработчика. Писать плагины под каждый браузер не было времени. Оставалось два решения: java апплет и туннель. Решающим здесь оказался… вы не поверите, ГОСТ.

Дело в том, что в Беларуси как и в России принят свой ГОСТ на процедуры выработки и проверки электронной цифровой подписи, только у нас он называется СТБ РБ 1176.2–99 и никаких вам RSA. Даешь свой ГОСТ каждой стране! И если для российского ГОСТа есть практические реализации каждого из вышеперечисленных способов, можно выбирать любой, то белорусским разработчикам повезло куда меньше. По этому поводу даже лично беседовал c представителями компании, выпускающей криптографическое ПО для нашей страны. Разговор оставил двоякое впечатление. Народ вполне адекватный, проблему понимают, но говорят, что это не их задача, они, мол, написали криптопровайдер, удовтлеторяющий всем ГОСТам и прошедший государственную экспертизу, а как вы его собираетесь использовать, это не их проблема.

— Можем лишь предложить вам использовать ActiveX.
— Ну, а как же, проблемы связанные с ним?
— У нас, конечно, есть определенные наработки с использованием java апплетов, но в качестве продукта мы вам их пока предложить не можем. Разработка такого рода ПО — не наша задача.

На мой взгляд, это не совсем верная позиция, ведь предлагая продукт, коммерчески выгодно предложить и окружение к нему.

Ну да ладно, работаем с тем, что есть. А что у нас есть? Ранее в нашей компании уже было написано desktop-ое приложение, использующее функции ЭЦП, и там имелся компонент, работающий непосредственно с CryptoAPI, написан он был на delphi. Очень уж хотелось как-то использовать этот опыт коллег и самому не тратить на это время, а самое главное сделать это быстро. Но как это сделать? Соединить компонент на delphi и веб-приложение? Ответ на схеме:

ЭЦП в браузере: проблемы, решения, личный опыт

Кратко поясню, что происходит. Когда нам нужно что-то подписать, мы с помощью javascript вызываем функцию java апплета:

	document.CryptoAPI.sign(text); 
	

Апплет в свою очередь через сокеты связывается с desktop-приложением, передает ему необходимые параметры, приложение подписывает то, что мы запросили (для этого как раз используется ранее написанный компонент коллег), и передает подписанные данные апплету, а тот в свою очередь браузеру, вызывая функцию:

	function signResult(params) {
		//что-то делаем с подписанными данными
	}
	

Для общения апплета и приложения был придуман и реализован простой протокол, на это, наверное, ушла большая часть времени, так как остальное оказалось довольно простым. Недостатки здесь типичные: наличие JRE и desktop-приложения, которое будет либо установлено, либо откуда-то запущено. Интересно будет услышать ваши комментарии относительно данного способа.

Надеюсь, что вышеизложенная информация поможет лучше разобраться с проблемой ЭЦП в браузере тем, кто с ней столкнулся.

Автор: SergeiStartsev


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js