Типичные ошибки API платежных систем

    imageЕсли вы собираетесь написать n-ную платежную систему, рекомендую ознакомиться с типичными ошибками в реализации API, которые я собрал в процессе написания модулей для своего проекта.



    1. Анархия в форматах данных. Например, клиент посылает данные как ключ=значение, в ответ получает xml. Если вы выбрали xml как протокол — используйте его в обе стороны. В запросах и ответах используйте единообразное кодирование и подписывание. Если вы не будете это делать — программисты со стороны клиента будут делать минимально рабочий код, а не как вы планировали. Приведу примерный диалог со службой поддержки одной платежной системы:

    я: гарантирую, что ни один магазин не отсылает вам ответ на финальной стадии запроса

    поддержка: так и есть! из-за этого мы не можем зафиксировать факт получения этого запроса клиентом

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


    2. Баг при склеивании данных для подписи. Такое ощущение, что платежная система обязательно должна переболеть этим багом. Обычно подпись формируют так: берем все параметры запроса, конкатенируем с приватным ключем и вычисляем хеш. Допустим, поле description в порядке конкатенации идет перед суммой — убираем у суммы первую цифру и добавляем к description. Хеш не меняется. В итоге оплачиваем заказ меньшей суммой. Что интересно, программисты сначала сопротивляются признавать это багом, а потом сообщают «ну, мы же не можем менять протокол, он уже используется на широкую ногу». Масса проектов болеет этой болезнью в различных вариациях:

    2.1 склейка с помощью разделителей и нефильтрация разделителей в парамерах

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

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

    2.4 отбрасывание невалидных необязательных параметров

    3. Изобретение своего таймстампа — надоело писать под каждую систему свой парсер ДДММГГГГЧЧММСС, ГГГГ-ММ-ДДлевыйсимволЧЧ: ММ: СС и т.д множество вариантов. Чем стандартный таймстамп не устраивает?

    4. Коды ошибок. Я понимаю, что ваша платежная система работает идеально и для кодов ошибок вы предусмотрели только ошибки на моей стороне. Пожалуйста, предусмотрите код ошибки «неверные данные со стороны платежной системы», которым может ответить клиентский код

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

    6. Недокументированные и как следствие малозащищенные методы API. Обычно в них не проверяется подпись, проверка по ip и т.д. Тайное рано или поздно станет явным — программисты частенько не засиживаются на одном месте работы и за пивком сольют подобное:

    — прикиньте, а банкоматчики к нам ходили без проверки подписи, потому что им было влом менять софт на тысячах банкоматов.


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

    8. Не давайте дурных примеров: на приводите в документации упрощенный пример, код которого предусматривает явное присутствие секретного ключа в html странице — поверьте, некоторые этот код скопируют в сайты своих магазинов.
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 26

      +8
      Подписываюсь под каждым пунктом. Сейчас подсключаем систему бронирования noname поставщика. Так у них документация — это набор xml докуметов с примерами запросов и ответов. Об их назначении я должен догадываться по названию.

      Что еще смущает, так это то, что полгода назад отправил пулреквест одной фирме, где прислал им примеры кода для их документации (документация в открытом виде лежит у них). Ибо их примеры были написанны на версии языка 5-летней давности. И что же. Спустя полгода они даже не удосужились проверить мой коммит. И такое отношение кругом: не работает — разбирайтесь сами.

      Хотя встречаются API с отличной документацией и отзывчивым сапортом. Таких на руках носить хочется.
        +1
        > Чем стандартный таймстамп не устраивает?

        Очевидно, отсутствием стандарта на таймстемп.
          +4
          чем плох например UNIX timestamp?
            –14
            Плох тем, что в данный момент существует минимум 24 таймстампа для текущего времени
              +5
              вы имеете ввиду часовой пояс?
                +15
                мне кажется вы ошибаетесь по поводу unix timestamp
                  +6
                  Да, ошибся. Извините
                +2
                Тем, что внизу написали о ISO 8601, который тоже ни чем не плох, кроме существования UNIX timestamp
                +9
                Я специально опрос не проводил, но все программисты, которым я говорил «таймстемп» понимали, что речь идет о unix_timestamp и он неоднозначностью, вроде бы, не страдает
                  +7
                  ISO 8601?
                  +1
                  А вот, кстати, есть ли причины, почему их протоколы не могут таки быть транзакционными?
                    0
                    наверное потому, что у них REST-архтектура
                      0
                      Разве нельзя REST-запросами определить начало транзакции, коммит или откат и всё такое?
                        +1
                        Можно. Но во-первых, зачем тогда REST? А во-вторых, квалификация программистов клиентов системы обычно невысок — подстраиваются под них в пользу простоты, а не надежности
                          +2
                          REST — это не только структура самих URL'ов, но и логика обработки запросов. По REST сервер является stateless, т.е. не хранит состояние между запросами, а все действия — атомарны и самодостаточны. Для обеспечения транзакционности сервер должен быть statefull.
                            +1
                            Вы почти правы, однако если бы все было точно так, мы не могли бы аутентифицировать пользователей в REST…
                            Состояние возможно, просто оно должно определяться запросом…
                            Что мешает скажем сделать 2 метода:
                            — start — возвращает уникальный токен транзакции
                            — commit — завершает транзакцию, определяемую переданным токеном
                            ну и rollback аналогично…
                            Если от обычной аутентификации наш сервис не перестал быть REST, то и от этого не перестанет.
                              0
                              если сервер ничего не хранит между запросами, то каким образом работает аплоад файлов, регистрация заказов, проводка платежей и прочие замечательные вещи? про это есть замечательная статья, где в терминах непривычных REST интерфейсов описаны особенности привычных платежных систем и популярной системы массового кофейного обслуживания — How to GET a Cup of Coffee (и про транзакции тоже, куда без них). кто бы перевел для хабра…
                        +3
                        Всё бы ничего, но у меня был проект, в котором мы общались напрямую с платежным шлюзом одной оооочень крупной компании, клиентами которой тут так или иначе являются очень многие, я просто ох**ренел, когда до реализации валидации данных на клиенте, решил отправить отрицательную сумму платежа, а шлюз ее принял и выдал мне общую сумму: сумма_с_клиента + коммиссия -> отрицательная_сумма

                        Например: сумма_с_клиента = -2000 руб, коммисия = 20 руб, общая_сумма_платежа = -1980 руб, то есть платежная система осталась должна пользователю 1980 руб!

                        Количество же архитектурных косяков было просто неимоверным, по-моему они реализовали все грабли из статьи
                          0
                          Возврат с тем же API?
                          0
                          А мне больше всего нравится когда пользователь может оплатить заказ после отмены и перехода на failurl… Особенно это весело когда нет возможности проверить статут платежа и нужна сложная обработка заказа (например, начисление бонусов) :)
                            0
                            2. Баг при склеивании данных для подписи.

                            Простите, но я верно не понял в чем тут проблема.

                            Провайдер просит платежную систему снять (ПС) с пользователя N денег. Формируется запрос, подписывается и отправляется в ПС.
                            Если сам провайдер поменял сумму и подписал транзакцию своим же ключиком — почему это должно заботить ПС?

                            Я согласен с комментарием выше по поводу отрицательной суммы, но в данном случае, какая разница для ПС прислал мне провайдер валидную транзакцию на 10 или 100 денег?
                              +1
                              есть разные виды API. Я говорю о ситуации, когда на странице магазина формируется форма, клиент сабмитит эту форму и попадает на сайт платежной системы для проведения оплаты. Т.е клиент с его браузером выступает в качестве транспорта, поэтому может слать любые невалидные данные.
                                +1
                                Вот с такими вещами я не сталкивался =)
                                Спасибо за пояснения.
                              +1
                              Посмотрел недавно API приёма платежей российских платёжных систем. Иногда за такое хочется взять и, извините, уе… уехать подальше от интернета.
                              Такое впечатление, что некоторые мелочи туда добавили прямо специально чтобы добавить граблей в реализацию.
                              Причем неочевидных граблей. Вскользь описанных граблей. Или совсем никак не описанных граблей. Причем у кого три версии API, количество граблей возрастает от версии к версии.

                              Веселее всего у динозара российских онлайн-платежей.
                              Параметр «тестовый режим», который
                              А) не входит в «хеш/дайждест счёта/платежа» (мало кто в здравом уме после прочтения документации этот флаг будет проверять )
                              Б) типа выключается в контрольной панели (на самом деле фиг, флаг в контрольной панели — всего лишь значение по-умолчанию), что нигде не написано
                              B) в любом режиме можно провести платёж описанной на сайте «тестовой» карточкой с номером 4222 2222 2222 2222/CVC123 (выключается, но где-то в дебрях, упоминание есть только в английской версии сайта).

                              Где-то году в 2010 я делал платёжный шлюз webmoney(и др., но этот самый популярный) для биллинга whmcs (и других), по договорённости с первыми пользователями и по сей день я получаю логи обо всех попытках «считерить».
                              За 4 года попыток «считерить» набралось более нескольких тысяч, если просуммировать рублёвые эквиваленты платежей (здесь учтены только те случаи, где мне известна оригинальная сумма платежа), это более 2млн рублей. И это только несколько довольно небольших предприятий.

                              Мораль такова: «Если вы владелец магазина, который принимает интернет-платежи, проверяйте транзакции руками, поскольку некоторые ПС работать головой уже, к сожалению, не в состоянии».
                              Может прямо сейчас у вас за спиной, а возможно и с ведома ваших сотрудников, неустановленные клиенты-физлица выносят, к примеру, диван за 200 тысяч.
                                0
                                Кстати, а есть какие-нибудь «гайды» для написания и документирования API? Какой-нибудь ГОСТ
                                  +1
                                  Посмотрите тут: www.restapitutorial.com/
                                  Там есть видео с объяснением основных тем (вверху в меню можно выбрать)

                                Only users with full accounts can post comments. Log in, please.