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

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

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

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

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

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

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

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

  1. Когда get-csrf-token.js?apiKey=abc123 наш get-csrf-token.js?apiKey=abc123 :

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

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

    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. Вместо этого обычный браузер может загружать его только с помощью (или динамического эквивалента), а затем запускает код. Конечно, ваш сервер не должен поддерживать Cross-Origin Resource Sharing и JSONP для сгенерированного JavaScript.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Interesting Posts

DataTrigger не изменяет свойство Text

Есть ли способ сделать мой жесткий диск недоступным для всех, кроме меня?

Связывание видимости для DataGridColumn в WPF

Asus x551M отключился и не появится

Как переключить ddrescue из `/ dev / sdq1` в` / dev / sdq`, если я уже сделал резервную копию данных из `/ dev / sdq1`?

У __LINE__ __FILE__ эквиваленты существуют в C #?

Что такое хорошо для?

Получение шрифтов, размеров, жирного шрифта, … и т. Д.

Ионный 2: Кордова недоступна. Обязательно включите cordova.js или запустите в устройстве / симуляторе (работает в эмуляторе)

Как предотвратить дублирование пользовательских свойств в Firebase?

Как использовать платную версию моего приложения в качестве «ключа» для бесплатной версии?

Существует ли структура URI для запуска приложений Windows Store из браузера?

setState не обновляет состояние сразу

Как изменить пользователя в WinSCP?

Как назначить сочетание клавиш для записанного макроса в Sublime Text

Давайте будем гением компьютера.