Предоставляемая информация верна для любой платежной системы. В том числе для систем DSS PCI, простого эквайринга (прием платежей банковскими картами), виртуальных платежных систем (яндекс.деньги, вебмани, робокасса и др).
Обсуждение статьи «Скомпрометированы транзакции плательщиков RBK Money» показало критичную безграмотность некоторых комментирующих. Обычно свет знаний у невежества вызывает страх и раздражение, что интересно отследить по комментариям. Я попытался дать разъяснения там в обсуждениях, за что и поплатился.
Как программировать безопасный прием платежей? Поделюсь опытом, расскажу и покажу. Для нуждающихся ссылки на прувы (доказательства) приведены в конце статьи.
Их три.
1. Пользователь – в общем случае живой человек, которые использует сервисы.
2. Интернет-магазин (ИМ) – браузерная CMS или апп с функцией оплаты. У него должен быть владелец, имеющий право заниматься коммерческой деятельностью (в соответствии с ГК РФ – ИП или юрлицо – коммерческая организация). Владелец ИМ должен заключить юридический договор с ПС и выполнить требования последнего по техническому подключению.
3. Платежная система (ПС) – сервис, предоставляющий возможность совершать платежи. Его владельцем обязательно должна быть финансовая организация (юридическое лицо, имеющее юридические возможности осуществлять такого рода деятельность).
1. Пользователь выбирает какие-то товары или услуги в ИМ.
2. Пользователь выражает желание купить и оплатить покупку в ИМ.
3. ИМ направляет пользователя в ПС.
4. Пользователь совершает платеж в ПС. Пользователь видит, что платеж успешен или не успешен.
5. ПС предлагает пользователю вернуться в ИМ.
6. Если платеж был успешен, пользователь может получить оплаченные товары или услуги. Если платеж не был успешен, пользователь получает соответствующее уведомление.
1. ИМ позволяет пользователю сформировать заказ. Обычно это один или несколько заказанных товаров и услуг. У товаров и услуг должна быть явно обозначена цена и условия, на которых они продаются.
2. ИМ формирует счет к оплате.
3. ИМ отправляет пользователя в ПС, при этом сообщает данные счета к оплате – идентификатор, сумму.
4. ИМ получает уведомление от ПС об успехе или неудаче платежа. Для этого отправляется специальное сообщение – мимо пользователя! Пользователь не знает об этом сообщении. Формат сообщения, как правило – XML или JSON.
5. ИМ отвечает ПС об успешном получении уведомления о статусе платежа. ПС не примет деньги, если ИМ не работает, или не желает признавать успешность платежа (например, счет истек, или произошли другие события, которые не позволяют ИМ признать этот платеж). Повторю – в этом случае ПС не примет платеж от пользователя!
6. ИМ привечает пользователя после посещения ПС, сообщая статус счета к оплате. При этом ПС сообщает ИМ номер счета – в ссылке или в данных, полученных POST. Пользователь должен быть авторизован! Не следует сообщать данные счета к оплате посторонним лицам (глупость, которая обсуждалась в пресловутых комментариях!). Следует запрограммировать механизм авторизации таким образом, что если неавторизованный пользователь попадет на страницу счета к оплате – он должен получить сообщение “Доступ запрещен” и приглашение авторизоваться. Авторизация при успехе должна возвращать (или не уводить) на текущую страницу сайта. Если авторизованный пользователь является владельцем счета, то он имеет право просматривать его страницу. Если авторизованный пользователь не является владельцем счета (и не является сотрудником ИМ) – следует вместо данных показать ему сообщение ДОСТУП ЗАПРЕЩЕН.
1. Принять пользователя от ИМ вместе с данными счета к оплате.
2. Принять платеж от пользователя, в соответствии с данными счета к оплате (сумма, действительно до, валюта).
3. Сообщить ИМ об успехе или неудаче платежа (это сообщение для ИМ, а не для пользователя!).
4. Получить сообщение от ИМ о том, что ИМ успешно получил и подтвердил сообщение об успехе платежа! Если ИМ не ответит – ПС не будет принимать платеж от пользователя (вернет деньги и сообщит, что в оплате отказано).
5. Сообщить пользователю об успехе или неудаче платежа (это сообщение для пользователя, а не для ИМ!).
6. Вернуть пользователя в ИМ, передав номер счета (чтобы пользователь смог попасть на нужную страницу сайта ИМ).
![](https://habrastorage.org/r/w1560/files/ff5/d5f/225/ff5d5f225ecb4b31ad643ee7b1deab85.png)
Добавьте эту сущность в вашу CMS, если ее еще нет.
У счета к оплате должны быть обязательные свойства:
1. Идентификатор. Обычно это положительное целое число. ИМ должен обязательно сообщать его ПС при запросе действия оплаты!
2. Дата, когда создан счет
3. Время, в течении которого действителен счет. Это опциональная возможность, но она позволит избежать массы глупых ситуаций.
4. Сумма
5. Идентификатор пользователя. Чей это счет? Это важная информация, которая также используется и для обеспечения безопасности.
6. Признак действительности счета.
7. Другие данные.
В ИМ, кроме счета есть и другие сущности: заказ, статусы заказа (иногда это не отдельная сущность, а просто денормализованные данные), товары и услуги в заказе.
Не надо делать заказ и счет к оплате одной сущностью. Тому есть технологические причины, юзкейсы:
— пользователь может совершить несколько попыток оплаты;
— действительность (имею в виду время актуальности) заказа может отличаться от действительности счета, и это нормально;
— результаты неисправностей (в том числе проблем нетехнического характера) и взломов хорошо фиксировать. Логи не хранят пользовательские данные (userdata). А в этой сущности они как раз есть;
— другие причины, известные разработчикам.
Небольшой оффтопик.
Если бы мы говорили только о программировании ИМ, тут стоило бы напомнить следующее.
1. Следует сохранять цены в сущности “товары и услуги в заказе”. Цены изменяются, и это нормально. При этом не должны пострадать старые данные – цены, действующие ранее на момент оформления заказов.
2. Нельзя делать реальное удаление товаров и услуг в ИМ. Они должны отображаться, как связные данные – для корректного отображения старых заказов, когда они были в наличии, были в каталогах и т.д.
1. Создание. На этом этапе заказ должен быть полностью сформирован, так как редактирование данных в процессе платежа не допускается.
2. Счет к оплате не должен редактироваться в процессе платежа. Если содержимое заказа изменено, и он еще не оплачен – должен быть создан новый счет к оплате, а старый объявлен недействительным.
3. Изменение статуса счета к оплате, в соответствии с сигналом, полученным от ПС. Счет к оплате должен быть действительным (проверяется дата создания счета и период действительности или дата действительности счета – может быть сделано и так и эдак). При этом ИМ получает сообщение от ПС в формате JSON, XML или пачку данных POST. Это сообщение страницей (сверстанной в HTML, DOC, PDF, RTF) ну никак не влияется. Более того, оно вообще для людей не предназначено.
4. Страница счета для пользователя. Должна быть защищена пользовательской сессией. На этой странице пользователь-владелец счета (или сотрудник ИМ) может увидеть информацию о статусе счета: оплачен, не оплачен, неудачная оплата, истек и т.д.
При изменении статуса счета должен срабатывать триггер, который должен изменять статус заказа. Это делает возможным процессинг интернет-магазина и связанных с ним модулей: CRM, склада и т.д.
1. Пользователь должен быть авторизован в ИМ перед оплатой.
2. Хорошо, когда действия пользователя в ИМ скрыты от посторонних глаз посредством SSL.
3. Сообщения, которыми обмениваются ПС и ИМ, сопровождаются хешами, соленными секретными кодами, исключительно уникальными для каждого ИМ – партнера ПС. Хеши генерируются из данных счета. Таким образом, попытка искажения данных оригинального счета ИМ приведет к неуспеху платежа.
4. Все персональные данные, включая сведения о статусе и других деталях счетов, должны быть защищены пользовательской сессией! Защищать их одним хешем, как обсуждалось в пресловутых комментариях, недостаточно. А вот причины как раз там раскрыты.
Вот обещанные прувы.
Яндекс.Деньги api.yandex.ru/money/doc/dg/concepts/About.xml
PayPal developer.paypal.com/webapps/developer/docs/classic/products
WebMoney wiki.webmoney.ru/projects/webmoney/wiki/Web_Merchant_Interface
Робокасса www.robokassa.ru/ru/Doc/Ru/Interface.aspx
Обсуждение статьи «Скомпрометированы транзакции плательщиков RBK Money» показало критичную безграмотность некоторых комментирующих. Обычно свет знаний у невежества вызывает страх и раздражение, что интересно отследить по комментариям. Я попытался дать разъяснения там в обсуждениях, за что и поплатился.
Как программировать безопасный прием платежей? Поделюсь опытом, расскажу и покажу. Для нуждающихся ссылки на прувы (доказательства) приведены в конце статьи.
Действующие лица
Их три.
1. Пользователь – в общем случае живой человек, которые использует сервисы.
2. Интернет-магазин (ИМ) – браузерная CMS или апп с функцией оплаты. У него должен быть владелец, имеющий право заниматься коммерческой деятельностью (в соответствии с ГК РФ – ИП или юрлицо – коммерческая организация). Владелец ИМ должен заключить юридический договор с ПС и выполнить требования последнего по техническому подключению.
3. Платежная система (ПС) – сервис, предоставляющий возможность совершать платежи. Его владельцем обязательно должна быть финансовая организация (юридическое лицо, имеющее юридические возможности осуществлять такого рода деятельность).
Действия пользователя
1. Пользователь выбирает какие-то товары или услуги в ИМ.
2. Пользователь выражает желание купить и оплатить покупку в ИМ.
3. ИМ направляет пользователя в ПС.
4. Пользователь совершает платеж в ПС. Пользователь видит, что платеж успешен или не успешен.
5. ПС предлагает пользователю вернуться в ИМ.
6. Если платеж был успешен, пользователь может получить оплаченные товары или услуги. Если платеж не был успешен, пользователь получает соответствующее уведомление.
Действия ИМ
1. ИМ позволяет пользователю сформировать заказ. Обычно это один или несколько заказанных товаров и услуг. У товаров и услуг должна быть явно обозначена цена и условия, на которых они продаются.
2. ИМ формирует счет к оплате.
3. ИМ отправляет пользователя в ПС, при этом сообщает данные счета к оплате – идентификатор, сумму.
4. ИМ получает уведомление от ПС об успехе или неудаче платежа. Для этого отправляется специальное сообщение – мимо пользователя! Пользователь не знает об этом сообщении. Формат сообщения, как правило – XML или JSON.
5. ИМ отвечает ПС об успешном получении уведомления о статусе платежа. ПС не примет деньги, если ИМ не работает, или не желает признавать успешность платежа (например, счет истек, или произошли другие события, которые не позволяют ИМ признать этот платеж). Повторю – в этом случае ПС не примет платеж от пользователя!
6. ИМ привечает пользователя после посещения ПС, сообщая статус счета к оплате. При этом ПС сообщает ИМ номер счета – в ссылке или в данных, полученных POST. Пользователь должен быть авторизован! Не следует сообщать данные счета к оплате посторонним лицам (глупость, которая обсуждалась в пресловутых комментариях!). Следует запрограммировать механизм авторизации таким образом, что если неавторизованный пользователь попадет на страницу счета к оплате – он должен получить сообщение “Доступ запрещен” и приглашение авторизоваться. Авторизация при успехе должна возвращать (или не уводить) на текущую страницу сайта. Если авторизованный пользователь является владельцем счета, то он имеет право просматривать его страницу. Если авторизованный пользователь не является владельцем счета (и не является сотрудником ИМ) – следует вместо данных показать ему сообщение ДОСТУП ЗАПРЕЩЕН.
Действия ПС
1. Принять пользователя от ИМ вместе с данными счета к оплате.
2. Принять платеж от пользователя, в соответствии с данными счета к оплате (сумма, действительно до, валюта).
3. Сообщить ИМ об успехе или неудаче платежа (это сообщение для ИМ, а не для пользователя!).
4. Получить сообщение от ИМ о том, что ИМ успешно получил и подтвердил сообщение об успехе платежа! Если ИМ не ответит – ПС не будет принимать платеж от пользователя (вернет деньги и сообщит, что в оплате отказано).
5. Сообщить пользователю об успехе или неудаче платежа (это сообщение для пользователя, а не для ИМ!).
6. Вернуть пользователя в ИМ, передав номер счета (чтобы пользователь смог попасть на нужную страницу сайта ИМ).
![](https://habrastorage.org/files/ff5/d5f/225/ff5d5f225ecb4b31ad643ee7b1deab85.png)
Счет к оплате
Добавьте эту сущность в вашу CMS, если ее еще нет.
У счета к оплате должны быть обязательные свойства:
1. Идентификатор. Обычно это положительное целое число. ИМ должен обязательно сообщать его ПС при запросе действия оплаты!
2. Дата, когда создан счет
3. Время, в течении которого действителен счет. Это опциональная возможность, но она позволит избежать массы глупых ситуаций.
4. Сумма
5. Идентификатор пользователя. Чей это счет? Это важная информация, которая также используется и для обеспечения безопасности.
6. Признак действительности счета.
7. Другие данные.
В ИМ, кроме счета есть и другие сущности: заказ, статусы заказа (иногда это не отдельная сущность, а просто денормализованные данные), товары и услуги в заказе.
Не надо делать заказ и счет к оплате одной сущностью. Тому есть технологические причины, юзкейсы:
— пользователь может совершить несколько попыток оплаты;
— действительность (имею в виду время актуальности) заказа может отличаться от действительности счета, и это нормально;
— результаты неисправностей (в том числе проблем нетехнического характера) и взломов хорошо фиксировать. Логи не хранят пользовательские данные (userdata). А в этой сущности они как раз есть;
— другие причины, известные разработчикам.
Небольшой оффтопик.
Если бы мы говорили только о программировании ИМ, тут стоило бы напомнить следующее.
1. Следует сохранять цены в сущности “товары и услуги в заказе”. Цены изменяются, и это нормально. При этом не должны пострадать старые данные – цены, действующие ранее на момент оформления заказов.
2. Нельзя делать реальное удаление товаров и услуг в ИМ. Они должны отображаться, как связные данные – для корректного отображения старых заказов, когда они были в наличии, были в каталогах и т.д.
Действия ИМ со счетом к оплате
1. Создание. На этом этапе заказ должен быть полностью сформирован, так как редактирование данных в процессе платежа не допускается.
2. Счет к оплате не должен редактироваться в процессе платежа. Если содержимое заказа изменено, и он еще не оплачен – должен быть создан новый счет к оплате, а старый объявлен недействительным.
3. Изменение статуса счета к оплате, в соответствии с сигналом, полученным от ПС. Счет к оплате должен быть действительным (проверяется дата создания счета и период действительности или дата действительности счета – может быть сделано и так и эдак). При этом ИМ получает сообщение от ПС в формате JSON, XML или пачку данных POST. Это сообщение страницей (сверстанной в HTML, DOC, PDF, RTF) ну никак не влияется. Более того, оно вообще для людей не предназначено.
4. Страница счета для пользователя. Должна быть защищена пользовательской сессией. На этой странице пользователь-владелец счета (или сотрудник ИМ) может увидеть информацию о статусе счета: оплачен, не оплачен, неудачная оплата, истек и т.д.
При изменении статуса счета должен срабатывать триггер, который должен изменять статус заказа. Это делает возможным процессинг интернет-магазина и связанных с ним модулей: CRM, склада и т.д.
Безопасность
1. Пользователь должен быть авторизован в ИМ перед оплатой.
2. Хорошо, когда действия пользователя в ИМ скрыты от посторонних глаз посредством SSL.
3. Сообщения, которыми обмениваются ПС и ИМ, сопровождаются хешами, соленными секретными кодами, исключительно уникальными для каждого ИМ – партнера ПС. Хеши генерируются из данных счета. Таким образом, попытка искажения данных оригинального счета ИМ приведет к неуспеху платежа.
4. Все персональные данные, включая сведения о статусе и других деталях счетов, должны быть защищены пользовательской сессией! Защищать их одним хешем, как обсуждалось в пресловутых комментариях, недостаточно. А вот причины как раз там раскрыты.
Источники
Вот обещанные прувы.
Яндекс.Деньги api.yandex.ru/money/doc/dg/concepts/About.xml
PayPal developer.paypal.com/webapps/developer/docs/classic/products
WebMoney wiki.webmoney.ru/projects/webmoney/wiki/Web_Merchant_Interface
Робокасса www.robokassa.ru/ru/Doc/Ru/Interface.aspx