Как предотвратить CSRF в приложении RESTful?



подделка межсайтовых запросов (CSRF) обычно предотвращается одним из следующих методов:




  • Проверьте referer-спокойный, но ненадежный

  • вставьте токен в форму и сохраните токен в сеансе сервера-не очень RESTful

  • загадочный один раз URIs-не успокоительный по той же причине, что и токены

  • отправить пароль вручную для этого запроса (не кэшированный пароль, используемый с http auth) - RESTful но не удобно


моя идея состоит в том, чтобы использовать секрет пользователя, загадочный, но статический идентификатор формы и JavaScript для генерации токенов.



<form method="POST" action="/someresource" id="7099879082361234103">
<input type="hidden" name="token" value="generateToken(...)">
...
</form>




  1. GET /usersecret/john_doe извлекается JavaScript от аутентифицированного пользователя.

  2. ответ: OK 89070135420357234586534346 этот секрет концептуально статичен, но может быть изменен каждый день/час ... повысить безопасность. Это единственная конфиденциальная вещь.

  3. читать загадочные (но статические для всех пользователей!) идентификатор формы с JavaScript, обработайте его вместе с секретом пользователя:generateToken(7099879082361234103, 89070135420357234586534346)

  4. Отправьте форму вместе с сгенерированным токеном на сервер.

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


что-то не так с этим подходом, несмотря на то, что он не работает без JavaScript?



дополнение:



648   6  

6 ответов:

есть много ответов здесь, и проблемы с довольно многими из них.

вещи, которые вы не должны делать:

  1. Если вам нужно прочитать токен сеанса из JavaScript, вы делаете что-то ужасно неправильное. Ваш идентификатор сеанса cookie всегда должен иметь HTTPOnly, поэтому он недоступен для скриптов.

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

  2. идентификатор сеанса не должен быть записан в содержимое страницы. Это по тем же причинам, что и HTTPOnly. Это означает, что ваш токен csrf не может быть вашим идентификатором сеанса. Они должны быть разными ценностями.

вещей, которые вы должны делать:

  1. соблюдать OWASP в!--22-->:

  2. в частности, если это приложение REST вы можете требуется двойная подача токенов CSRF:

просто создайте что-то криптографически случайное, сохраните его в кодировке ASCII Hex или Base64 и добавьте его в виде файла cookie и в свои формы, когда сервер возвращает страницу. На стороне сервера убедитесь, что значение cookie соответствует форме значение. Вуаля, вы убили CSRF, избежали дополнительных запросов для своих пользователей и не открыли себя для большего количества уязвимостей.

вам определенно нужно некоторое состояние на сервере для аутентификации / авторизации. Это не обязательно должен быть сеанс http, хотя вы можете хранить его в распределенном кэше (например, memcached) или базе данных.

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

эта схема использует один идентификатор в сессии.

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

кроме того, не создавайте токены в JS. Любой может скопировать код и запустить его из другого домена, чтобы атаковать ваш сайт.

Я правильно понял:

  • вы хотите защиту от CSRF для пользователей, вошедших в систему через куки.
  • и в то же время вы хотите RESTful интерфейс для Basic, OAuth и Digest аутентифицированных запросов от приложений.

Так, почему бы не проверить если пользователи вошли в систему через cookie и применить CSRF только тогда?

Я не уверен, но возможно для другого сайта подделать такие вещи, как Basic auth или заголовки?

насколько я знаю, CSRF-это все о cookies? RESTful auth не происходит с cookies.

статический идентификатор формы не обеспечивает никакой защиты вообще; злоумышленник может получить его сам. Помните, что злоумышленник не ограничен использованием JavaScript на клиенте; он может получить статический идентификатор формы на стороне сервера.

Я не уверен, что полностью понимаю предложенную защиту; где же GET /usersecret/john_doe откуда? Это часть страницы JavaScript? Это буквальный предложил URL-адрес? Если да, то я предполагаю, что username это не секрет, а значит, что evil.ru можно восстановить секреты пользователей если ошибка браузера или плагина позволяет получать междоменные запросы. Почему бы не сохранить секрет пользователя в файле cookie при аутентификации, а не позволить любому, кто может сделать кросс-домен, получить его?

Я бы прочитала "надежная защита для Межсайтовой подделки" очень тщательно, прежде чем я реализовал свою собственную систему аутентификации, которую я хотел быть устойчивым к CSRF. Фактически, я бы вообще пересмотрел реализацию своей собственной системы аутентификации.

есть несколько методов в CSRF профилактика шпаргалка это может быть использовано службой restful. Наиболее спокойным безгосударственным смягчением CSRF является использование источника или HTTP referer чтобы убедиться, что запросы исходят из домена, которому Вы доверяете.

что-то не так с этим подходом, несмотря на то, что он не работает без JavaScript?

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

Если вы хотите быть спокойным, запрос должен содержать всю информацию о том, как его обрабатывать. Способы, которыми вы можете это сделать:

  • добавить файл cookie токена csrf с вашим клиентом REST и отправьте тот же токен в скрытом вводе с вашими формами. Если служба и клиент находятся в разных доменах, необходимо совместно использовать учетные данные. На сервисе вы должны сравнить 2 токена, и если они одинаковы, запрос действителен...

  • вы можете добавить файл cookie токена csrf с вашим сервисом REST и отправить тот же токен с представлениями ваших ресурсов (скрытые входы и т. д...). Все остальное то же самое, что и в конце предыдущего решения. Это решение находится на грани успокоения. (Это нормально, пока клиент не вызовет службу для изменения файла cookie. Если файл cookie является только http, клиент не должен знать об этом, если это не так, то клиент должен установить его.) Вы можете сделать более сложное решение, если вы добавляете разные токены в каждую форму и добавляете время истечения срока действия в куки. Вы можете отправить срок действия с формами, поэтому вы будете знать причину, когда токен проверка завершается неудачно.

  • вы можете иметь секрет пользователя (разные для каждого пользователя) в состоянии ресурса на вас службы. Создавая представления, вы можете создать маркер (и время истечения срока действия) для каждой формы. Вы можете создать хэш из фактического токена (и время истечения срока действия, метод, url и т. д...) и секрет пользователя, и отправить этот хэш с формой, а также. Вы держите "секрет пользователя" в секрете, конечно, поэтому вы никогда не отправляете его с формой. После этого, если ваш сервис получает запрос, вы можете сгенерировать хэш из параметров запроса и секрет пользователя снова, и сравнить их. Если они не совпадают, запрос недействителен...

ни один из них не защитит вас, если ваш клиент REST является инъекционным javascript, поэтому вам нужно проверить все свое пользовательское содержимое на HTML-сущности и удалить все из них или всегда использовать TextNodes вместо innerHTML. Вы также должны защитить себя от инъекции SQL и инъекции заголовка HTTP. Никогда использовать простой FTP для обновления вашего сайта. И так далее... Есть много способов внедрить злой код в ваш сайт...

я почти забыл упомянуть, что запросы GET всегда предназначены для чтения службой и клиентом. По службе это очевидно, по настройке клиента любой url в браузере должен приводить к представлению ресурса или нескольких ресурсов, он никогда не должен вызывать метод POST/PUT/DELETE на ресурсе. Например GET http://my.client.com/resource/delete -> DELETE http://my.api.com/resource Это очень-очень плохое решение. Но это очень простой навык, если вы хотите помешать CSRF атак.

Comments

    Ничего не найдено.