Опять сломали!!!

Ревизия 12331 нарушила обратную совместимость функции wp_nonce_field()

В очередной раз разработчики ломают совместимость… Хотя справедливости ради стоит отметить, что затронуты будут далеко не все плагины, а только те, которые полагаются на то, что функция wp_nonce_field() создаёт в форме поле с именем _wp_http_referer.

Итак, что же случилось?

Еще начиная с  2.0.3 разработчики рекомендуют использовать функцию wp_nonce_field() для предотвращения атак CSRF. Эта функция создаёт два новых скрытых поля в форме: _wpnonce (это имя можно изменить) и _wp_http_referer. Первое поле — это nonce (number used once), его значение и используется для защиты от CSRF; второе поле — URL страницы, с которой отправляется форма.

Плагины, которые отправляют POST-запросы файлу /wp-admin/admin-post.php (как и положено), обычно используют подобный код:

[-]
View Code PHP
// Защита от CSRF
check_admin_referer('...');

// Здесь проверяем и сохраняем данные

// Редирект на страницу, с который пришел запрос
$referer = stripslashes($_POST['_wp_http_referer']);
// или $referer = wp_get_referer(); что в данном случае одно и то же
add_query_arg(array('updated' => 1), $referer);
wp_redirect($referer);
die();

Проблема в том, что в  2.9 такой код работать не будет. Сломали.

Что изменилось: в  2.8.x функция wp_nonce_field() вызывала функцию wp_referer_field(), которая и вставляла поле с именем _wp_http_referer. В WP 2.9 wp_nonce_field() вызывает другую функцию — wp_original_referer_field() — которая вставляет поле с именем _wp_original_http_referer и абсолютно другим смыслом: поле хранит адрес страницы, с которой пользователь перешел на страницу с формой. Переход по полю _wp_original_http_referer не имеет никакого смысла, так как пользователь мог перейти на страницу с формой вообще с другого сайта:

[-]
View Code HTML
<input type="hidden" value="ef08c8f103" name="_wpnonce" id="_wpnonce"/>
<input type="hidden" value="http://www.google.ru/" name="_wp_original_http_referer"/>

Что характерно, функция wp_get_referer(), вызываемая (косвенно) из check_admin_referer(), не изменилась и по-прежнему пытается отыскать адрес ссылающейся страницы в $_REQUEST['_wp_http_referer']:

[-]
View Code PHP
function wp_get_referer() {
    $ref = '';
    if ( ! empty( $_REQUEST['_wp_http_referer'] ) )
        $ref = $_REQUEST['_wp_http_referer'];
    else if ( ! empty( $_SERVER['HTTP_REFERER'] ) )
        $ref = $_SERVER['HTTP_REFERER'];

    if ( $ref !== $_SERVER['REQUEST_URI'] )
        return $ref;
    return false;
}

В общем, если в коде нужно использовать _wp_http_referer, вместе с wp_nonce_field() придётся вызывать wp_referer_field(), так как полагаться на $_SERVER['HTTP_REFERER'] (именно его будет теперь проверять wp_get_referer()) не стоит: поле часто блокируется браузерами или брэндмауэрами.

Я написал в Trac свои мысли по этому поводу, но что-то меня терзают смутные сомнения, что патч откатят.

Добавить в закладки

Связанные записи

Автор: Vladimir; опубликовано в: WordPress; метки: WordPress, безопасность, ошибка
9
Дек
2009

RSS Комментарии к статье «Опять сломали!!!» (1)

  1. Патч всё-таки откатили. Это не может не радовать.

Извините, комментарии закрыты.