wp_sanitize_redirect()WP 2.3.0

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

Удаляет недопустимые символы в параметрах URL. Удаляет пробелы!

Чтобы проверить ссылку редиректа, используйте wp_validate_redirect()

Pluggable функция — эту функцию можно заменить из плагина. Это значит, что она будет работать (подключается) только после подключения всех плагинов, а до этого момента функция еще не определена... Поэтому нельзя вызывать эту и зависящие от неё функции прямо из кода плагина. Их нужно вызывать через хук plugins_loaded или позднее, например хук init.

Замена функции (переопределение) — в must-use или обычном плагине можно создать функцию с таким же названием, тогда она заменит текущую функцию.

Работает на основе: wp_kses_no_null()
Основа для: wp_safe_redirect()
1 раз — 0.000309 сек (быстро) | 50000 раз — 0.20 сек (очень быстро) | PHP 7.1.5, WP 4.8.2

Хуков нет.

Возвращает

Строку. Очищенный URL.

Использование

wp_sanitize_redirect( $location );
$location(строка) (обязательный)
URL для перенаправления (редиректа).

Примеры

0

#1 Пример очистки вредоносного URL

$url = 'http://test.example.com/redirect.php?page=%0d%0aContent-Type: text/html%0d%0aHTTP/1.1 200 OK%0d%0aContent-Type: text/html%0d%0aContent-
Length:%206%0d%0a%0d%0a%3Chtml%3EHACKED%3C/html%3E.';

echo wp_sanitize_redirect( $url );

//> http://test.example.com/~arpit/redirect.php?page=Content-Type:text/htmlHTTP/1.1200OKContent-Type:text/htmlContent-Length:%206%3Chtml%3EHACKED%3C/html%3E.
0

#2 Обратите внимание - функция удаляет пробелы

$url = '/inventory/certified new used/';

echo wp_sanitize_redirect( $url ); // /inventory/certifiednewused/

Про атаки с помощью редиректов

Как создается атака

Атака с редиректами осуществляется с помощью вставки вредоносных или недопустимых символов в URL, которые при обработки статуса 3xx (переадресации HTTP) изменяют запрос и влияют на параметры заголовка HTTP "Location" или "Set-Cookie".

Это возможно из-за недостаточной проверки введенных данных на наличие символов: CR (возврат каретки: %0d или \r) и LF (переход на новую строку: %0a или \n).

Например, так сервер может обрабатывать редирект:

<?php
header( "Location: " . $_GET['page'] );

Далее, взломщик может использовать последовательность символов %0d%0a для добавления в заголовок данных, аналогичных представленным ниже:

http://test.example.com/arpit/redirect.php?page=%0d%0aContent-Type: text/html%0d%0aHTTP/1.1 200 OK%0d%0aContent-Type: text/html%0d%0aContent-
Length:%206%0d%0a%0d%0a%3Chtml%3EHACKED%3C/html%3E.

В удобном формате:

\r\n
Content-Type: text/html\r\n
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Content-Length: 6\r\n
\r\n
<html>HACKED</html>

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

GET /arpit/redirect.php?page=%0d%0aContent-Type: text/html%0d%0aHTTP/1.1 200 OK%0d%0aContent-Type: text/html%0d%0aContent-
Length:%206%0d%0a%0d%0a%3Chtml%3EHACKED%3C/font%3E%3C/html%3E.
Host: test.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9)
Gecko/2008052960 Firefox/3.6.2
......
Accept-Language: en-us,en;q=0.5
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

Сервер должен ответить следующим образом:

HTTP/1.1 302 Found [Первый стандартный ответ со статусом HTTP 302]
Date: Tue, 12 Apr 2005 22:09:07 GMT
Server: Apache/2.3.8 (Unix) mod_ssl/2.3.8 OpenSSL/1.0.0a
Location:
Content-Type: text/html
HTTP/1.1 200 OK [второй ответ на новый запрос, сформированный взломщиком]
Content-Type: text/html
Content-Length: 6
<html>HACKED</html> [Введенные произвольные данные отображаются в качестве страницы перенаправления]
Content-Type: text/html
Connection: Close

Как мы можем увидеть в описании процесса обмена данными выше, сервер отправляет стандартный ответ HTTP со статусом 302, но ввод произвольных данных в строку запроса приводит к передаче нового ответа HTTP со статусом 200 OK, что позволяет показать введенные данные жертве атаки в виде обычного ответа веб-сервера. Жертва атаки увидит веб-страницу с текстом "HACKED".

Схема вышеописанного:

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

Что нужно делать для повышения безопасности

Межпользовательская уязвимость может привести к замене страниц сайта с помощью помещения вредоносных данных в кэш сервера (Web-cache poisoning) и к возможности использования межсайтовых уязвимостей сценариев, но следующие методы повышения безопасности позволяют нейтрализовать ее:

  • Поиск во всех введенных пользователями данных символов CR/LF, т.е, \r\n, %0d%0a или любой другой формы их кодирования (или других небезопасных символов) перед использованием этих данных в любых заголовках HTTP.

  • Следует правильно форматировать строки URI в любых местах сообщений HTTP, например, в параметре "Location" заголовка HTTP; после этого символы CRLF (/r, /n) не будут обрабатываться браузером.

  • SSL (HTTPS) НЕ позволяет противодействовать таким атакам - это миф; при использовании SSL кэш веб-браузера и соединения вне SSL остаются незащищенными. Не полагайтесь на технологию SSL для защиты от рассматриваемого типа атак.

Подробнее про атаки с разделением ответов HTTP читайте тут.

Список изменений

С версии 2.3.0 Введена.

Код wp_sanitize_redirect() WP 6.6.2

function wp_sanitize_redirect( $location ) {
	// Encode spaces.
	$location = str_replace( ' ', '%20', $location );

	$regex    = '/
	(
		(?: [\xC2-\xDF][\x80-\xBF]        # double-byte sequences   110xxxxx 10xxxxxx
		|   \xE0[\xA0-\xBF][\x80-\xBF]    # triple-byte sequences   1110xxxx 10xxxxxx * 2
		|   [\xE1-\xEC][\x80-\xBF]{2}
		|   \xED[\x80-\x9F][\x80-\xBF]
		|   [\xEE-\xEF][\x80-\xBF]{2}
		|   \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences   11110xxx 10xxxxxx * 3
		|   [\xF1-\xF3][\x80-\xBF]{3}
		|   \xF4[\x80-\x8F][\x80-\xBF]{2}
	){1,40}                              # ...one or more times
	)/x';
	$location = preg_replace_callback( $regex, '_wp_sanitize_utf8_in_redirect', $location );
	$location = preg_replace( '|[^a-z0-9-~+_.?#=&;,/:%!*\[\]()@]|i', '', $location );
	$location = wp_kses_no_null( $location );

	// Remove %0D and %0A from location.
	$strip = array( '%0d', '%0a', '%0D', '%0A' );
	return _deep_replace( $strip, $location );
}