Мы предоставляем API, который партнеры могут использовать только на тех доменах, которые они зарегистрировали у нас.Его содержание частично общедоступно (но желательно только для показа на доменах, которые мы знаем), но в основном является частным для наших пользователей.Итак:
Чтобы определить , что показывается , наш пользователь должен войти в систему вместе с нами, но это обрабатывается отдельно.
Чтобы определить , где данные отображаются, открытый ключ API используется для ограничения доступа к доменам, которые мы знаем, и, прежде всего, для обеспечения конфиденциальности данных пользователя.не уязвим для CSRF .
Этот ключ API действительно виден всем, мы не аутентифицируем нашего партнера любым другим способом, и нам не нужен REFERER .Тем не менее, это безопасно:
Когда наш get-csrf-token.js?apiKey=abc123
запрашивается:
Найдите ключ abc123
в базе данных и получитесписок допустимых доменов для этого ключа.
Найдите файл проверки CSRF.Если он не существует, сгенерируйте безопасное случайное значение и поместите его в файл cookie сеанса только для HTTP .Если файл cookie существовал, получите существующее случайное значение.
Создайте токен CSRF из ключа API и случайное значение из файла cookie, а подпишите его .(Вместо того, чтобы хранить список токенов на сервере, мы подписываем значения. Оба значения будут доступны для чтения в подписанном токене, это нормально.)
Установите для ответа значение notкэшируйте, добавьте 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">
(или динамического эквивалента), а затем запустит код.Конечно, ваш сервер должен не поддерживать Cross-Origin Resource Sharing или 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 пользователя и, следовательно, могут только извлекать общедоступные данные.Это те же данные, которые серверный сценарий мог бы получить непосредственно с сайта партнера.
Когда пользователь входит в систему, задайте какой-либо пользовательский файл cookie любым удобным для вас способом.,(Возможно, пользователь уже вошел в систему до того, как запросили JavaScript.)
Все последующие запросы API к серверу (включая запросы GET и JSONP) должны включать токен CSRF, проверку CSRF.cookie, и (если вход в систему) пользовательский cookie.Теперь сервер может определить, следует ли доверять запросу:
Наличие действительного токена CSRF гарантирует, что JavaScript был загружен из ожидаемого домена, , если загруженочерез браузер.
Наличие токена CSRF без , проверочный файл cookie указывает на подделку.
Наличие как токена CSRF, так и файла cookie проверки CSRF ничего не гарантирует: это может быть либо поддельный запрос на стороне сервера, либо действительный запрос от браузера.(Это не может быть запрос от браузера, сделанный из неподдерживаемого домена.)
Наличие cookie пользователя гарантирует, что пользователь вошел в систему, но не гарантирует, что пользователь являетсячлен данного партнера, а также то, что пользователь просматривает правильный веб-сайт.
Наличие файла cookie пользователя без файла проверки CSRF указывает на подделку.
Наличие файла cookie пользователя гарантирует, что текущий запрос выполняется через браузер.(Предполагая, что пользователь не будет вводить свои учетные данные на неизвестном веб-сайте, и предполагая, что мы не заботимся о том, чтобы пользователи использовали свои собственные учетные данные для выполнения какого-либо запроса на стороне сервера.) Если у нас также есть файл проверки CSRF,затем этот файл проверки CSRF также был получен с помощью браузера.Затем, если у нас также есть токен CSRF с действительной подписью, и случайное число в файле cookie проверки CSRF совпадает с числом в этом токене CSRF, тогда JavaScript для этого токена былтакже получен во время того же самого более раннего запроса, во время которого был установлен файл cookie CSRF, следовательно, также с использованием браузера.Это также подразумевает, что приведенный выше код JavaScript был выполнен до того, как токен был установлен, и что в то время домен был действительным для данного ключа API.
Итак: сервер теперь может безопасно использовать ключ API изподписанный токен.
Если в какой-то момент сервер не доверяет запросу, возвращается 403 Запрещено.Виджет может ответить на это, показывая пользователю предупреждение.
Подписывать cookie-файл проверки CSRF не требуется, поскольку мы сравниваем его сподписанный токен CSRF.Отказ от подписи файла cookie делает каждый HTTP-запрос короче, а проверка сервера - немного быстрее.
Сгенерированный токен CSRF действует неопределенно долго, но только в сочетании с файлом cookie проверки, поэтому действует до закрытия браузера.
Мы могли бы ограничить время жизни подписи токена.Мы можем удалить cookie проверки CSRF, когда пользователь выходит из системы, чтобы удовлетворить рекомендацию OWASP .И чтобы не делить случайное число для нескольких пользователей между несколькими партнерами, можно добавить ключ API к имени файла cookie.Но даже тогда невозможно легко обновить файл cookie проверки CSRF при запросе нового токена, поскольку пользователи могут просматривать один и тот же сайт в нескольких окнах, совместно используя один файл cookie (который при обновлении будет обновляться во всех окнах, после чегоТокен JavaScript в других окнах больше не будет соответствовать этому отдельному файлу cookie.
Для тех, кто использует OAuth, см. Также OAuth и клиентские виджеты , из которых я получил идею JavaScript.Для серверной стороны использования API, в котором мы не можем полагаться на код JavaScript для ограничения домена, мы используем секретные ключи вместо открытых ключей API.