QIWI терминалы. Альтернативный путь

в 13:02, , рубрики: Delphi, интерфейсы, платежные системы, платежные терминалы, разработка

Говоря по правде, я никогда не имел дел с платежными терминалами от QIWI или с софтом для них. Видимо, так сложились звезды, что мое почти пятилетнее общение с платежными автоматами началось с неизвестной фирмочки подвального типа, где и были в 2006-м году приобретены пять «железных друзей» розового цвета. Тем не менее, видя как много вокруг именно QIWI-терминалов, думаю, что их владельцам будет интересно прочитать, как я создал свою собственную сеть, со своим терминальным софтом, процессингом и мониторингом, и, возможно, что-то взять себе на вооружение.

Знакомство

Возможно, для кого-то станет откровением, что 9 лет назад далеко не все автоматы обладали сенсорными экранами. Те, что приобрел я, были устроены примерно как экраны в банкоматах — обычный вандалостойкий экран, отдельный цифровой блок под экраном и два ряда по четыре кнопки слева и справа от экрана. В качестве софта работала программа momentalka.exe, к которой прилагался обширный мануал из 15 листов А4, выполненный в лучших традициях студенческих работ — 80% воды для объема, 20% полезной информации. К сожалению, программа эта была утеряна за давностью времен, и продемонстрировать ее интерфейс, убогий чуть менее, чем полностью, я не смогу. Если вкратце — это набор jpg-картинок, где были жестко захардкожены нарисованы возможные операторы, в программе же они были жестко захардкожены, и при желании поменять, добавить или убрать что-то самому меня ждало жестокое разочарование. К чести продавца скажу, что перед отгрузкой на главном экране были именно те операторы, которые мне были нужны.

В то время рынок платежных систем было значительно менее развит, и QIWI (а в те времена еще ОСМП) не была лидером, в основном народ использовал e-порт, впоследствии купленный QIWI. По сравнению с QIWI в е-порте было гораздо больше возможностей: три формата взаимодействия с сервером, возможность авторизации через пин-код или ЭЦП на выбор, работа через https.

Интернет в моих автоматах отсутствовал: 3G-модемов да и вообще сетей третьего поколения в то время в уездных городках типа моего не было, а покупать за 10% стоимости автомата GPRS-модем жаба задушила. Приобрел дешевые телефоны motorolla E350L, преимуществом которых было наличие USB-порта для связи и отдельного разъема для питания. Некоторые сложности с ними были, но в целом затея себя оправдала.

Первые проблемы

Они начались в первый же день работы. Как оказалось, протокол работы с купюроприемником был проработан крайне криво, и частенько возникала ситуация, когда купюроприемник отрапортовал хосту, что купюра негодная, но при этом ее успешно проглотил. Или не проглотил, а зажевал, но это, в общем-то, неважно: клиент свято верит, что его денежки вот-вот придут на телефон; я, как владелец, тоже на это рассчитываю, а в итоге мы имеем потерянный платеж и неучтенные деньги в стекере купюроприемника. Приходилось покупюрно сравнивать содержимое ящика с логами принятых купюр в программе и находить эти расхождения. Часто бывало, что разъяренные вкладчики сообщали нам о проблемах раньше, чем мы находили «левые купюры».

Второй неприятный момент был связан с полным отсутствием мониторинга. Т.е. узнать о том, что автомат все еще стоит на своем месте, не зажевал купюру, не завис и на нем не упал интернет можно было только косвенно — по периодически идущим платежам. В то же время, большой закономерности между пропавшими платежами и работоспособностью терминала не было, и часто я выезжал на точку, чтобы приехав, узнать, что с автоматом все в порядке.

Еще одним разочарованием стал интернет от бело-зеленого оператора. Вроде бы и самый дешевый, но порог тарификации в 100кб при цене за трафик в 6 р/мб выливался в 1000 рублей в месяц за интернет. В итоге на половине автоматов был проведен стационарный интернет, а на тех, где такой возможности не было — оператор был заменен, интернет формально стал дороже, но в реальности затраты на интернет упали до 100 р/месяц.

Первые доработки

Один из терминалов территориально был расположен в том же здании, где находился и мой офис, поэтому к нему была проложена витая пара, а сам терминал стал основным подопытным кроликом. Естественно, первой жертвой переработки стала родная программа от терминала. За небольшое время мы с приятелем исследовали через portmon протокол работы купюроприемника, напомню, это был 2006-й год, и информации в интернете нам найти не удалось. Тем не менее, все получилось, мы смогли успешно принимать купюры. Второй серьезной доработкой стало изменение работы с серверами e-порта, мы перешли на новый протокол 2-й версии и реализовали авторизацию по ЭЦП. В принципе, даже спустя 9 лет, я не уверен, что это было необходимо — перехватить исходящий из терминала ssl-пакет и вытащить из него пин-код вряд ли сильно легче, чем получить доступ к автомату и забрать оттуда ЭЦП, после чего слить весь остаток с балансе агента на какие-нибудь яндекс-деньги или веб-мани, но что сделано — то сделано.

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

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

image
после внесения денег, можно засунуть еще деньжат или оплатить

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

Также написал небольшую веб-мордочку в минималистичном стиле для отображения на экране мобильника (никаких скриптов, только минимум html) и программу для операторов, которые отвечали на звонки и направляли меня к нужному автомату в случае каких-то обстоятельств, требовавших моего присутствия там.

image
Программа для операторов. Задания в очереди печати означают, что кончилась бумага в принтере

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

Переход на сенсор

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

Программная часть к тому времени была переработана, а точнее разделена на два независимых модуля: один работал с интерфейсом, принимал купюры и печатал чеки, а второй отправлял все данные на сервер платежной системы и логи на мой сервер, а также служил watchdog-ом для интерфейсного модуля. Забегая вперед, скажу, что в дальнейшем был выделен в отдельный исполняемый файл еще и модуль печати чеков. На сенсор я перевел не все автоматы, а лишь ту часть, где, по моему мнению, это было оправдано, поэтому фоновый модуль остался один, а вот интерфейсные разделились на две ветки — для сенсорных экранов и обычных. С одной стороны, это несколько усложнило поддержку, ведь программ стало больше, с другой — за два года не-сенсорный интерфейс был вылизан до неприличия и больше я его фактически не трогал.

Хотя интерфейс для работы с сенсорными экранами позволил добавить некоторых провайдеров, которые до этого автомат принимать не мог физически, я решил ограничиться приемом платежей за сотовых операторов и местного интернет-провайдера, позднее добавив еще одного. Во-первых, наблюдая за поведением клиентов можно однозначно утверждать — чем меньше вариантов выбора, тем меньше потом проблем с тем, что этот самый выбор был сделан не верно. Во-вторых, у коллег, использующих софт ОСМП, периодически появлялись попытки незаконно вывести деньги в различные электронные кошельки, и я решил не заморачиваться. Картинки интерфейса ниже:

image
главный экран, уже приходится кое-что выбирать

image
в процессе платежа

image
успех!

Смена оператора платежной системы

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

Поэтому оставался единственный приемлимый вариант — оставить на терминалах свой софт и написать свой процессинг в качестве. Собственно, все логи со всех платежных терминалов к тому моменту уже отправлялись на мой сервер, так что я всего лишь добавил ЭЦП для безопасности и сделал небольшой парсинг логов, чтобы платежи отображались в отдельной таблице в той же БД, что использовалась до этого исключительно для логгирования. Остался только один вопрос: как проводить платежи из этой таблицы?

Свой процессинг, попытка номер один

Поскольку QIWI очень не нравилась идея давать мне использовать платежные шлюзы для бесконтрольного приема моих платежей, мне пришлось пойти на хитрость. Была установлена программа QIWI-кассир, представлявшая собой рабочее место оператора по принему платежей. На горячие клавиши были повешены нужные мне операторы, а моя программа-эмулятор изображала кипучую деятельность оператора: из базы данных, куда сливались логи с терминалов, выбиралась нужная информация по платежам и проводилась через QIWI-кассир. Программа эмулировала нажатие нужной горячей клавиши для выбора оператора, набирала реквизиты платежа и сумму и отправляла платеж в QIWI. Все это крутилось на виртуальной машине на том же сервере, куда сливались логи, так что дополнительных затрат я не понес. В целом, идея себя оправдала, разве что периодически приходилось посматривать, что QIWI-кассир не «совершил недопустимую операцию и будет закрыт», и столь же периодиочески перезапускать его, иногда даже пару раз в день. Впрочем, невысокая плата за возможность оставить свой софт на сети терминалов и полностью контролировать их деятельность.

Принтер

В то время (2010) на платежные автоматы начала пристально смотреть налоговая инспекция, ведь в большинстве случаев наличка из терминалов продавалась, и в рамках борьбы с обналичкой через платежные терминалы всех обязали использовать фискальные регистраторы. Конечно, поставить можно было их, технически сложностей особых не было — но даже если не брать разовый платеж в 3,5 месячных прибыли от автоматов, ежегодное обслуживание только ЭКЛЗ лишило бы еще десятой части прибыли.

В итоге было принято решение добавить в свой процессинг общение с единственным фискальником, стоящим в офисе, а автоматы на местах печатают дубликаты чеков. Признаюсь сразу, вторая часть этой эпической задачи не была реализована: дубликат чека печатался, но вместо ЭЦП, которую должен генерировать фискальный регистратор в офисе, на чеке был обычный random(65536). Как оказалось, фискальный регистратор, печатая чек, отображает «подпись», которая его удостоверяет, только на самом чеке, программно эту подпись мне получить не удалось. Была мысль вытащить ЭКЛЗ (электронная контрольная лента защищенная — блок, который собственно и хранит все чеки и генерирует подпись) и работать напрямую с ним — но с юридической точки зрения распотрошенный кассовый аппарат с «честной» ЭКЛЗ вряд ли лучше, чем такой же чек с неправильной подписью: налоговиками проверяется факт наличия фискальника в терминале, если есть — то все ок, если нету — штраф, а правильные ли там чеки или нет — никому не интересно.

Один фискальный регистратор я все же купил, в итоге модуль печати чеков стал поддерживать не только принтеры, но и фискальные регистраторы определенной модели, причем чеки печатались абсолютно идентичные (не считая кода ЭКЛЗ), поскольку сделан фискальник как раз на базе этого же принтера, в моем случае — Citizen CBM1000.

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

Процессинг, второй заход

Весной 2011 года этот бизнес я продал. Но в качестве бонуса решил сделать покупателю нормальный процессинг, чтобы ему не приходилось постоянно смотреть в радмин на то, как робот щелкает виртуальными кнопками в QIWI-кассире.

Начали с того, что решили посмотреть на общение кассира с сервером, благо в списке серверов можно было вручную указать используемые. Соответственно, все сервера, работающие через https были убраны, запущен wireshark и все стало предельно понятно: xml-запрос, содержащий данные платежа. Затруднений было два: некий «магический» параметр в запросе, не имевший отношения к платежу, и ЭЦП запроса. Первую проблему мы с товарищем решили довольно быстро — ollydbg, час времени — и алгоритм вычисления некоего кода, складывающего из даты, суммы и номера терминала, был готов. С ЭЦП пришлось повозиться: кассир использовал стандартные средства Windows CryptoAPI, ключ был сгенерирован неизвлекаемый, найти его в памяти и извлечь, если такое возможно в принципе, у нас скилла не хватило. Здесь нужно сделать небольшое отступление и рассказать, как происходит процесс генерации этого ключа. Для этого у QIWI есть еще одна программка — QIWI-защита. Она генерирует этот самый неизвлекаемый ключ, после чего QIWI-кассир его использует для подписи отправляемых запросов. Для генерации используется функция CryptGenKey, в одном из параметров которой задаются различные опции ключа. Мы пропатчили exe-файл, таким образом, чтобы установить флаг CRYPT_EXPORTABLE, позволяющий экспортировать закрытые ключи. После этого сгенерировали ключ и успешно его извлекли, хотя и не без приключений — в параметре функции CryptExportKey, отвечающем за пароль, поставили пустые кавычки вместо NULL и два дня не могли сконвертировать экспортированный ключ в нужный нам формат. Ну а когда баг был побежден — еще пару часов кодирования и php-скрипт, запускаемый из крона каждые тридцать секунд на отдельной линуксовой виртуалке, отправлял на сервер QIWI мои платежи.

Заключение

Еще через пару лет мои автоматы были еще раз перепроданы, уже большой сети, которая использовала софт QIWI и не стала заморачиваться с моим процессингом. Видимо, оказалось выгоднее вдвое поднять комиссию и платить процент от оборота банку, под вывеской которого они работали, чем что-то оптимизировать. А я выключил виртуалку с процессингом, остановил веб-сервер для сбора логов и еще одна моя разработка стала невостребованной.

Написать эту статью меня вдохновило творение Almazist, хотя наши подходы и отличаются в корне, но суть, по-моему, та же — установить свои правила для своих автоматов. Я не профессиональный программист, я не зарабатываю на жизнь написанием кода, поэтому мое развитие остановилось на Delphi 6, актуальном в годы моей учебы в институте, и свои исходники не выкладываю на всеобщее обозрение. Но если кому-то понадобится — готов поделиться, берите — не жалко. Надеюсь, было интересно.

Автор: electric13

Источник


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


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