Аутентификация REST и предоставление ключа API


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

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

6 87

6 ответов:

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

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

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

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

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

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

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

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

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

    4. Установите ответ не кэшироваться, добавьте файл cookie и верните скрипт, например:

      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.');
      }
      

    Примечания:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. клиент имеет открытый ключ, им можно поделиться с кем угодно, не так ли материи, так что вы можете встроить его в javascript. Это используется для идентификации пользователя на сервере.
  2. сервер имеет секретный ключ, и этот секрет должен быть защищен. Следовательно, аутентификация с общим ключом требует, чтобы вы могли защитить свой секрет ключ. Таким образом, публичный клиент javascript, который подключается непосредственно к другой обслуживание невозможно, потому что вам нужен посредник сервера, чтобы берегите тайну.
  3. сервер подписывает запрос, используя некоторый алгоритм, который включает секрет ключ (секретный ключ-это что-то вроде соли) и предпочтительно метка времени, после чего отправляет запрос в службу. Метка времени предназначена для предотвращения атак" повтора". Подпись запроса действительна только в течение приблизительно n секунд. Вы можете проверить это на сервере, получив заголовок timestamp, который должен содержать значение метка времени, которая была включена в подпись. Если эта временная метка истекла, запрос завершается неудачей.
  4. сервис получает запрос, который содержит не только подпись но также и все поля, которые были подписаны обычным текстом.
  5. затем служба подписывает запрос таким же образом, используя общий доступ. секретный ключ и сравнивает подписи.

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

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

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

Идентификатор сеанса передается только один раз, и это должно быть по протоколу SSL.

Смотрите пример здесь

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

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

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

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

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