1
0
mirror of https://github.com/twirl/The-API-Book.git synced 2025-01-05 10:20:22 +02:00

Anti-fraud chapters significantly expanded

This commit is contained in:
Sergey Konstantinov 2022-07-08 21:42:27 +03:00
parent 27b826f1c8
commit 4ffc10751b
9 changed files with 64 additions and 39 deletions

View File

@ -982,6 +982,12 @@ POST /v1/orders
You may note that in this setup the error can't be resolved in one step: this situation must be elaborated over, and either order calculation parameters must be changed (discounts should not be counted against the minimal order sum), or a special type of error must be introduced.
##### Stipulate future restrictions
With the API popularity growth, it will inevitably become necessary to introduce technical means of preventing illicit API usage, such as displaying captcha, setting honeypots, raising the ‘too many requests’ exceptions, installing anti-DDoS proxies, etc. All these things cannot be done if the corresponding errors and messages were not described in the docs from the very beginning.
You are not obliged to actually generate those exceptions, but you might stipulate this possibility in the terms of service. For example, you might describe the `429 Too Many Requests` error or captcha redirect, but implement the functionality when it's actually needed.
##### No results is a result
If a server processed a request correctly and no exceptional situation occurred — there must be no error. Regretfully, an antipattern is widespread — of throwing errors when zero results are found.
@ -1032,3 +1038,5 @@ Sometimes explicit location passing is not enough since there are lots of territ
Worth mentioning is that the `localized_` prefix in the example is used to differentiate messages to users from messages to developers. A concept like that must be, of course, explicitly stated in your API docs.
And one more thing: all strings must be UTF-8, no exclusions.
#####

View File

@ -41,6 +41,8 @@ Still, let us re-iterate once more: any problems with your API are automatically
It is important to mention that predicting the workload for the API service is rather complicated. Sub-optimal API usage, e.g. initializing the API in those application and website parts where it's not actually needed, might lead to a colossal increase in the number of requests after changing a single line of partner's code. The safety margin for an API service must be much higher than for a regular service for end users — it must survive the situation of the largest partner suddenly starting querying the API on every page and every application screen. (If the partner is already doing that, then the API must survive doubling the load: imagine the partner accidentally starts initializing the API twice on each page / screen.)
Another extremely important hygienic minimum is the informational security of the API service. In the worst-case scenario, namely, if an API service vulnerability allows for exploiting partner applications, one security loophole will in fact be exposed *in every partner application*. Needless to say that the cost of such a mistake might be overwhelmingly colossal, even if the API itself is rather trivial and has no access to sensitive data (especially if we talk about webpages where no ‘sandbox’ for third-party scripts exists, and any piece of code might let's say track the data entered in forms). API services must provide the maximum protection level (for example, choose cryptographical protocols with a certain overhead) and promptly react to any messages regarding possible vulnerabilities.
#### Comparing to Competitors
While measuring KPIs of any service, it's important not only to evaluate your own numbers but also to match them against the state of the market:

View File

@ -47,9 +47,11 @@ This data is not itself reliable, but it allows for making cross-checks:
* if the key was issued for one specific domain but requests are coming with a different Referer, it makes sense to investigate the situation and maybe ban the possibility to access the API with this Referer or this key;
* if an application initializes API by providing the key registered to another application, it makes sense to contact the store administration and ask for removing one of the apps.
**NB**: don't forget to set infinite limits for using the API with the `localhost`, `127.0.0.1` / `[::1]` Referers, and also for your own sandbox if it exists. Yes, abusers will sooner or later learn this fact and will start using it, but otherwise, you will ban local development and your own website much sooner than that.
The general conclusion is:
* it is highly desirable to have partners formally identified (either through obtaining API keys or by providing contact data such as website domain or application identifier in a store while initializing the API);
* this information shall not be trusted unconditionally; there must be double-checking mechanisms that identify the suspicious requests.
* this information shall not be trusted unconditionally; there must be double-checking mechanisms that identify suspicious requests.
#### Identifying end users

View File

@ -0,0 +1,3 @@
### IT-Security
As we have mentioned several times, API serves as a multiplier to *any* possibility, including illegal ones: severabl

View File

@ -976,6 +976,12 @@ POST /v1/orders
Легко заметить, что в этом примере нет способа разрешить ошибку в один шаг — эту ситуацию требуется предусмотреть отдельно, и либо изменить параметры расчёта (минимальная сумма заказа не учитывает скидки), либо ввести специальную ошибку для такого кейса.
##### Предусмотрите ограничения
С ростом популярности API вам неизбежно придётся внедрять технические средства защиты от недобросовестного использования — такие, как показ капчи, расстановка приманок-honeypot-ов, возврат ошибок вида «слишком много запросов», постановка прокси-защиты от DDoS перед эндпойнтами и так далее. Всё это невозможно сделать, если вы не предусмотрели такой возможности изначально, а именно — не ввели соответствующей номенклатуры ошибок и предупреждений.
Вы не обязаны с самого начала такие ошибки действительно генерировать — но вы можете предусмотреть их на будущее. Например, вы можете описать ошибку `429 Too Many Requests` или редирект на показ капчи, но не имплементировать возврат таких ответов, пока не возникнет такая необходимость.
##### Отсутствие результата — тоже результат
Если сервер корректно обработал вопрос и никакой внештатной ситуации не возникло — следовательно, это не ошибка. К сожалению, весьма распространён антипаттерн, когда отсутствие результата считается ошибкой.

View File

@ -41,6 +41,8 @@
Важно отметить, что нагрузку на API, вообще говоря, крайне сложно предсказать. Неоптимальное использование API, т.е. его инициализация в тех разделах приложений, где он в реальности не нужен, может привести к колоссальному росту нагрузки вследствие перемещения одной-единственной строки кода партнёра. «Запас прочности» API-сервис должен быть гораздо выше, чем у обычных пользовательских сервисов — как минимум на уровне, достаточном для поддержания его работоспособности в том случае, если крупнейший партнёр начнёт вызывать API при загрузке любой страницы вебсайта / открытии любого экрана приложения. (Если партнёр уже так делает — то API должен переживать как минимум удвоение этой нагрузки на тот случай, если разработчики случайно начнут инициализировать API дважды.)
Другой важнейший гигиенический минимум — это обеспечение информационной безопасности API. В худшем из возможных сценариев, если посредством эксплуатации уязвимости в API можно будет наносить вред конечным пользователем, фактически дыра в безопасности будет создана *в каждом приложении партнёра*. Излишне уточнять, что цена такой ошибки может оказаться невероятно большой даже если само API достаточно невинно и никакого доступа к чувствительным данным не имеет (особенно если речь идёт о веб-страницах, где в принципе нет никакой «песочницы» для сторонних скриптов, и любой код на странице может, например, отследить вводимые данные в формы). Сервисы API обязаны как использовать максимальные меры защиты (например, с запасом выбирать надёжные криптографические протоколы), так и максимально оперативно реагировать на сообщения об уязвимостях.
#### Сравнение с конкурентами
При измерении KPI любого сервиса критически важно измерять не только свои собственные показатели, но и состояние рынка:

View File

@ -47,6 +47,8 @@
* если ключ был выпущен для одного домена, но запросы приходят с Referer-ом другого домена — это повод разобраться в ситуации и, возможно, забанить возможность обращаться к API с этим Referer-ом или этим ключом;
* если одно приложение инициализирует API с указанием ключа другого приложения — это повод обратиться к администрации стора с требованием удалить одно из приложений.
**NB**: не забудьте разрешить безлимитное использование с Referer-ом `localhost` и `127.0.0.1` / `[::1]`, а также из вашей собственной песочницы, если она есть. Да, в какой-то момент злоумышленники поймут, что на такие Referer-ы не действуют ограничения, но это точно произойдёт гораздо позже, чем вы по неосторожности забаните локальную разработку или собственный сайт документации.
Общий вывод из вышеизложенного таков:
* очень желательно иметь формальную идентификацию пользователей (API-ключи как самая распространённая практика, либо указание контактных данных, таких как домен вебсайта или идентификатор приложения в сторе, при инициализации API);
* доверять этой информации безусловно ни в коем случае нельзя: должны существовать механизмы проверки, которые позволяют найти подозрительные запросы.

View File

@ -1,38 +0,0 @@
### Информационная безопасность
Как мы неоднократно упоминали, API выступает мультипликатором *любых* возможностей — в том числе и противозаконных: серьёзная уязвимость в API означает, что проблемам подвержены *все* клиенты, и это может приводить к проблемам совсем другого масштаба, нежели уязвимость в отдельном сервисе. Поэтому обеспечение безопасности API должно иметь максимальный приоритет из возможных.
Любой ИТ-сервис под капотом работает через внутренние API, которые, как правило, и являются главной мишенью злоумышленников. В этом смысле корпус возможных векторов атаки на API и на сервис для конечного пользователя почти полностью совпадает. На общих проблемах информационной безопасности мы останавливаться не будем, поскольку это тема для отдельной книги. Выделим же здесь те, которые специфичны именно для API как продукта.
##### Автоматическая генерация запросов
Речь идёт о следующем сценарии: допустим, ваш партнёр использует в своём приложении функцию поиска кофеен в виде эндпойнта для конечных пользователей (который «под капотом» вызывает соответствующую платную функциональность вашего API). Злоумышленник может вызывать этот эндпойнт автоматически (роботом), который эмулирует поведение обычного пользователя, и тем самым свободно пользоваться API. Основной и по факту единственный способ борьбы с таким фродом — не перекладывать на плечи партнёра борьбу с фродом, а встроить её в сам API. В частности, чрезвычайно полезно с самого начала закладывать возможность показывать конечному пользователю captcha, если он ведёт себя подозрительно. Другой способ борьбы — это honeypot-ы, т.е. «приманки», по которым может перейти только робот, но не законопослушный пользователь (типа невидимых результатов поиска).
Весьма полезным может оказаться подсчёт агрегированной статистики по сетям, о которой мы писали в предыдущей главе. Большое количество запросов с одного ip или одной сети (особенно если они относится к известным публичным прокси или выходным нодам TOR) является хорошим маркером необходимости показать captcha.
Очевидно, что добавление любого из описанных механизмов — нарушение обратной совместимости, поэтому их необходимо предусматривать с самой первой версии API.
##### Кража токенов доступа к платным API
Вопрос частично обсуждался в предыдущей главе: ключи доступа достаточно легко извлечь из кода клиентских приложений; это означает, что, предоставляя любую функциональность в виде SDK, виджетов и любых других клиентских компонентов вы автоматически создаёте возможность для злоумышленника представиться законопослушным партнёром и не платить за использование API (более того — переложить бремя оплаты на партнёра). Серверный ключ тоже может случайно утечь или быть украден. С такими нарушениями необходимо бороться комплексно.
1. Настроить распознавание роботов, как описано выше, и агрегацию статистики по автономным сетям (см. предыдущую главу). Скорее всего, украденные ключи будут использоваться не в приложении для конечных пользователей, а для какой-то непубличной деятельности, а значит будут хорошо отлавливаться обоими видами фильтров.
2. Дать возможность партнёрам ограничивать функциональность, которая доступна по ключу:
* устанавливать диапазон допустимых IP-адресов для серверных API, идентификаторов приложений и хостов в клиентских API;
* разрешать использование конкретного ключа только для конкретных методов API;
* вводить иные разумные ограничения (например, для ключа нашего кофейного API можно установить ограничения по странам и городам, в которых работает партнёр).
3. Вводить дополнительное подписывание запроса:
* например, если на странице вебсайта партнера осуществляется поиск лучших предложений лунго, для чего клиент обращается к URL вида `/v1/search?recipe=lungo&api_key={apiKey}`. В этом случае API-ключ может быть заменён на сгенерированную сервером подпись вида `sign = HMAC("recipe=lungo", apiKey)`. Такая подпись может быть украдена, но будет бесполезна для злоумышленника, так как позволяет найти только лунго;
* вместо API-ключа можно использовать одноразовые пароли (Time-Based One-Time Password, TOTP); такие токены действительны, как правило, в течение минуты, что чрезвычайно затрудняет злоумышленнику работу с украденными ключами.
По сути, описанные выше методы — вариации существующих алгоритмов защиты авторских прав (DRM, Digital Rights Management), поскольку конечная цель защиты та же: не допустить несанкционированного использования данных, доступных клиенту. И, как и в случае DRM, недостаток этого подхода — это необходимость законопослушным пользователям тратить время и ресурсы на работу с такой защитой. Любые технологии подобного рода — это всегда некоторые эвристические способы увеличить стоимость атаки настолько, чтобы она стала невыгодной.
Существует мнение, что любые активные способы защиты скорее вредят API, из-за сочетания двух факторов:
* бороться с выявленным нарушением вам, скорее всего, придётся административными методами, т.е. путём написания жалоб в магазины приложений и хостерам «пиратских» сайтов; для этого важно, чтобы доказательства нарушения были просты и очевидны, в то время как продемонстрировать факт взлома сложных DRM-алгоритмов может быть далеко не тривиальной задачей;
* вводя сложные алгоритмы, вы тем самым проводите своеобразный эволюционный отбор, направленный на выявление самых умных и хитрых злоумышленников, противодействовать которым будет гораздо сложнее, чем наивным попыткам украсть ключи.
С нашей точки зрения лучшей политикой борьбы с фродом является пассивный мониторинг нарушений (с последующим принятием административных мер) плюс возможность партнерам по их желанию установить дополнительные технические ограничения.
**NB**. Описанные выше разнообразные методы борьбы с нарушителями подразумевают, что вы предусмотрели процедуры отзыва ключа — как технические (обеспечение минимальной сложности процедуры смены ключа), так и организационные (уведомление партера о компрометации ключа) — иначе вы попросту ничего не сможете сделать с выявленными фактами фрода.

View File

@ -0,0 +1,38 @@
### Технические способы борьбы с несанкционированным доступом к API
Реализация парадигмы, описанной в предыдущей главе — централизованной борьбы с фродом, осуществляемым через клиентские API партнёра — на практике сталкивается с достаточно нетривиальными проблемами. Допустим, с помощью каких-то признаков и/или поведенческого анализа мы определили, что запрос с большой вероятностью выполнен не реальным человеком, а роботом. Что мы можем с этим сделать?
В случае сервисов для конечных пользователей мы могли бы показать капчу; но в случае API это весьма проблематично, особенно если вы пренебрегли советом [«Предусмотрите ограничения»](#chapter-11-paragraph-19). Если полная отработка сценария (идентификация пользователя — показ капчи или honeypot-а — пометка результатов прохождения теста) на вашем уровне невозможна или не была предусмотрена, вам придётся переложить её на партнёра (т.е. это партнёр должен будет показывать капчу и идентифицировать пользователя, основываясь на сигналах, поступающих от эндпойнтов API) что, конечно, сильно снижает комфортность работы с таким API.
Другой способ борьбы с роботами — это попытка идентифицировать среду атаки. Программная оболочка, через которую выполняются запросы, не идентична реальному пользовательскому устройству, и этот факт можно попытаться определить — особенно это касается веб-страниц, которые часто обрабатываются не эмулятором браузера, а каким-то фреймворком, который будет не способен, например, исполнять JavaScript или не поддерживает последние дополнения к WebAPI браузеров.
Немаловажен и вопрос, а что вы будете делать, если вы всё же смогли идентифицировать злонамеренного пользователя, но не можете сделать так, чтобы он прекратил слать запросы. В какой-то момент придётся прибегнуть к одной из двух стратегий:
* бан пользователя по ip (подсети, автономной системе), Referer-у или идентификатору приложения (если они передаются), либо какому-то частному правилу (например, по заголовку User-Agent, если злоумышленник забыл его подменить);
* отдача ложного ответа.
С точки зрения эффективности противоборства атаке второй вариант куда предпочтительнее, поскольку перекидывает мяч на ту сторону: теперь уже злоумышленнику нужно каким-то образом определять, был ли он пойман. Но с точки зрения морали (и буквы закона) этот способ весьма сомнителен — особенно если учесть, что всегда возможны ложположительные срабатывания, и некорректные данные будут отданы честному пользователю.
#### Противодействие краже ключей
Рассмотрим теперь второй вариант несанкционированного использования, когда злоумышленник крадёт API-ключ добросовестного партнёра и вставляет его в своё приложение. Запросы при этом генерируются настоящими пользователями, а значит капча никак не поможет — но помогут другие методы.
1. Вести иерархическую статистику доступа по сетям, как было рекомендовано в предыдущей главе. Если приложение злоумышленника всё-таки не обычное приложение для честных потребителей, а какой-то закрытый сервис для ограниченного круга пользователей, этот факт будет виден по аномальной плотности запросов с определённых ip / подсетей / автономных систем (а если повезёт — то ещё и по подозрительным referer-ам, которые закрыты для внешнего доступа).
2. Дать возможность партнёрам ограничивать функциональность, которая доступна по ключу:
* устанавливать диапазон допустимых IP-адресов для серверных API, идентификаторов приложений и хостов в клиентских API;
* разрешать использование конкретного ключа только для конкретных методов API;
* вводить иные разумные ограничения (например, для ключа нашего кофейного API можно установить ограничения по странам и городам, в которых работает партнёр).
3. Вводить дополнительное подписывание запроса:
* например, если на странице вебсайта партнера осуществляется поиск лучших предложений лунго, для чего клиент обращается к URL вида `/v1/search?recipe=lungo&api_key={apiKey}`. В этом случае API-ключ может быть заменён на сгенерированную сервером подпись вида `sign = HMAC("recipe=lungo", apiKey)`. Такая подпись может быть украдена, но будет бесполезна для злоумышленника, так как позволяет найти только лунго;
* вместо API-ключа можно использовать одноразовые пароли (Time-Based One-Time Password, TOTP); такие токены действительны, как правило, в течение короткого времени, порядка минуты, что чрезвычайно затрудняет злоумышленнику работу с украденными ключами.
4. Банить ключи. Эта операция почти всегда вызовет негативную реакцию партнёра, но, в конце концов, для многих бизнесов лучше временно лишиться какой-то функциональности в приложении, чем получить многомиллионный счёт.
#### Щит и меч
Описанные выше методы — по сути, вариации существующих алгоритмов защиты авторских прав (DRM, Digital Rights Management), поскольку конечная цель защиты та же: не допустить несанкционированного использования данных, доступных клиенту. И, как и в случае DRM, недостаток этого подхода — это усложнение использования сервиса для абсолютно законопослушных партнёров и конечных пользователей. Это первая причина, по которой совершенствование и усложнение защиты может привести к неконкурентоспособности продукта и накоплению негативной репутации в глазах потребителей.
Вторая причина состоит в том, что любые технологии подобного рода — всегда эвристические и не дают стопроцентных гарантий. По большому счёту их цель — сделать атаку на API настолько затратной, чтобы пропала целесообразность атаковать. Предотвратить атаку полностью невозможно, поскольку у злоумышленника всегда есть в запасе дорогой, но работающий способ посадить реальных людей с реальными приложениями, чтобы они выполняли нужные запросы к API и были неотличимы от обычных пользователей. Вводя сложные алгоритмы, вы тем самым проводите своеобразный «эволюционный отбор», направленный на выявление самых умных и хитрых злоумышленников, противодействовать которым будет гораздо сложнее, чем наивным попыткам украсть ключи.
В конечном итоге, когда наивные злоумышленники закончились, а умные научились обходить все технические препоны, бороться с выявленным нарушением вам придётся административными методами, т.е. путём написания жалоб хостерам «пиратских» сайтов и обращений в магазины приложений и в суд. Для этого важно, чтобы доказательства нарушения были просты и очевидны, в то время как продемонстрировать факт взлома сложных DRM-алгоритмов может быть далеко не тривиальной задачей. С нашей точки зрения лучшей политикой борьбы с фродом является пассивный мониторинг нарушений (с последующим принятием административных мер) плюс возможность партнерам по их желанию установить дополнительные технические ограничения плюс административное преследование наиболее вопиющих случаев. (Уточнение «вопиющих» важное: судебные действия против таких «предпринимателей» обязательно вызовут напряженность со стороны бизнеса и разработчиков, которые могут иметь совсем другое мнение относительно тяжести нарушения; важно, чтобы деяние заслуживало строгости наказания и в глазах незаинтересованных сторон.)