Как защитить вызовы REST API?

92

Я разрабатываю успокаивающее веб-приложение, использующее какую-нибудь популярную веб-структуру на бэкэнде, скажем (rails, sinatra, flask, express.js). В идеале я хочу разработать клиентскую часть с помощью Backbone.js. Как разрешить только моей стороне клиента javascript взаимодействовать с этими вызовами API? Я не хочу, чтобы эти вызовы API были общедоступными и вызывались curlпросто путем ввода ссылки в браузере.

knd
источник
Для всех ваших вызовов API требуется токен, который передается клиенту при обслуживании вашей страницы?
hajpoj
Amazon AWS javascript SDK использует предварительно подписанный URL-адрес объекта: - docs.aws.amazon.com/AmazonS3/latest/dev/…
rjha94

Ответы:

91

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

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

  • Я уверен, что у вашего API есть какое-то поле аутентификации (например, хеш, вычисленный на клиенте). Если нет, взгляните на этот вопрос SO . Убедитесь, что вы используете соль (или даже ключ API), которая предоставляется вашему JS-клиенту для каждого сеанса (не жестко запрограммирована). Таким образом, неавторизованный потребитель вашего API будет вынужден выполнять гораздо больше работы.

  • При загрузке клиента JS запомните некоторые заголовки HTTP (на ум приходит пользовательский агент) и IP-адрес и попросите повторную аутентификацию, если они изменятся, используя черные списки для обычных подозреваемых. Это заставляет злоумышленника снова более тщательно выполнять домашнюю работу.

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

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

Ойген Рик
источник
это полезная информация, но что, если я хочу сделать некоторую аутентификацию из моего backend api в другое приложение api, например, на отдельный сервер, чтобы упростить мой вопрос, я хочу, чтобы мой back-end aka node.js отправлял запрос на выборку другому back - конечный сервер, который является моим собственным, по некоторым причинам это необходимо, но я хочу защитить вызовы api, поскольку он может получить доступ к конфиденциальным данным, и я не могу использовать sesions или jwt, потому что я не могу хранить их в браузере.
Пирамида
@Thepyramid Не имеет значения, что делает вызов API на стороне сервера, особенно если сторона сервера выполняет еще один вызов API 2-го уровня. Важная часть - рассматривать ваш сервер не как прокси, а как приложение.
Eugen Rieck
не могли бы вы объяснить, как сделать приложение, а не прокси
Пирамида
1
Я имею в виду: чтобы получить приличный уровень безопасности, вам необходимо использовать все инструменты, которые есть в веб-приложении: сеансы, база данных аутентификации, бизнес-логика. Если этого не делать и просто рассматривать свой сервер как способ передачи запросов на другой сервер, вы просто используете его как прокси для этого другого сервера и ограничены любой безопасностью, которую предлагает другой сервер.
Eugen Rieck
1
@PirateApp Злоумышленник может легко проигнорировать заголовки CSRF. Они работают только в том случае, если конечным устройством является браузер без исправлений
Eugen Rieck
12

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

В качестве альтернативы многие системы создают ожидаемые токены доступа или ключи (например, youtube, facebook или twitter), используя какую-то систему учетных записей api. В таких случаях ваш клиент должен каким-то образом хранить их в клиенте.

Затем нужно просто добавить проверку сеанса в вашу структуру REST и выбросить исключение. Если это вообще возможно, код состояния (для успокоения) будет ошибкой 401.

gview
источник
8
Хотя ничто не мешает им посмотреть на заголовки и воспроизвести их.
cdmckay
1
@cdmckay - токен должен соответствовать токену, хранящемуся в сеансе. Простое воспроизведение заголовка приведет к ответу «Неавторизованный», если он поступает из другого сеанса.
Андрей Волгин
3
Они по-прежнему могут использовать тот же сеанс и изменять запросы до их отправки в API, хотя ... или даже с помощью консоли во время выполнения генерировать вызов с соответствующими заголовками / полями, изменяя только те части, которые вам нужны ...
Поттер Рафед
2
@PotterRafed: если пользователь получает доступ к своему собственному действующему сеансу, он вызывается с помощью приложения, а не атакует его. Цель аутентификации - предотвратить доступ к сеансам / данным других пользователей .
Андрей Волгин
@AndreiVolgin: да, достаточно честно, но это все еще уязвимость
Поттер Рафед
9

Сейчас существует открытый стандарт под названием «JSON Web Token»,

см. https://jwt.io/ и https://en.wikipedia.org/wiki/JSON_Web_Token

JSON Web Token (JWT) - это открытый стандарт на основе JSON (RFC 7519) для создания токенов, которые утверждают некоторое количество утверждений. Например, сервер может сгенерировать токен с утверждением «зарегистрирован как администратор» и предоставить его клиенту. Затем клиент может использовать этот токен, чтобы доказать, что он вошел в систему как администратор. Токены подписаны ключом сервера, поэтому сервер может проверить, является ли токен законным. Маркеры разработаны так, чтобы быть компактными, безопасными для URL-адресов и использоваться, особенно в контексте единого входа (SSO) веб-браузера. Утверждения JWT обычно могут использоваться для передачи идентификационных данных аутентифицированных пользователей между поставщиком удостоверений и поставщиком услуг или любых других типов утверждений в соответствии с требованиями бизнес-процессов. [1] [2] Токены также могут быть аутентифицированы и зашифрованы. [3] [4]

bbozo
источник
Что может помешать пользователю скопировать свой токен и использовать его в любом другом ответе?
Улад Kasach
1
@UladKasach, если честно, я никогда особо не разбирался в них, но, кстати, они имеют срок действия, уникальны для вашего пользователя и зашифрованы с помощью SSL (что вы, конечно, практикуете), это точно такая же идея, что и oauth afaik
bbozo
3

Простите @MarkAmery и Евгения, но это неверно.

Ваше js + html (клиентское) приложение, работающее в браузере, МОЖЕТ быть настроено для исключения несанкционированных прямых вызовов API следующим образом:

  1. Первый шаг: настройте API для требования аутентификации. Клиент должен сначала идентифицировать себя через сервер (или какой - либо другой сервер безопасности) , например , с просьбой человека пользователя предоставить правильный пароль.

Перед аутентификацией вызовы API не принимаются.

Во время аутентификации возвращается «токен».

После аутентификации будут приниматься только вызовы API с "токеном" аутентификации.

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

  1. Второй шаг: теперь настройте дополнительный API безопасности, который будет вызываться в течение короткого времени после того, как клиентское приложение js + html было первоначально запрошено с сервера. Этот «обратный вызов» сообщит серверу, что клиент был успешно загружен. Ограничьте вызовы REST API для работы только в том случае, если клиент был запрошен недавно и успешно.

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

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

(Заголовок вопроса: «Как мне защитить вызовы REST API», и, судя по большей части того, что вы говорите, это ваша главная проблема, а не буквальный вопрос, КАК вызывается ваш API, а скорее КЕМ, правильно? )

пашуте
источник
5
Второй пункт не имеет смысла. Если злоумышленнику нужно загрузить ваше приложение, он это сделает (ваш обратный вызов виден). А потом атака.
Андрей Волгин
Пункт 2 является дополнением к пункту 1. Злоумышленнику по-прежнему требуется аутентификация. Пункт 2 только добавляет к этому необходимость фактической загрузки html-приложения для авторизации. Таким образом, прямой вызов API без приложения (предположительно доступ и загрузка только после аутентификации) невозможен. Это то, что было запрошено в этом вопросе.
пашуте
Вы можете просто разрешить запросы только из вашего домена.
Андрей Волгин
Это ограничивает вызовы только внутри домена, поэтому теперь пользователи javascript-приложения браузера должны находиться внутри домена (вероятно, это не то, чего хотел knd), и эти пользователи все еще могут вызывать API напрямую через curl.
pashute 03
2
Вы, кажется, упускаете из виду, что ЧТО бы вы ни попросили браузер сделать, злоумышленник может скопировать его - чтобы браузер сделал это, он должен быть читаемым.
Ойген Рик
1
  1. Установите переменную SESSION на сервере, когда клиент впервые загружает ваш index.html(или backbone.jsт. Д.)

  2. Проверяйте эту переменную на стороне сервера при каждом вызове API.

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

Alex
источник
0

Вот что я делаю:

  1. Защитите API с помощью HTTP-заголовка с такими вызовами, как X-APITOKEN:

  2. Используйте переменные сеанса в PHP. Создайте систему входа в систему и сохраните токен пользователя в переменных сеанса.

  3. Вызовите код JS с Ajax в PHP и используйте переменную сеанса с curl для вызова API. Таким образом, если переменная сеанса не установлена, она не будет вызывать, а код PHP содержит токен доступа к API.

Павнит Сингх
источник