Очистить введенный пользователем CSS
Кто-нибудь знает, как очистить CSS, введенный с помощью пользовательского ввода? Я обеспокоен межсайтовыми сценариями с помощью CSS. Я использую wp_filter_kses для очистки введенного пользователем HTML, но мне нужно аналогичное решение для введенных пользователем стилей. Пока я использую следующую уродливую и неполную функцию, но мне хотелось бы чего-то более полного.
function sanitizeCSS ( $css ) {
$css = str_replace( '/-moz-binding/', '', $css );
$css = str_replace( '/expression/', '', $css );
$css = str_replace( '/javascript/', '', $css );
$css = str_replace( '/vbscript/', '', $css );
return $css;
}
5 answers
Вам понадобится настоящий синтаксический анализатор CSS, такой как этот для фильтрации CSS. Регулярные выражения или простые замены строк недостаточно безопасны.
Лучший подход, который я нашел, состоял в том, чтобы включить CSSTidy в мой плагин. Я взял страницу из JetPack, в которой есть пользовательская функция CSS.
Реализация CSSTidy Jetpack содержится в классе Jetpack_Safe_CSS в виде функции filter_attr. Я не мог полностью понять, почему JETPack вложил, что пользователь ввел CSS в элемент "div" до синтаксического анализа, но после некоторых проб и ошибок я узнал, что CSSTidy на самом деле не способен анализировать файл CSS. Этот урок я усвоил буквально сорвал код с реактивного ранца.
Я скачал CSSTidy, создал каталог, содержащий PHP-файлы CSSTidy. Затем я требую class.csstidy.php по мере необходимости в моем коде и инициализируйте новый объект csstidy. Вставьте CSS, подлежащий проверке, в элемент "div", проанализируйте его через CSSTidy, затем извлеките обычный CSS из объекта csstidy. До сих пор так хорошо с тысячами установок (хотя я никогда не узнаю, сколько пользователей на самом деле используют функцию CSS моего плагина).
Я возможно, я не заметил, что это мой первоначальный вопрос, но я искал самый простой, легкий подход, а не самый технический, сложный или мощный подход. Я ценю как можно меньше изменений в работе WordPress. Вот почему я обратился к JetPack как к самой близкой вещи к "источнику". Я считаю Jetpack почти каноническим, поскольку он разработан Automattic (разработчиками самого WordPress). Мой единственный... сожалеть?... это то, что CSSTidy был заброшен в 2007 году, поэтому я полагаю, что мне нужно будет в какой-то момент найдите другое решение.
require_once( 'csstidy/class.csstidy.php' );
$csstidy = new csstidy();
$csstidy->set_cfg( 'remove_bslash', FALSE );
$csstidy->set_cfg( 'compress_colors', FALSE );
$csstidy->set_cfg( 'compress_font-weight', FALSE );
$csstidy->set_cfg( 'discard_invalid_properties', TRUE );
$csstidy->set_cfg( 'merge_selectors', FALSE );
$csstidy->set_cfg( 'remove_last_;', FALSE );
$csstidy->set_cfg( 'css_level', 'CSS3.0' );
$csstovalidateindiv = 'div {' . $csstovalidate . '}';
$csstovalidateindiv = preg_replace( '/\\\\([0-9a-fA-F]{4})/', '\\\\\\\\$1', $csstovalidateindiv );
$csstovalidateindiv = wp_kses_split( $csstovalidateindiv, array(), array() );
$csstidy->parse( $csstovalidateindiv );
$csstovalidateindiv = $csstidy->print->plain();
$csstovalidateindiv = str_replace( array( "\n", "\r", "\t" ), '', $csstovalidateindiv );
preg_match( "/^div\s*{(.*)}\s*$/", $csstovalidateindiv, $matches );
if ( !empty( $matches[1] ) ) $cssvalidated = $matches[1];
(код или этого не произошло)
Jetpack на самом деле не очищает CSS, он просто очищает его, что имеет побочный эффект удаления некоторых уязвимостей, но не всех.
Злоумышленник все еще может использовать @import
для импорта неаналитизированного CSS; expression()
для внедрения XSS в старые браузеры IE; @charset
для обмана браузера, чтобы интерпретировать CSS как HTML, открывая возможности XSS; устанавливать URL-адреса с произвольными протоколами для запуска SSRF-атак и т.д.
Если вы хотите провести полную дезинфекцию, вам нужно будет сделать что-то вроде r2085-мета.
Вам следует провести дезинфекцию в соответствии с комплексными тестовыми случаями , чтобы убедиться, что она все очищает.
CSSTidy на самом деле не заброшен; один из первоначальных авторов разветвил класс PHP, а команда Jetpack и другие внесли свой вклад в его разумное обновление. Однако, если вы не чувствуете себя комфортно с этим, Caja - еще один вариант.
wp_filter_nohtml_kses()
, похоже, работает неправильно, потому что он избегает символа ", поэтому вы не можете написать никаких селекторов атрибутов. Похоже, что "простого" способа сделать это не существует.
Ну, если вам нужен подход с 50-миллиметровым стволом, вы могли бы использовать wp_filter_nohtml_kses()
, но могут быть и лучшие способы.