Я под угрозой CSRF-атак в форме POST, которая не требует, чтобы пользователь вошел в систему?

Я, вероятно, здесь полный Noob, но я все еще не уверен, что именно атака CSRF (Cross-Site Request Forgery). Поэтому давайте рассмотрим три ситуации...

1) У меня есть форма POST, которую я использую для редактирования данных на моем сайте. Я хочу, чтобы эти данные редактировались только пользователями, которые вошли в систему.

2) У меня есть сайт, который может использоваться как для пользователей, которые вошли в систему, так и для гостей. Части сайта регистрируются только для пользователей, но есть также формы POST, которые могут использоваться всеми пользователями - анонимными и нет (например, стандартная контактная форма). Следует ли защищать контактную форму от атак CSRF?

3) У меня есть сайт, который вообще не имеет системы аутентификации (ну, возможно, это нереально, поэтому давайте скажем, что у него есть админ-сайт, который отделен от остальной части, а часть администратора должным образом защищена), Основная часть сайта используется только анонимными пользователями. Должны ли защищаться формы POST?

В случае 1) ответ явно да. Но в случае 2 и 3 я не знаю (и разница между 2 и 3 даже значительна?).

Ответы

Ответ 1

Существует средство CSRF, когда вредоносный HTML или JavaScript, предназначенный для вашего сайта, встроен в другую страницу HTML (или сообщение электронной почты) который успешно выполнен.

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

<form action="http://yoursite.com/transferfunds" method="post">
    Your name: <input type="text"><br>
    Your age: <input type="text"><br>
    <input type="submit">
    <input type="hidden" name="amount" value="1000">
    <input type="hidden" name="toaccount" value="12345678">
</form>

Обратите внимание, что действие указывает на ваш сайт и что скрытые входы содержат необходимую информацию POST. В этом примере мы попытаемся передать фонд в размере 1000 (в любой валюте) на номер счета 12345678. Если вам требуется логин в вашей форме, а также на самом деле проверяет его, то указанное выше, конечно, будет успешно выполнено только в том случае, если у незнакомого пользователя есть недавно зарегистрировался на вашем веб-сайте, но еще не вышел из системы, или сеанс еще не истек.

Чтобы этого не случилось, лучше всего добавить к форме токен, основанный на запросе, и проверить его на стороне сервера. То есть генерировать длинную, уникальную и невозможную догадываться случайную строку, которую вы храните в сеансе и вставляете в качестве элемента <input type="hidden"> формы. Когда форма отправлена, сравните представленное значение токена с тем, которое уже находится в сеансе (и сразу же удалите его в сеансе). Чтобы сделать еще один шаг, используйте CAPTCHA.

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

<form name="delete" action="admin/deleteusers" method="post"></form>
<script>document.form.delete.submit();</script>

Всякий раз, когда вы - являетесь администратором - просматриваете страницу с комментарием с формой (невидимой!) и script внутри, то она будет успешно выполнена.

Предотвращение XSS на самом деле довольно просто. Просто HTML-escape любой пользовательский вход (т.е. URL-адрес запроса, заголовки запросов, параметры запроса и тело запроса) перед их отображением на веб-странице. В PHP вы можете использовать htmlspecialchars() для этого, а в Java/JSP - JSTL fn:escapeXml(). Таким образом, каждый из < будет преобразован в &lt; и > в &gt;, что сделает любой введенный HTML/JS будет отображаться буквально как есть и, следовательно, не может быть выполнен.