Проверка подлинности REST и отображение ключа API

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

Если я создаю API RESTful, и я хочу его защитить, один из методов, который я видел, - использовать токен безопасности. Когда я использовал другие API-интерфейсы, был токен и общий секрет... имеет смысл. Что я не понимаю, запросы на операцию службы отдыха выполняются через javascript (XHR/Ajax), что должно помешать кому-то обнюхивать это с помощью чего-то простого, такого как FireBug (или "источник просмотра" в браузере) и копируя ключ API, а затем выдавая себя за человека, использующего ключ и секрет?

Ответ 1

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

Ответ 2

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

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

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

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

  • Когда запрашивается наш get-csrf-token.js?apiKey=abc123:

    • Посмотрите ключ abc123 в базе данных и получите список допустимых доменов для этого ключа.

    • Найдите файл cookie проверки CSRF. Если он не существует, создайте безопасное случайное значение и поместите его в только для HTTP файлов cookie сеанса. Если файл cookie существует, получите существующее случайное значение.

    • Создайте токен CSRF из ключа API и случайное значение из файла cookie, а отметьте его. (Вместо того, чтобы хранить список токенов на сервере, мы подписываем значения. Оба значения будут считаны в подписанном токене, это прекрасно.)

    • Установите ответ, чтобы он не был кэширован, добавьте файл cookie и верните script как:

      var apiConfig = apiConfig || {};
      if(document.domain === 'expected-domain.com' 
            || document.domain === 'www.expected-domain.com') {
      
          apiConfig.csrfToken = 'API key, random value, signature';
      
          // Invoke a callback if the partner wants us to
          if(typeof apiConfig.fnInit !== 'undefined') {
              apiConfig.fnInit();
          }
      } else {
          alert('This site is not authorised for this API key.');
      }
      

    Примечания:

    • Вышеописанная информация не препятствует ошибке на стороне сервера script, но гарантирует только совпадение домена с запросом браузера.

    • та же самая политика происхождения для JavaScript гарантирует, что браузер не сможет использовать XHR (Ajax) для загрузки, а затем проверить исходный код JavaScript. Вместо этого обычный браузер может загружать его только с помощью <script src="https://our-api.com/get-csrf-token.js?apiKey=abc123"> (или динамического эквивалента), а затем запускает код. Конечно, ваш сервер не должен поддерживать Cross-Origin Resource Sharing и JSONP для сгенерированного JavaScript.

    • Браузер script может изменить значение document.domain перед загрузкой вышеуказанного script. Но одна и та же политика происхождения допускает сокращение домена, удаляя префиксы, например, переписывая subdomain.example.com только example.com или myblog.wordpress.com в wordpress.com, или в некоторых браузерах даже bbc.co.uk до co.uk.

    • Если файл JavaScript извлекается с использованием некоторой серверной части script, тогда сервер также получит файл cookie. Тем не менее, сторонний сервер не может заставить браузер пользователей связывать этот файл cookie с нашим доменом. Следовательно, куки-маркер CSRF и валидация, которые были выбраны с использованием серверной стороны script, могут использоваться только последующими вызовами на стороне сервера, а не в браузере. Однако такие вызовы на стороне сервера никогда не будут включать cookie пользователя, и, следовательно, могут получать только общедоступные данные. Это те же данные, что серверная сторона script может соскоблить с веб-сайта партнера.

  • Когда пользователь входит в систему, установите некоторый файл cookie пользователя любым способом. (Возможно, пользователь уже зарегистрировался до того, как был запрошен JavaScript.)

  • Все последующие запросы API на сервер (в том числе запросы GET и JSONP) должны включать токен CSRF, куки файл проверки CSRF и (при входе в систему) cookie пользователя. Теперь сервер может определить, нужно ли доверять запросу:

    • Наличие допустимого токена CSRF гарантирует, что JavaScript был загружен из ожидаемого домена, если он загружен браузером.

    • Наличие токена CSRF без файла cookie проверки указывает на подделку.

    • Наличие как токена CSRF, так и файла cookie валидации CSRF ничего не гарантирует: это может быть либо поддельный запрос на стороне сервера, либо действительный запрос от браузера. (Это не может быть запрос из браузера, сделанного из неподдерживаемого домена.)

    • Наличие cookie пользователя гарантирует, что пользователь вошел в систему, но не гарантирует, что пользователь является членом данного партнера, и что пользователь просматривает правильный веб-сайт.

    • Наличие файла cookie пользователя без файла cookie проверки CSRF указывает на подделку.

    • Наличие cookie пользователя гарантирует, что текущий запрос будет выполнен через браузер. (Предполагая, что пользователь не будет вводить свои учетные данные на неизвестном веб-сайте и предположим, что мы не заботимся о том, чтобы пользователи использовали свои собственные учетные данные, чтобы сделать запрос на стороне сервера.) Если у нас также есть файл cookie проверки CSRF, то также был получен куки файл проверки CSRF используя браузер. Затем, если у нас также есть токен CSRF с действительной сигнатурой, а случайное число в cookie-валиде CSRF соответствует тому, что указано в этом токене CSRF, тогда JavaScript для этого токена также был получен во время того же самого более раннего запроса, в течение которого CSRF cookie был установлен, следовательно, также используя браузер. Это также подразумевает, что вышеуказанный код JavaScript был выполнен до того, как был установлен токен, и что в то время домен был действителен для данного ключа API.

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

    • Если в любой момент сервер не доверяет запросу, возвращается 403 Forbidden. Виджет может ответить на это, показывая предупреждение пользователю.

Не нужно подписывать файл cookie проверки CSRF, поскольку мы сравниваем его с подписанным токеном CSRF. Не подписание cookie делает каждый HTTP-запрос короче, а проверка сервера немного быстрее.

Сгенерированный токен CSRF действует неограниченно, но только в сочетании с валидацией cookie, так эффективно, пока браузер не будет закрыт.

Мы могли бы ограничить время жизни сигнатуры токена. Мы удалим файл cookie проверки CSRF, когда пользователь выйдет из системы, чтобы встретить рекомендацию OWASP. И чтобы не делиться случайным числом между пользователями между несколькими партнерами, можно добавить ключ API в имя файла cookie. Но даже тогда невозможно легко обновить cookie проверки CSRF при запросе нового токена, так как пользователи могут просматривать один и тот же сайт в нескольких окнах, совместно используя один файл cookie (который при обновлении будет обновляться во всех окнах, после чего JavaScript-токен в других окнах больше не будет соответствовать одному cookie файлу).

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

Ответ 3

Этот вопрос имеет принятый ответ, но для уточнения, общая секретная аутентификация работает следующим образом:

  • Клиент имеет открытый ключ, его можно обменивать с кем угодно, не вопрос, поэтому вы можете вставлять его в javascript. Это используется для идентификации пользователя на сервере.
  • Сервер имеет секретный ключ, и этот секрет ДОЛЖЕН быть защищен. Следовательно, аутентификация с общим ключом требует, чтобы вы могли защитить свой секрет ключ. Таким образом, открытый клиент javascript, который подключается напрямую к другому сервис невозможен, потому что вам нужен посредник сервера для защищать секрет.
  • Сервер подписывает запрос с использованием некоторого алгоритма, который включает в себя секрет (секретный ключ подобен соли), и предпочтительно временная метка затем отправляет запрос на услугу. Временная метка предназначена для предотвращения "повторных" атак. Подпись запроса действительна только в течение n секунд. Вы можете проверить это на сервере, получив заголовок timestamp, который должен содержать значение метки времени, которая была включена в подпись. Если эта временная метка истекла, запрос не работает.
  • Служба получает запрос, который содержит не только подпись но и все поля, которые были подписаны простым текстом.
  • Служба затем подписывает запрос таким же образом, используя общий секретный ключ и сравнивает подписи.

Ответ 4

Я полагаю, вы имеете в виду ключ сеанса, а не ключ API. Эта проблема наследуется от протокола http и называется захват сеанса. Обычным "обходным путем" является, как и на любом веб-сайте, изменение на https.

Чтобы запустить службу REST, вы должны включить https и, возможно, аутентификацию клиента. Но ведь это выходит за рамки идеи REST. REST никогда не говорит о безопасности.

Ответ 5

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

Идентификатор сеанса передается только один раз, и это ДОЛЖНО превышать SSL.

См. пример здесь

Используйте знак nonce и timestamp при подписании запроса, чтобы предотвратить захват сеанса.

Ответ 6

Я постараюсь ответить на вопрос в оригинальном контексте. Поэтому вопрос заключается в том, является ли секретный (API) ключ безопасным для размещения в JavaScript.

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

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

Надеюсь, это поможет.