Почему для оплаты используют POST, а не GET
Что проверяют
Знаете ли вы семантику методов: какой безопасен, какой идемпотентен, и что из этого следует для денег. Для бэкендера на Java проверяют ещё и практику: где это всплывает в Spring Security и чем на самом деле защищаются от двойного списания.
Как отвечать
GET по спецификации безопасный метод: он не должен менять состояние. На этом свойстве построена вся инфраструктура вокруг, и это главный аргумент:
- браузер, прокси и CDN вправе кэшировать ответ GET, а предзагрузка ссылок и поисковый робот вправе позвать его сами. Оплата по ссылке означает списание при обходе краулером;
- параметры URL утекают не по проводу, а вокруг него: история браузера, закладки, журналы веб-сервера и приложения, заголовок
Refererпри переходе на сторонний ресурс, счётчики аналитики. Шифрование канала закрывает передачу, но не эти следы; - лимит длины URL это не норма стандарта, а практический предел серверов и прокси на строку запроса, обычно единицы килобайт.
В Spring это @PostMapping на платёжную ручку и запрет менять состояние в обработчиках GET. Защита от подделки межсайтовых запросов в Spring Security по умолчанию проверяет токен именно на изменяющих методах, поэтому операция, спрятанная в GET, обходит её целиком.
От повторного списания спасает не выбор метода, а ключ идемпотентности: клиент генерирует его, сервер сохраняет с уникальным индексом и на повтор возвращает прежний результат. Плюс схема «POST, редирект, GET», чтобы обновление страницы не отправляло форму заново.
Где спотыкаются
Говорят, что POST хорош именно неидемпотентностью. Всё наоборот: неидемпотентность это риск двойного списания при ретрае клиента или обрыве связи, и её приходится компенсировать ключом идемпотентности на сервере.
Считают POST защищённым сам по себе. Без шифрования канала тело читается так же легко, как строка запроса, а журналы и трассировка при отладке пишут и тело тоже. Секреты не защищены методом, они защищены каналом и правилами логирования.
Смешивают безопасность метода и идемпотентность. GET обладает обоими свойствами, PUT и DELETE идемпотентны, но состояние меняют, POST не обладает ни одним. Без этого различения ответ превращается в набор заученных фраз.