Использование собственного API с ограничением по скорости

117

Обзор:

Моя компания разработала API с ограничением скорости. Наша цель двоякая:

  • О: Создайте вокруг нашего продукта сильную экосистему для разработчиков.
  • B: Продемонстрируйте мощь нашего API, используя его для управления нашим собственным приложением.

Уточнение: Зачем вообще ограничение по скорости?

Мы оцениваем ограничение нашего API, потому что мы продаем его как дополнение к нашему продукту. Анонимный доступ к нашему API имеет очень низкий порог для вызовов API в час, тогда как нашим платным клиентам разрешено более 1000 вызовов в час и более.

Эта проблема:

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

Итак, вопрос:

Как защитить api, чтобы можно было удалить ограничение скорости, когда в процессе удаления такого ограничения скорости не может быть легко подделано?

Изученные решения (и почему они не сработали)

  1. Проверьте реферер по заголовку хоста. - Неправильно, потому что реферера легко подделать.

  2. Используйте HMAC для создания подписи на основе запроса и общего секрета, а затем проверьте запрос на сервере. - Ошибочно, потому что секрет и алгоритм можно было бы легко определить, заглянув в интерфейс JavaScript.

  3. Прокси-сервер запроса и подпись запроса в прокси-сервере - все еще некорректно, так как прокси-сервер сам предоставляет API.

Вопрос:

Я обращаюсь к блестящим умам Stack Overflow, чтобы они представили альтернативные решения. Как бы вы решили эту проблему?

Джейсон Уолдрип
источник
13
Вы не можете. Если ваше собственное использование API, которое вы не хотите ограничивать ограничением скорости, исходит только от общедоступных веб-страниц, то вы не можете делать ничего безопасного с этих общедоступных веб-страниц, потому что, как вы, кажется, уже знаете, существуют никаких секретов на общедоступных веб-страницах. Итак, что вы можете делать на своих веб-страницах, может и любой другой.
jfriend00
28
Вы уверены, что у вас действительно есть проблема с ограничением скорости, которую нужно решить при использовании корма для собак? Каждый пользователь, использующий ваш сайт и ваши веб-страницы, должен выглядеть совершенно другим пользователем для вашего кода ограничения скорости. Таким образом, просто убедитесь, что каждая веб-страница сама по себе подчиняется нормальным правилам ограничения скорости, и все будет в порядке. Предполагая, что ваше ограничение скорости для каждого клиента, один пользователь не будет иметь ничего общего с другим пользователем.
jfriend00
6
Почему бы вам не рассмотреть решение для управления API, которое обеспечивает ограничение скорости и регулирование для каждого пользователя, для каждой роли / разрешения или области приложения. Например, wso2 api manger
MiddlewareManiac
28
Ваш dogfooding обнаружил серьезную проблему с вашим общедоступным API (которая заключается в том, что предел скорости слишком низкий), и вместо того, чтобы исправить ее, вы пытаетесь ее обойти. Зачем использовать собачью еду, если вы собираетесь игнорировать обнаруженные вами проблемы?
user253751

Ответы:

93

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

Это часто делается с помощью маркеров доступа для каждого пользователя, а не с помощью одного маркера для всего приложения. Лимит каждого токена должен быть достаточным для типичного использования вашего API, но ограничительным для тех, кто пытается им злоупотребить. Например, 100 звонков в минуту может быть более чем достаточно для поддержки обычного просмотра, но если я хочу очистить вас, я не смогу сделать это эффективно с таким бюджетом.

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

Кристьян
источник
8
Принимая это как лучший ответ. Мы решили пойти по пути: использовать токены JWT с меньшим сроком действия и увеличить лимит скорости этих вызовов. Мы закодируем некоторую дополнительную информацию в токене, чтобы сервер узнал о более высоком пределе скорости. Поскольку эти токены надежно подписаны на сервере, проблем со спуфингом возникнуть не должно. Кто-то все еще может использовать токен, но он истечет через несколько дней, и поэтому поддерживать любого бота будет труднее.
Джейсон Уолдрип,
33

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

  • Не ограничивайте скорость по IP-адресу. Скорее, ограничение скорости чем-то связанным с пользователем, например его идентификатором пользователя. Примените ограничение скорости на этапе аутентификации.

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

  • Создавайте свое веб-приложение с теми же ограничениями, которые ожидаются от экосистемы разработчика, т. Е. Убедитесь, что вы можете спроектировать его в разумных пределах.

  • Убедитесь, что ваша серверная часть является масштабируемой (предпочтительно по горизонтали), поэтому вам не нужно устанавливать дросселирование на настолько низких уровнях, что это фактически вызывает проблемы для пользовательского интерфейса.

  • Убедитесь, что ваше дросселирование способно справляться со всплесками, а также ограничивать более длительные злоупотребления.

  • Убедитесь, что ваше дросселирование выполняет разумные действия с учетом злоупотреблений, которые вы пытаетесь устранить. Например, подумайте о постановке в очередь или задержке незначительных нарушителей, а не об отказе в соединении. Большинство веб-интерфейсов открывают только четыре одновременных соединения одновременно. Если вы откладываете попытку открыть пятый, вы попадете только в тот случай, когда они используют CLI одновременно с веб-клиентом (а не двумя веб-клиентами). Если вы отложите n-й вызов API без перерыва, а не откажетесь от него, конечный пользователь увидит, что все замедляется, а не ломается. Если вы объедините это только с постановкой в ​​очередь N вызовов API одновременно, вы поразите только тех, кто распараллеливает большое количество вызовов API, что, вероятно, не является тем поведением, которое вам нужно - например, 100 одновременных вызовов API, тогда промежуток в течение часа обычно далеко хуже 100 последовательных вызовов API за час.

Разве это не ответило на ваш вопрос? Что ж, если вам действительно нужно делать то, о чем вы просите, установите ограничение скорости на этапе аутентификации и примените другое ограничение скорости в зависимости от группы, в которую входит ваш пользователь. Если вы используете один набор учетных данных (используемый вашими разработчиками и командой QA), вы получаете более высокий предел скорости. Но вы сразу понимаете, почему это неизбежно приведет вас к тому, что ваша экосистема увидит проблемы, которых ваш разработчик и команда QA не видят.

abligh
источник
11

Купите свой товар. Станьте платным клиентом самого себя.

«Анонимный доступ к нашему API имеет очень низкий порог для вызовов API в час, тогда как нашим платным клиентам разрешено более 1000 вызовов в час и более».

Это также помогает протестировать систему с точки зрения клиента.

jkdev
источник
1
Очевидный ответ. Никакого обмана или фальсификаций!
wizzwizz4
9

К сожалению, для этого нет идеального решения.

Общий подход обычно заключается в предоставлении поддельногоспособ для клиентов идентифицировать себя (например, идентификатор, версию и ключ API - например), для клиентов, чтобы зарегистрировать информацию о себе, которая может использоваться для ограничения доступа (например, клиент является сервером в заданном диапазоне IP-адресов, поэтому разрешите только вызывающие абоненты в этом диапазоне; например, клиент - это JavaScript, но доставляется только в определенную категорию браузера, поэтому разрешать доступ только к HTTP-запросам, которые определяют определенные строки пользовательского агента и т. д.), а затем использовать машинное обучение / шаблон распознавание для обнаружения аномального использования, которое, вероятно, является поддельным клиентом, а затем для отклонения трафика от этих поддельных клиентов (или подтверждения клиентами, что эти использования действительно не исходят от легитимного клиента, заменить их поддельные учетные данные, а затем запретить дальнейший трафик с использованием более старых поддельные учетные данные).

Вы можете немного усложнить подделку, используя несколько слоев ключа. Например, вы выдаете долговременные учетные данные, которые хранятся на сервере (и которые могут использоваться только в ограниченном наборе диапазонов IP-адресов), чтобы выполнить вызов API, который записывает информацию о клиенте (например, пользовательском агенте) и возвращает недолговечный клиентский ключ, который синдицируется в JavaScript для использования на клиенте для клиентских запросов API. Это тоже несовершенно (спуфер может выполнить тот же вызов сервера для получения учетных данных), но будет сложнее, если возвращаемый ключ API будет включен в запутанный (и часто меняющийся) JavaScript или HTML (что затрудняет достоверно извлечь из ответа). Это также дает возможность более легко обнаружить спуфинг; ключ на стороне клиента теперь привязан к конкретному клиенту (например,

Михаил Аарон Сафян
источник
8

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

Выберите другой способ продемонстрировать мощь вашего API. Например, напишите такое приложение и поделитесь его исходным кодом, но не запускайте этот код. Убедитесь, что он хорошо задокументирован, чтобы любой мог его развернуть и убедиться, что он работает (при условии ограничения).

Приложение, которое вы запускаете, необходимо будет реорганизовать, чтобы избежать запросов API на стороне клиента и сделать его более серверным. Вы по-прежнему можете тестировать свой API, но не очевидным способом - делать безопасные запросы к API без ограничений со стороны сервера.

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

И да, в первую очередь освободите ядро ​​API от дросселей и держите его в частной сети. Дроссель в отдельном общедоступном слое.

Антон Строгонов
источник
4

Можете ли вы создать отдельный экземпляр пользовательского интерфейса и API без ограничений, а затем ограничить доступ к IP-адресам, исходящим от вашей организации?

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

Питер Мортенсен
источник
4

Вы можете попытаться создать уникальный идентификатор сеанса, привязанный к определенному IP-адресу / пользователю и ограниченный по времени существования. Когда пользователь загружает код JavaScript внешнего интерфейса вашего приложения, вставьте сгенерированный идентификатор сеанса в исходный код JavaScript. Идентификатор сеанса будет прикреплен к каждому запросу к вашему API, и ограничение по скорости будет снято.

Идентификатор нельзя просто скопировать для подделки, потому что он действителен только для одного IP-адреса, пользователя и ограниченное время. Таким образом, злоумышленник должен будет вызвать вашу страницу и отфильтровать ключ из вашего источника JavaScript или перехватить запрос Ajax каждый раз, когда новый пользователь захочет его использовать.

Другой вариант:

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

Ваш фактический API не будет ограничивать скорость запросов через прокси.

И чтобы другие люди не использовали ваш прокси для своих приложений, вы ежедневно меняете схему обфускации. Обфусцированные имена вызовов могут быть автоматически сгенерированы в исходном коде JavaScript и настроены в прокси.

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

Falco
источник
3
  • Добавить в белый список исходные IP-адреса
  • Используйте VPN , внесите в белый список участников VPN
  • Прокси-решение или надстройка браузера, которые добавляют HTTP-заголовки, должны подойти, если вы можете защитить прокси и не беспокоиться о MITM. атаках перехватывающих трафик.
  • Любое решение, связанное с секретами, может смягчить воздействие утечек за счет ежедневной смены секретов.
the8472
источник
Эти решения не применимы к интерфейсному веб-клиенту. Идеально, если доступ к API был на бэкэнде.
Джейсон Уолдрип,
@jason все они могут быть применены к
веб-
2

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

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

Филип Хаглунд
источник