Чтоб было понятно, приведу простой пример, как атака может выглядеть на практике.
Предположим есть некий сайт, на котором существуют внутренние виртуальные денежные единицы. Допустим модератор может начислять их отдельному клиенту post запросом, такой формы
<form action="" method="post">
<input type="text" name="client_login" />
<input type="text" name="payment_amount" />
<input type="submit" value="пополнить" />
</form>
Вот такой способ - яркий пример CSRF уязвимости. "Доброжелатель" может каким либо способом заманить админа на свою, подготовленную страницу. Методы соц инженерии мы обсуждать не будем, это отдельный разговор. :) Для него важно только чтоб админ в этот момент был авторизован на атакуемом сайте. Все параметры формы предсказуемы, и легко можно подделать запрос. На подготовленной странице делается скрытая форма, с теми же полями и нужными значениями, а в action указывается урл атакуемого скрипта, в target формы задается имя невидимого ифрейма, чтобы обеспечить передачу скрытно, без перезагрузки страницы. Вот и всё, админ заходит на вредоносную страницу, и ни о чем не подозревая выполняет авторизованный запрос. Злоумышленник пополнил свой счёт :)
Защита от таких атак очень проста, нужно в форму добавить поле с секретным значением (csrf token), уникальным для каждого клиента, которое невозможно предугадать. Особенность этой атаки в том, что можно браузер заставить послать любой запрос, но не возможно получить ответ, соответственно нельзя получить токен.
Еще существует вариант защиты с проверкой referer, но полагаться на него нельзя, т.к. этот заголовок не является обязательным, он может быть отключен в настройках браузера, или резаться каким нибудь анти шпионом.
Приведу простой вариант реализации защиты
session_start();
if(!empty($_POST['payment_amount']) && empty($_SESSION['csrf_token']) || $_SESSION['csrf_token'] != $_POST['csrf_token'])
die('invalid request');
if(isset($_POST['client_login'], $_POST['payment_amount'])) {
}
if(empty($_SESSION['csrf_token']))
$_SESSION['csrf_token'] = md5($user_id . microtime(true));
?>
<input type="text" name="client_login" />
<input type="text" name="payment_amount" />
<input type="hidden" name="csrf_token" value="<?=$_SESSION['csrf_token']?>" />
<input type="submit" value="пополнить" />
</form>