Как избежать внутреннего css?

Я хотел бы вставить некоторый пользовательский css в head моего html, используя javascript. Проблема в том, что когда я убегаю от определенных символов, ломается CSS.

Например:

    let css = `
        @import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
        body { font-family: "Roboto", sans-serif; }
        `,
        style = document.createElement('style');

    style.type = 'text/css';
    document.head.appendChild(style);
    css = escape(css);
    style.appendChild( document.createTextNode( css ) );

выходы:

    <style type="text/css" id="custom-theme-styles">
    @import url(&#39;https://fonts.googleapis.com/css?family=Roboto&amp;display=swap&#39;);
    body { font-family: &quot;Roboto&quot;, sans-serif !important; }
    </style>

Как видите, одинарные и двойные кавычки производят &#39; и &quot; соответственно. Амперсанд в строке запроса преобразуется в &amp;. Я также мог видеть проблемы с использованием дочернего комбинатора css (>).

Есть ли способ избежать css, чтобы он не ломался и надежно отображался? Это кажется плохой идеей, но если я не убегу от css, это вообще проблема безопасности? Я могу ошибаться, но я не думаю, что тег <script> внутри тега <style> будет выполняться. Есть ли какие-либо другие уязвимости, которые я пропускаю, не выходя из css?


person jwerre    schedule 01.10.2019    source источник
comment
Я не уверен в вопросах безопасности, но вы можете попробовать css = decodeURI(css); Чего вы пытаетесь достичь? Мне любопытно, можете ли вы подойти к этому по-другому, не опасаясь проблем с безопасностью.   -  person disinfor    schedule 01.10.2019
comment
Я устал decodeURI(), та же проблема. Это ломает css.   -  person jwerre    schedule 01.10.2019
comment
Использование функций, которые кодируют URL-адреса (или фрагменты URL-адресов), не поможет (особенно не escape, который в значительной степени устарел). Вместо этого вам, вероятно, следует использовать парсер CSS.   -  person str    schedule 01.10.2019


Ответы (1)


Я обновил это, чтобы отразить подробности и рекомендации по ссылке OWASP в комментариях

Я думаю, что нет никакой пользы от использования чего-то вроде decodeURI() или escape(), которые не предназначены для этого.

У OWASP есть довольно подробное руководство по предотвращению XSS, которое включает раздел о том, как работать с CSS.

По их собственным словам:

CSS удивительно мощен и может использоваться для многочисленных атак. Поэтому важно использовать ненадежные данные только в значении свойства, а не в других местах данных стиля. Вам следует избегать помещения ненадежных данных в сложные свойства, такие как URL-адрес, поведение и пользовательское (-moz-binding).

Вы также не должны помещать ненадежные данные в значение свойства выражения IE, которое разрешает JavaScript.

Стоит прочитать руководство полностью, так как есть ряд вещей, которые вам нужно учитывать в целом, а с безопасностью достаточно одной ошибки, чтобы отменить все.

На практике я считаю, что вы можете начать с передачи его через что-то вроде PostCSS, чтобы сначала проанализировать CSS. (Это также имеет некоторые преимущества с точки зрения общей функциональности/архитектуры, поскольку также упрощает добавление таких функций, как отладочные сообщения или префиксы CSS в будущем).

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

{ background-url : "javascript:alert(1)"; }

Обратите внимание, что OWASP настоятельно рекомендует использовать подход с использованием белого списка. Начните с точки зрения запрета всего, а затем разрешайте определенные исключения только тогда, когда вы знаете, что они безопасны и необходимы.

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

(В более ранней версии ответа я отметил, что теги стиля считались текстовый узел, который защищает от некоторых видов тривиальные атаки внедрения. Хотя это правда, примеры OWASP демонстрируют, что эта защита довольно иллюзорна).

person ChrisM    schedule 01.10.2019
comment
Правило #0 правил предотвращения XSS OWASP: никогда не вставляйте ненадежные данные, кроме как в разрешенные местоположения, одно из которых находится между <style> и </style>. Один проспект: background-image: url("javascript: malware()");. См. Правило №4 - person Heretic Monkey; 01.10.2019
comment
Спасибо @HereticMonkey, это именно то, что я искал. - person jwerre; 01.10.2019
comment
@HereticMonkey, это хорошая ссылка. Я собирался обновить свой ответ, чтобы отразить это, но я чувствую, что вы должны получить кредит. Вы хотите написать ответ самостоятельно? - person ChrisM; 01.10.2019