2010-03-26 4 views
44

У меня есть веб-сайт, где люди могут размещать вотум так:CSRF (запрос Межсайтовые подлог) пример атаки и профилактика в PHP

http://mysite.com/vote/25 

Это поместит голосование по пункту 25, я хочу только сделайте это доступным для зарегистрированных пользователей, и только если они захотят это сделать. Теперь я знаю, когда кто-то занят на веб-сайте, а кто-то дает им ссылку, как это:

http://mysite.com/vote/30 

то голосование будет места для него по этому пункту без его желания сделать это.

Я прочитал explanation on the OWASP website, но я не очень понимаю, что

Это пример CSRF, и как я могу предотвратить это. Лучшее, что я могу придумать, это добавить что-то к ссылке, как хэш. Но это будет очень раздражать, чтобы положить что-то на конец всех ссылок. Нет другого способа сделать это.

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

ответ

82

Это может стать примером CSRF, если:

  • , что ссылка извлекается (через <img> тега, например): подделкой
  • с другого сайта: межсайтовому


Например, если бы я мог вставить этот тег <img> в исходный код HTML stackoverflow (и я могу, как stackover потока позволяет использовать <img> теги в своих постах):

<img src="http://mysite.com/vote/30" /> 

Вы бы просто голосовали за этот пункт ;-)


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

Основная идея будет:

  • При генерации страницы:
    • генерировать уникальный маркер
    • хранить его в сессии пользователя
    • и поместить его в звеньях страница - которая будет выглядеть так: http://mysite.com/vote/30?token=AZERTYUHQNWGST
  • Когда страница голосования называется:
    • Проверьте маркер присутствует в URL
    • Проверьте, если он присутствует в сеансе пользователя
    • Если нет => не зарегистрированы на голосование

идея есть:

  • токены не имеют длительный срок службы, и трудно угадайте
  • Что означает, что ваш атакующему:
    • имеет только окно на несколько минут, в течение которого его инъекции будет действовать
    • должны быть хорошо угадывает ^^
    • будет генерировать другая страница для каждого пользователя.


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

Но здесь, вы должны выбрать между безопасностью и удобным для пользователя ...


Другая идея (это не совсем безопасно, но и помогает против парней бы не знаю, как заставить запрос POST), будет принимать только запросы POST, когда люди голосуют:

  • браузер посылает запросы GET для инжектированных тегов
  • Поскольку этот URL модифицирует некоторые данные, во всяком случае, он не должен работать с GET, но только с POST

Но обратите внимание, что это не совсем безопасно: это (возможно?) можно заставить/подделать запрос POST с некоторым количеством Javascript.

+2

Вы правы, это о том, как легко подделать GET как запрос POST. Хотя я не согласен с тем, что необходимо иметь токен, который истекает. Если злоумышленник может получить ваши данные сеанса, у вас больше проблем, чем некоторых дополнительных голосов. Но ваше исправление по-прежнему работает, поскольку ключ состоит только в том, чтобы иметь токен/случайное значение в Cookie и в данных запроса (сохраненных в файле cookie или привязанных к сеансу пользователя). – MyGGaN

+0

Благодарим вас за предложения. Я буду менять все ссылки, чтобы иметь этот токен. Я должен согласиться, что это очень безопасный метод. Однако я не собираюсь выполнять истечение срока годности, я согласен с MygGaN в этом. –

+0

У любого из вас, ребят, есть идея, что делать, когда я использую AJAX для голосования. Должен ли я просто повторно использовать один и тот же ключ, пока пользователь находится на странице, и только генерирует новый токен, когда он обновляется. Или я должен поставить новый токен для всех ссылок всякий раз, когда проводится голосование. –

17

Во-первых, запрос GET не должен использоваться для изменения состояний на сервере, поэтому для вашей службы голосования я бы рекомендовал POST/PUT. Это всего лишь ориентир, но один кливер.

Итак, на ваш вопрос CSRF является проблемой клиента, поэтому не имеет значения, какой язык сервера вы используете (PHP в вашем случае). Стандартное исправление одинаков и выполняется следующим образом: иметь случайное значение в URI/POST-данных и такое же значение в заголовке Cookie. Если в этих матчах вы можете быть уверены, что нет CSRF. Существует много информации о том, как это можно сделать здесь, например, в StackOverflow. this one.
Удачи!

4

OWASP имеет CSRFGuard для PHP и ESAPI для PHP, которые я написал давно для XMB -> UltimaBB -> GaiaBB.

http://code.google.com/p/gaiabb-olpc/source/search?q=function+get_new_token&origq=function+get_new_token&btnG=Search+Trunk

Кажется, что некоторые другие очистили этот код и позволили более сильным лексемы:

https://www.owasp.org/index.php/PHP_CSRF_Guard

спасибо, Andrew