Экранирование HTML

Предисловие

В версии ACF 5.10 была представлена важная функция безопасности — экранирование HTML. Впервые она была представлена в качестве экспериментальной функции в ACF 5.9.6 и обеспечивает прохождение всего HTML-контента, отображаемого ACF, через функцию WordPress wp_kses().

Запуская весь HTML-контент через эту нативную функцию WordPress, ACF гарантирует, что любой HTML, который он отображает, не подвержен атакам межсайтового скриптинга (XSS).

Важно отметить, что экранирование будет работать только для HTML-контента, отображаемого плагином АЦФ в панели управления WordPress или на любых формах для конечных пользователей, отображаемых через acf_form(). И не будет работать для значений полей, загруженные через функции API, такие как get_field() и the_field(). Мы не делаем никаких предположений о том, где вы используете значения полей в своей теме и не производим экранирование для них.

Реализация

Система экранирования HTML в ACF представляет новую функцию экранирования acf_esc_html(), которая теперь используется во всем плагине ACF для отображения HTML. Эта функция принимает содержимое для рендера и передает его в функцию wp_kses(), возвращая результат. Она также передает контекста acf.

/**
 * Очищает текстовое содержимое и удаляет недопустимый HTML.
 *
 * Эта функция имитирует wp_kses_post() с контекстом "acf" для расширяемости.
 *
 * @date    16/4/21
 * @since   5.9.6
 *
 * @param   string $string
 * @return  string
 */
function acf_esc_html( $string = '' ) {
    return wp_kses( (string) $string, 'acf' );
}

Содержимое ACF, прошедшее через wp_kses(), просит WordPress удалить любые недопустимые HTML-теги или атрибуты тегов. Список разрешенных тегов управляется функцией WordPress wp_kses_allowed_html(). По-умолчанию WordPress поставляется с рядом предопределенных разрешенных тегов и их разрешенных атрибутов. Вот пример разрешенного тега button и его разрешенных атрибутов.

[button] => Array
    (
        [disabled] => true
        [name] => true
        [type] => true
        [value] => true
        [aria-describedby] => true
        [aria-details] => true
        [aria-label] => true
        [aria-labelledby] => true
        [aria-hidden] => true
        [class] => true
        [id] => true
        [style] => true
        [title] => true
        [role] => true
        [data-*] => true
    )

Если HTML-элемент в содержимом, переданном в wp_kses(), не находится в списке разрешенных тегов, или атрибут тега отсутствует в списке разрешенных, он будет удален из содержимого.

Кастомизация

Передача пользовательского контекста acf в wp_kses() позволяет настраивать разрешенные теги HTML и атрибуты. Если у вас есть конкретный HTML-тег или атрибут тега, который вы хотите разрешить, вы можете добавить его в список разрешенных тегов, используя фильтр-хук wp_kses_allowed_html в PHP.

Например, вы можете использовать этот фильтр в functions.php вашей темы или плагине, чтобы разрешить тег iframe:

add_filter( 'wp_kses_allowed_html', 'acf_add_allowed_iframe_tag', 10, 2 );
function acf_add_allowed_iframe_tag( $tags, $context ) {
    if ( $context === 'acf' ) {
        $tags['iframe'] = array(
            'src'             => true,
            'height'          => true,
            'width'           => true,
            'frameborder'     => true,
            'allowfullscreen' => true,
        );
    }

    return $tags;
}

Вот еще один пример, который разрешает явно указанные теги svg и path:

add_filter( 'wp_kses_allowed_html', 'acf_add_allowed_svg_tag', 10, 2 );
function acf_add_allowed_svg_tag( $tags, $context ) {
    if ( $context === 'acf' ) {
        $tags['svg']  = array(
            'xmlns'       => true,
            'fill'        => true,
            'viewbox'     => true,
            'role'        => true,
            'aria-hidden' => true,
            'focusable'   => true,
        );
        $tags['path'] = array(
            'd'    => true,
            'fill' => true,
        );
    }

    return $tags;
}

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

В WordPress, по-умолчанию, встроено экранирование, которое удаляет теги и атрибуты тегов HTML, которые считает небезопасными, также удаляются свойства CSS, которые считаются небезопасными, например, свойство display. В некоторых случаях вам может потребоваться определить и добавить встроенный стиль в панель управления WordPress. Например, такое.

<div style="display: flex">

Поскольку свойство display удаляется, это свойство также будет удалено из тега div.

Как и в случае с разрешенными HTML-тегами, вы также можете разрешить определенные свойства CSS, используя фильтр safe_style_css:

add_filter( 'safe_style_css', 'add_display_to_safe_css', 10, 1 );
function add_display_to_safe_css( $css_attributes ) {
    $css_attributes[] = 'display';

    return $css_attributes;
}

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

Экранирование HTML в ACF

В Advanced Custom Fields PRO версии 5.12 и выше, WordPress будет применять свою стандартную санитизацию wp_kses_post() к блокам ACF для пользователей без разрешения unfiltered_html. В некоторых случаях это может привести к удалению HTML-кода из содержимого блока, и следовательно, этот контент не будет отображаться на frontend, что не происходило в версиях до 5.12.

Если у пользователя нет возможности unfiltered_html, но ему нужно вставлять HTML в блоки ACF, который удаляется функцией wp_kses_post(), вы можете добавить поддержку определенных HTML-тегов, используя тот же фильтр-хук wp_kses_allowed_html, что и ранее, но с контекстом «post»:

add_filter( 'wp_kses_allowed_html', 'acf_add_allowed_iframe_tag', 10, 2 );
function acf_add_allowed_iframe_tag( $tags, $context ) {
    if ( $context === 'post' ) {
     $tags['iframe'] = array(
         'src'          => true,
         'height'       => true,
         'width'        => true,
         'frameborder'  => true,
         'allowfullscreen' => true,
     );
    }

    return $tags;
}

Кроме того, вы можете вручную предоставить пользователю разрешение unfiltered_html.