Обзор:
Моя компания разработала API с ограничением скорости. Наша цель двоякая:
- О: Создайте вокруг нашего продукта сильную экосистему для разработчиков.
- B: Продемонстрируйте мощь нашего API, используя его для управления нашим собственным приложением.
Уточнение: Зачем вообще ограничение по скорости?
Мы оцениваем ограничение нашего API, потому что мы продаем его как дополнение к нашему продукту. Анонимный доступ к нашему API имеет очень низкий порог для вызовов API в час, тогда как нашим платным клиентам разрешено более 1000 вызовов в час и более.
Эта проблема:
Наш API с ограничением скорости отлично подходит для экосистемы разработчиков, но для того, чтобы мы могли испытать его, мы не можем допустить, чтобы он ограничивался тем же ограничением скорости. Передняя часть нашего API - это весь JavaScript, выполняющий прямые Ajax-вызовы API.
Итак, вопрос:
Как защитить api, чтобы можно было удалить ограничение скорости, когда в процессе удаления такого ограничения скорости не может быть легко подделано?
Изученные решения (и почему они не сработали)
Проверьте реферер по заголовку хоста. - Неправильно, потому что реферера легко подделать.
Используйте HMAC для создания подписи на основе запроса и общего секрета, а затем проверьте запрос на сервере. - Ошибочно, потому что секрет и алгоритм можно было бы легко определить, заглянув в интерфейс JavaScript.
Прокси-сервер запроса и подпись запроса в прокси-сервере - все еще некорректно, так как прокси-сервер сам предоставляет API.
Вопрос:
Я обращаюсь к блестящим умам Stack Overflow, чтобы они представили альтернативные решения. Как бы вы решили эту проблему?
источник
Ответы:
Поскольку ваш собственный клиент JavaScript обращается к API напрямую, любой сможет посмотреть, что он делает, и имитировать это, в том числе использовать тот же ключ API. Вы можете попытаться сделать его более сложным, например, запутав свой код или поставив различные препятствия на пути, но вы и человек, которого вы пытаетесь ограничить, в основном имеете одинаковый доступ. Вместо того, чтобы пытаться создать различие в привилегиях, вам нужно построить систему, в которой совершенно нормально, что неофициальный клиент использует весь доступ в своей области, но система устроена таким образом, что официальное использование для всех клиентов больше.
Это часто делается с помощью маркеров доступа для каждого пользователя, а не с помощью одного маркера для всего приложения. Лимит каждого токена должен быть достаточным для типичного использования вашего API, но ограничительным для тех, кто пытается им злоупотребить. Например, 100 звонков в минуту может быть более чем достаточно для поддержки обычного просмотра, но если я хочу очистить вас, я не смогу сделать это эффективно с таким бюджетом.
Всегда будет гонка вооружений - я могу обойти предел, создав множество учетных записей пользователей-ботов. Это, тем не менее, довольно решенная проблема, если вы просто добавите капчу в свой поток регистрации, за небольшую плату для настоящего человека. Когда вы входите в эти сценарии, все становится просто компромиссом между удобством и ограничениями. Вы никогда не найдете чего-то полностью пуленепробиваемого, поэтому сосредоточьтесь на том, чтобы сделать его достаточно хорошим и подождите, пока кто-то вас не использует, чтобы узнать, где были дыры.
источник
Если это вызывает у вас проблемы, это вызовет проблему у вашей предполагаемой экосистемы разработчиков (например, когда они попытаются разработать альтернативный пользовательский интерфейс). Если вы действительно едите собачий корм, заставьте API (и ограничение скорости) работать для вашего приложения. Вот несколько предложений:
Не ограничивайте скорость по IP-адресу. Скорее, ограничение скорости чем-то связанным с пользователем, например его идентификатором пользователя. Примените ограничение скорости на этапе аутентификации.
Разработайте свой API так, чтобы пользователям не приходилось вызывать его постоянно (например, вызовите список, который возвращает много результатов, а не повторяющийся вызов, который каждый раз возвращает один элемент)
Создавайте свое веб-приложение с теми же ограничениями, которые ожидаются от экосистемы разработчика, т. Е. Убедитесь, что вы можете спроектировать его в разумных пределах.
Убедитесь, что ваша серверная часть является масштабируемой (предпочтительно по горизонтали), поэтому вам не нужно устанавливать дросселирование на настолько низких уровнях, что это фактически вызывает проблемы для пользовательского интерфейса.
Убедитесь, что ваше дросселирование способно справляться со всплесками, а также ограничивать более длительные злоупотребления.
Убедитесь, что ваше дросселирование выполняет разумные действия с учетом злоупотреблений, которые вы пытаетесь устранить. Например, подумайте о постановке в очередь или задержке незначительных нарушителей, а не об отказе в соединении. Большинство веб-интерфейсов открывают только четыре одновременных соединения одновременно. Если вы откладываете попытку открыть пятый, вы попадете только в тот случай, когда они используют CLI одновременно с веб-клиентом (а не двумя веб-клиентами). Если вы отложите n-й вызов API без перерыва, а не откажетесь от него, конечный пользователь увидит, что все замедляется, а не ломается. Если вы объедините это только с постановкой в очередь N вызовов API одновременно, вы поразите только тех, кто распараллеливает большое количество вызовов API, что, вероятно, не является тем поведением, которое вам нужно - например, 100 одновременных вызовов API, тогда промежуток в течение часа обычно далеко хуже 100 последовательных вызовов API за час.
Разве это не ответило на ваш вопрос? Что ж, если вам действительно нужно делать то, о чем вы просите, установите ограничение скорости на этапе аутентификации и примените другое ограничение скорости в зависимости от группы, в которую входит ваш пользователь. Если вы используете один набор учетных данных (используемый вашими разработчиками и командой QA), вы получаете более высокий предел скорости. Но вы сразу понимаете, почему это неизбежно приведет вас к тому, что ваша экосистема увидит проблемы, которых ваш разработчик и команда QA не видят.
источник
Купите свой товар. Станьте платным клиентом самого себя.
«Анонимный доступ к нашему API имеет очень низкий порог для вызовов API в час, тогда как нашим платным клиентам разрешено более 1000 вызовов в час и более».
Это также помогает протестировать систему с точки зрения клиента.
источник
К сожалению, для этого нет идеального решения.
Общий подход обычно заключается в предоставлении поддельногоспособ для клиентов идентифицировать себя (например, идентификатор, версию и ключ API - например), для клиентов, чтобы зарегистрировать информацию о себе, которая может использоваться для ограничения доступа (например, клиент является сервером в заданном диапазоне IP-адресов, поэтому разрешите только вызывающие абоненты в этом диапазоне; например, клиент - это JavaScript, но доставляется только в определенную категорию браузера, поэтому разрешать доступ только к HTTP-запросам, которые определяют определенные строки пользовательского агента и т. д.), а затем использовать машинное обучение / шаблон распознавание для обнаружения аномального использования, которое, вероятно, является поддельным клиентом, а затем для отклонения трафика от этих поддельных клиентов (или подтверждения клиентами, что эти использования действительно не исходят от легитимного клиента, заменить их поддельные учетные данные, а затем запретить дальнейший трафик с использованием более старых поддельные учетные данные).
Вы можете немного усложнить подделку, используя несколько слоев ключа. Например, вы выдаете долговременные учетные данные, которые хранятся на сервере (и которые могут использоваться только в ограниченном наборе диапазонов IP-адресов), чтобы выполнить вызов API, который записывает информацию о клиенте (например, пользовательском агенте) и возвращает недолговечный клиентский ключ, который синдицируется в JavaScript для использования на клиенте для клиентских запросов API. Это тоже несовершенно (спуфер может выполнить тот же вызов сервера для получения учетных данных), но будет сложнее, если возвращаемый ключ API будет включен в запутанный (и часто меняющийся) JavaScript или HTML (что затрудняет достоверно извлечь из ответа). Это также дает возможность более легко обнаружить спуфинг; ключ на стороне клиента теперь привязан к конкретному клиенту (например,
источник
Предполагая, что рассматриваемое приложение должно быть открыто для всех, у вас нет особого выбора:
Выберите другой способ продемонстрировать мощь вашего API. Например, напишите такое приложение и поделитесь его исходным кодом, но не запускайте этот код. Убедитесь, что он хорошо задокументирован, чтобы любой мог его развернуть и убедиться, что он работает (при условии ограничения).
Приложение, которое вы запускаете, необходимо будет реорганизовать, чтобы избежать запросов API на стороне клиента и сделать его более серверным. Вы по-прежнему можете тестировать свой API, но не очевидным способом - делать безопасные запросы к API без ограничений со стороны сервера.
Настройте ограничение скорости чтобы ваше приложение работало, и инвестируйте в оптимизацию производительности для обработки нагрузки.
И да, в первую очередь освободите ядро API от дросселей и держите его в частной сети. Дроссель в отдельном общедоступном слое.
источник
Можете ли вы создать отдельный экземпляр пользовательского интерфейса и API без ограничений, а затем ограничить доступ к IP-адресам, исходящим от вашей организации?
Например, разверните все это за корпоративным брандмауэром и прикрепите приложение к той же базе данных, что и общедоступный экземпляр, если вам нужно обмениваться данными между экземплярами.
источник
Вы можете попытаться создать уникальный идентификатор сеанса, привязанный к определенному IP-адресу / пользователю и ограниченный по времени существования. Когда пользователь загружает код JavaScript внешнего интерфейса вашего приложения, вставьте сгенерированный идентификатор сеанса в исходный код JavaScript. Идентификатор сеанса будет прикреплен к каждому запросу к вашему API, и ограничение по скорости будет снято.
Идентификатор нельзя просто скопировать для подделки, потому что он действителен только для одного IP-адреса, пользователя и ограниченное время. Таким образом, злоумышленник должен будет вызвать вашу страницу и отфильтровать ключ из вашего источника JavaScript или перехватить запрос Ajax каждый раз, когда новый пользователь захочет его использовать.
Другой вариант:
Настройте прокси для своего собственного приложения и используйте обфускацию. Запросы Ajax к прокси используют имена, отличные от реальных API-вызовов, и прокси переводит их обратно. Итак, ваше приложение не будет вызывать
getDocument
к вашему реальному API, но оно будет вызыватьgetFELSUFDSKJE
ваш прокси. Прокси-сервер преобразует этот вызов обратно в getDocument и перенаправит его в фактический API с ограниченной скоростью.Ваш фактический API не будет ограничивать скорость запросов через прокси.
И чтобы другие люди не использовали ваш прокси для своих приложений, вы ежедневно меняете схему обфускации. Обфусцированные имена вызовов могут быть автоматически сгенерированы в исходном коде JavaScript и настроены в прокси.
Клиенту, желающему использовать это, также нужно будет следить за изменением обфускации, чтобы использовать ваш прокси. И вы по-прежнему можете использовать заголовки реферера и тому подобное для ведения журнала, чтобы вы могли находить людей, использующих ваш прокси. Или ловите их при изменении схемы обфускации.
источник
источник
Настройте несколько учетных записей и выбирайте одну из них случайным образом при каждом запросе или меняйте, какой из них вы используете, каждый час или около того. Таким образом, вы можете распределить нагрузку по
n
счетам,n
увеличив лимиты в разы.Будьте осторожны, чтобы случайно не выключиться, если вы пытаетесь найти других пользователей, делающих это, если это не разрешено для клиентов.
источник