Некоторые аспекты разработки платежных систем. Часть I. Трехзвенка без трехзвенки

    Мир тебе, %username%!


    В этой серии постов я хочу рассказать о некоторых аспектах реализации платежной системы(а если повезет и двух), реально имевшей честь работать с середины 2000х в одном из городов нашей необъятной родины.
    Что вообще такое ПС, и по каким принципам она должна работать? Я, как и заказчик, имел об этом представление лишь как пользователь WebMoney и платежных терминалов. Тем не менее, желание+деньги сделали своё дело и разработка началась.

    Для начала, что вообще понималось под платежной системой и с чего началась разработка.
    UPD:
    Вторая часть!

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

    Веб сервер представлял из себя FreeBSD с Apache, БД сервер на Windows с MySQL.
    К сожалению Postgre в то время был (да и остается) для меня дремучим лесом, а к MS SQL Server мы напрямую из под FreeBSD подключаться не умели. К тому же планировалось написание внешнего модуля для СУБД, отвечающего за часть с криптографией, что поставило точку в выборе ОС для неё.

    Ключевыми вопросами для меня при разработке были вопросы безопасности, т.к. работала система с какими никакими, а все таки деньгами.
    Почти сразу родилась следующая простая схема работы WEB server<->DB server:
    • Web сервер имеет доступ лишь к разрешенным хранимым процедурам в одной отдельно взятой базе. Никаких SELECT\INSERT\DELETE. Лишь вызов нескольких хранимок и всё.
    • Все доступные web серверу хранимки, кроме Auth(login, pass), принимают в качестве первого параметра ID сессии (и первым делом проверяют её живучесть), которая возвращается в Auth как hash(random()) и живет лишь несколько минут после неактивности.


    Таким образом
    • Мы на 100% защитились от SQL inject
    • На 99% защитились от злоумышленника в случае полной компрометации web сервера (1% оставим на дыры в MySQL и фаерволе). Можно делать для аккаунта веб сервера логин\пароль на БД web/qwerty и спать спокойно. Хакер неудачник будет видеть лишь пустые результаты выполнения хранимок
    • Вся логика системы реализована в хранимках, по сути web сервер лишь вызывает их и показывает оформленный результат пользователю.

    Со стороны юзера трафик защищался SSLем с купленным у VeriSign сертификатом.

    В первом приближении получилась безопасная «трехзвенка» без «трехзвенки», которой было довольно удобно рулить и которая отвечала неплохим, на мой взгляд, критериям безопасности. Проблемы были лишь когда добавлялась новая хранимка и я по запарке забывал выставить для неё права аккаунту веб сервера )

    Предстояло продумать структуру бд(неинтересно) и систему защиты виртуальных кошельков.

    Если хабрасообществу будет интересно, в следующих частях я расскажу о:
    • Защите клиента, в частности о системе ЭЦП с использованием эллиптических кривых и прикручиванием всего этого чуда к MySQL.
    • Прообразе «фермы платежных модулей».
    • Разработке с нуля платежной системы для терминалов самообслуживания.

    Средняя зарплата в IT

    120 000 ₽/мес.
    Средняя зарплата по всем IT-специализациям на основании 6 371 анкеты, за 1-ое пол. 2021 года Узнать свою зарплату
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

    Комментарии 36

      0
      компрометация веб-сервера — комплект паролей пользователей у злоумышленника.
        0
        Имхо «комплект паролей пользователей у злоумышленника» это как раз таки компрометация БД, но в виду того, что часто L\p от базы лежат в каком нибудь config.php залезть в неё не представляет сложности. Мой подход избавлен от этой проблемы, можно хоть рута от веб сервера раздавать.
          +1
          Я имею в виду man-in-the-middle.
            +1
            Именно. Скомпроментировали веб-сервер, поставили трейсер, получили все данные.
            +2
            А дадите рута от вебсервера? Взглянуть :)
            0
            Обсуждение взлома. Топик гадкий, но интересный.
            habrahabr.ru/blogs/pay_sistem/96438/#comment_2953781
              0
              точнее обсуждение как я лажанулся :-)
              топик глупый, но смешной.
            +2
            очень жду продолжения, особенно интересна тема безопасности со стороны клиента, идентификация пользователей, OTP, TAN
              +1
              Web сервер имеет доступ лишь к разрешенным хранимым процедурам в одной отдельно взятой базе. Никаких SELECT\INSERT\DELETE. Лишь вызов нескольких хранимок и всё.

              Бизнес логика в базе данных — это зло! Лучше использовать свой процессинговый сервис… Вот тут интересный перевод…
                0
                в 2007м году я и слов то таких не знал
                  0
                  Учитывая критичность данных, при выборе между «бизнес-логика на сайте» и «бизнес-логика в БД» первый вариант — еще большее зло
                    0
                    Никто и не говорит о бизнес логике на сайте… Сайт, это слой представления, он должен быть легким, быстрым, асинхронным. Будет интересно почитать, как они пускали платежные системы напрямую к БД… Или как они потом всё это масштабировали…
                  +1
                  если
                  >… каких либо существенных нагрузок не планировалось…
                  то вот это не понятно:
                  >Веб сервер представлял из себя FreeBSD с Apache, БД сервер на Windows с MySQL…

                  почему бы не поставить MySQL на FreeBSD рядышком с Apache?
                    0
                    Лучше рядышком, но не там же. Но тоже на фре.
                      0
                      Рядом нельзя, т.к. если сервер поимеют то досвидос. На фре нельзя, т.к. писалась внешняя хранимка на С, а я кодить под никсы на перле умею маленько. По поводу того что было в хранимке:
                      Вторая часть
                        0
                        Я это и имею в виду = Рядышком, но не там же.
                    0
                    А вообще, конечно, вы изобрели велосипед. Потому как использование хранимых процедур вместо update/select/delete — это типовое решение в случае двухзвенных систем.
                      0
                      Ух, интересно!!!
                        +5
                        Писал аналогичную платёжную систему. Тоже использовал минимум кода на веб-сервере и всю логику реализовывал в базе данных. Поначалу всё было очень логично и аккуратно. Со временем вылезли следующие проблемы:
                        — код всех этих хранимых процедур очень неудобно хранить в системе контроля версий (есть костыли вроде autobase, но они здорово усложняют разработку)
                        — взаимодействие кучи хранимых процедур приводило к трудноотлавливаемым багам и дедлокам (на mssql2005)
                        — код бизнес-логики на tsql ужасен. Ну не предназначен sql для императивного программирования — костыли на каждом шагу
                        — всё это усугублялось парой неудачных решений в структуре таблиц, которые невозможно было исправить из-за множества зависимостей в процедурах. Всё было бы гораздо проще при использовании orm-прослойки.
                        Больше никогда так не буду делать!)
                        Если хочется безопасности — лучше использовать отдельные сервера для сайта и для системных api.
                          –1
                          код всех этих хранимых процедур очень неудобно хранить в системе контроля версий
                          Перефразирую: «Текстовые файлы очень неудобно хранить в системе контроля версий».

                          взаимодействие кучи хранимых процедур приводило к трудноотлавливаемым багам
                          Перефразирую: «Взаимодействие кучи кривонаписанного кода приводило к трудноотлавливаемым багам».

                          не предназначен sql для императивного программирования
                          Перефразирую: «Отсутствие возможности поООПить — ужасно».

                          проще при использовании orm-прослойки
                          Перефразирую: «Мне пофиг на производительность, ACID и прочую фигню. Да и с SQL у меня плохо».

                          Больше никогда так не буду делать

                          А вот теперь фраза от меня: и слава святым!
                            +2
                            Взаимодействие кучи кривонаписанного кода приводило к трудноотлавливаемым багам
                            А, да, я и забыл, что тру-программисты сразу пишут идеальный код, правят чужие баги по скриншоту и уже забыли, что такое дебаггер) Ничего, я тоже когда-нибудь выучусь!

                            Отсутствие возможности поООПить — ужасно
                            ООП? А что это? Я чего-то читал про разные автомобили и всяких млекопитающих, но так и не понял. Мне просто не нравится sql в императивном стиле, глаза об него ломаются, боюсь инвалидом стать)

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

                            Мне пофиг на производительность, ACID и прочую фигню. Да и с SQL у меня плохо
                            Вы, наверно, не знаете, что кроме hibernate есть много других orm, не столь тормозных и без костылей в виде hql. Да, если не секрет, каким боком orm может нарушить acid принципы в субд?

                            Я так понимаю, у вас есть положительный пример использования бизнес-логики в базе данных. Поделитесь, если не трудно, а то у меня пока что только отрицательные.
                              0
                              тру-программисты сразу пишут идеальный код
                              Да нет, я всего лишь к тому, что кривой код можно написать на чем угодно. И более того — большинство кривого кода написано не на языках хранимых процедур СУБД.

                              их трудно хранить в текстовых файлах
                              Чем?

                              кроме hibernate есть много других orm, не столь тормозных и без костылей
                              ORM без костылей — это нонсенс просто из определения ORM. Просто потому, что маппинг множеств и отношений между множествами в объекты влечет кучу проблем. Всегда. Могу предложить ссылку на классику на эту тему.

                              каким боком orm может нарушить acid принципы в субд
                              Ну, конечно, ОРМ обеспечивает все буковки аббревиатуры гораздо лучше, чем сама СУБД.

                              у вас есть положительный пример использования бизнес-логики в базе данных
                              За последние четыре года я сделал как минимум три крупных проекта Мэйл.Ру, используя логику приложения в СУБД. В разных СУБД, надо сказать. И везде это было оправданно. И везде работает. Нагрузки — от сотен хитов в секунду до десятков тысяч.
                                0
                                Да нет, я всего лишь к тому, что кривой код можно написать на чем угодно
                                А, тогда ладно, а то я уж было подумал, что вы наш код заочно кривым обозвали =)

                                их трудно хранить в текстовых файлах
                                Чем?
                                Пример: заказчик захотел добавить новое поле к учётке пользователя. Нужно добавить поле в таблицу, новый параметр в пару процедур и слегка переделать триггер. Составить скрипт миграции — проще некуда (alter table, alter proc ...). Однако, добавив этот скрипт в систему контроля версий, мы не получим ясной истории изменений (старые файлы не изменились, лишь добавился один новый). Определение объектов базы будет «размазано» по нескольким файлам. Фактически, после нескольких доработок, весь код базы данных оказывается случайным образом распределён по нескольким скриптам. Если пойти другим путём и всегда хранить определение объекта в одном файле, то придётся как-то определять порядок выполнения скриптов.

                                Просто потому, что маппинг множеств и отношений между множествами в объекты влечет кучу проблем.

                                Да, это так. Но если в вашем приложении используется ООП, то без орм не обойтись по определению. Я не буду спорить насчёт обоснованности применения ООП как такового — очень холиварная тема.

                                Ну, конечно, ОРМ обеспечивает все буковки аббревиатуры гораздо лучше, чем сама СУБД.
                                Атомарность, изоляция и долговечность обеспечиваются субд в пределах одной транзакции. Все ОРМ умеют нормально работать с транзакциями. Согласованность можно обеспечить централизованным кэшем, или вобще отключить кэширование вне транзакций. Я в чём-то не прав?

                                По-моему спор становится немного бессмысленным. У вас есть положительный опыт, у меня отрицательный. Сейчас мне гораздо приятнее работать с обычными трехзвенными системами (особенно когда заказчик слабо представляет, чего хочет).
                                  0
                                  Пример: заказчик захотел добавить новое поле к учётке пользователя
                                  Так если изменения постоянны, то скрипты миграции можно не заносить в релизную ветку. Можно же просто сохранить новую схему таблиц и зафиксировать в документации, что после такой-то ревизии код несовместим с предыдущими релизами.

                                  В общем, опять же — у меня хватает примеров хранения sql-кода в репозитории, когда заносятся или пакеты (если СУБД их поддерживает), или функции, сгруппированные в файлы на подобие пакетов (если СУБД не поддерживает пакеты).

                                  Я в чём-то не прав?
                                  При желании, можно извратиться как угодно. Вам самому не кажется странным, что вместо одной сущности — СУБД — у вас добавляется еще две: кэш и орм? Как же принцип K.I.S.S? =) Ну да ладно.

                                  Продолжение спора, в общем-то, непринципиально, ага.
                          0
                          Обязательно пишите! Именно такая задача сейчас стоит у меня и ждет своего часа, как раз на стадии анализа.
                          +3
                          Дык это ж известная практика. Поселить код бизнес-логики в сервер БД.
                          Минусов тут несколько, и они очень жирные:
                          1. Как правило, ущербность языков хранимых процедур. Например, мы делали похожее на FireBird — а там хоть ты тресни, нет массивов. И в таком духе ограничения.
                          2. Жесткий вендор лок на одну базу без каких-либо шансов миграции.

                          В 2010 г. все-таки более логичной видится настоящая трехзвенка, с транспортом по HTTP (вебсервис), и кодом, который бы обобщил в себе работу с разными серверами БД. Плюсы очевидны. Основное — это возможность реализации не на птичьем языке :)
                            0
                            На тот момент это был весь арсенал моих знаний. Что такое веб сервисы я узнал только через год, но это была уже совсем другая система )
                              0
                              1. В платежной системе массивы не нужны.
                              2. Нормально спроектированная система в миграции не нуждается.
                              3. ОРМ — говно.
                                0
                                И переменные там тоже нафиг не нужны! Даёшь истинно функциональный sql с лямбдами и монадами!
                                Нормально спроектированная система не нуждается не только в миграции, но и в отладке, тестировании и внедрении. Она решает все проблемы юзера ещё в виде диаграмм.
                                Да при чём тут orm? Это всего лишь симтом. Вся идея ООП — полный отстой.
                                  0
                                  Вы чересчур категоричны.
                                  Я могу аргументировать каждое свое предложение.
                                  А Вы?

                                  Переменные — нужны.
                                  Более того, переменные в большинстве известных мне языков программирования СУБД есть.
                                  Массивы не везде, но не для всех проектов и нужны.
                                  Приведите пример, пожалуйста, для чего нужны массивы в бизнес-логике платежной системы?

                                    0
                                    Не, я не могу, это был сарказм. Просто у вас второй и третий пункты тоже очень категоричны.
                                    Про массивы — ладно, в реляционной модели данных всегда можно без них обойтись.
                                    Про остальное отвечу выше.
                                      0
                                      Просто у вас второй и третий пункты тоже очень категоричны.
                                      Эт все из опыта. Я неоднократно видел проблемы, которых можно было бы избежать, потратив какое-то разумное время на проектирование. Точно так же, как не видел ни одного использования ОРМа в более-менее серьезном проекте, где в итоге не пришли бы к прямому выполнению SQL-запросов или не вносили бы изменений в архитектуру исключительно, чтобы исправить проблемы ОРМа.
                                        0
                                        где в итоге не пришли бы к прямому выполнению SQL-запросов
                                        Вот, мне чем не нравится hibernate, так это тем, что он скрывает синтаксис sql. В паре мелких проектовал использовал iBatis — очень понравилось. Там всё основано именно на sql — есть средства для динамической генерации, разных комбинациях запросов, ОРМ не лезет дальше отображения строк в объекты. Конечно, там тоже проблем хватает, и 3-beta, которую я в последний раз использовал была весьма глючной, но надеюсь, что её доведут до ума. Сам пока что эксперементирую с no-sql базами.
                              0
                              «дремучий лес» называется PostgreSQL или, иногда, Postrgres. Реализация бы, кстати, могла быть более эффективной.
                                0
                                Да интересно. пиши дальше!

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

                                Самое читаемое