Проблема с кодировкой ColdFusion — encodeForHTML и encodeForJavascript сбрасывают обратную косую черту

Для защиты от межсайтового скриптинга (XSS) я использую то, что рекомендует OWASP, ESAPI ( API корпоративной безопасности). Файл esapi.jar был включен в предыдущую версию ColdFusion, но в CF10 теперь вы можете легко вызывать некоторые из этих полезных функций: encodeForJavascript(), encodeForHTML(), encodeForURL(), encodeForCSS() и encodeForHTMLAttribute().

У меня проблемы с encodeForJavascript(), я теряю обратную косую черту...

<cfoutput>
    <cfif isDefined("url.name")>
        <!--- Here is the problem, this is identical to the original ascii32to126 string except for one char is missing, the backslash between the brackets ...Z[]... --->
        #url.name#
        <cfabort>
    </cfif>

    <!---
    ASCII 32 thru 126
    !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
    In the line below I double up on the double-quotes and pounds in order to get the cfset to work
    --->
    <cfset ascii32to126 = "!""##$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~">

    <script>
        function locateTo(value)
        {
            window.location='thisPage.cfm?name='+encodeURIComponent(value);
            //alert('thisPage.cfm?name='+encodeURIComponent(value));
        }
        locateTo('#encodeForJavaScript(ascii32to126)#');
    </script>
</cfoutput>

Сначала я вызываю encodeForJavaScript(), потому что мы находимся в контексте JavaScript.

Затем я вызываю encodeURIComponent(), чтобы убедиться, что URL построен правильно.

Все работает нормально, но на результирующей странице я потерял обратную косую черту \. Что мне здесь не хватает?

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

** ОБНОВЛЕНИЕ ** — Я использую ColdFusion 10 со всеми последними исправлениями. Проблема, похоже, в encodeForJavaScript().

Также не работает с JSStringFormat(). Это показывает, что обратная косая черта отсутствует для обоих...

<cfset ascii32to126 = "!""##$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~">
<cfoutput>
    #encodeForHTML(encodeForJavaScript(ascii32to126))#
    <br><br>
    #encodeForHTML(JSStringFormat(ascii32to126))#
</cfoutput>

person gfrobenius    schedule 30.04.2014    source источник
comment
Вам не нужно просматривать источник: <cfcontent reset type="text/plain">#url.name#<cfabort/>   -  person Peter Boughton    schedule 01.05.2014
comment
Я только что запустил ваш код на Railo 4 и Chromium, и он отлично работает — обратная косая черта присутствует. Возможно, ошибка в encodeForJavaScript любой версии CF, которую вы используете, или в реализации encodeURIComponent любого браузера, с которым вы тестировали — вы не предоставили ни одной части информации.   -  person Peter Boughton    schedule 01.05.2014
comment
Я использую ColdFusion 10 со всеми последними исправлениями. Кажется, в encodeForJavaScript(), просто это показывает, что обратная косая черта отсутствует... <cfoutput>#encodeForJavaScript(ascii32to126)#</cfoutput>   -  person gfrobenius    schedule 01.05.2014
comment
Хм. Вместо этого он работает с JsStringFormat?   -  person Peter Boughton    schedule 01.05.2014
comment
Нет, смотрите обновление выше.   -  person gfrobenius    schedule 01.05.2014
comment
Эх, я только что запустил CF10, и JsStringFormat работает нормально - он правильно экранирует обратную косую черту. Однако encodeForJavaScript отбрасывает его — gist.github.com/boughtonp/519876a5f77c6f4ddcf0   -  person Peter Boughton    schedule 01.05.2014
comment
Обратите внимание, что cfcontent text/plain — нет необходимости в encodeForHtml, который ТАКЖЕ удаляет обратную косую черту. (Нет выхода %5C)   -  person Peter Boughton    schedule 01.05.2014
comment
Я быстро просмотрел JAR-файлы — похоже, что CF10 и Railo4 используют ESAPI v2.0.1, но encodeForJavaScript и encodeForHtml работают в Railo, но не в CF10. Именно из-за подобных ошибок я рекомендую избегать функций encodeForX.   -  person Peter Boughton    schedule 01.05.2014
comment
Я удалил encodeForHTML() и теперь вижу то же самое. С jsStringFormat() я вижу скрытую обратную косую черту \\, но с encodeForJavaScript() \x5C отсутствует. Вместо этого я вижу ...\x5B\x5D... К чему бы это? Из того, что я прочитал, OWASP и другие настоятельно рекомендуют ESAPI. .... Только что увидел ваш последний комментарий, спасибо!   -  person gfrobenius    schedule 01.05.2014
comment
Похоже, что обратная косая черта съедается следующим символом - т.е. кодируется одна обратная косая черта, но с другими символами она теряется. Не знаю, почему... это надо спросить у Adobe. :/   -  person Peter Boughton    schedule 01.05.2014
comment
Я уже разговаривал с Деймоном Миллером, руководителем проекта ESAPI, и посмотрю, есть ли у него какое-то представление об этом. Спасибо Питер!   -  person gfrobenius    schedule 01.05.2014


Ответы (3)


FWIW, мы используем все функции encodeForX уже более года, и проблемы возникают только тогда, когда разработчик использует неправильный контекст. Мы строго запретили использование HTMLEditFormat, и сервер Jenkins проверяет его (среди других запрещенных функций и тегов), поскольку сборки выполняются в течение дня.

Вы кодируете строку для JavaScript, а затем кодируете ее для URL. Я считаю, что вы должны сначала кодировать URL, а затем кодировать JavaScript. Кажется, нет никаких потерянных символов, когда я сравниваю вывод с незакодированной строкой.


<cfoutput>
    <cfif isDefined("url.name")>
        <!--- Here is the problem, this is identical to the original ascii32to126 string except for one char is missing, the backslash between the brackets ...Z[]... --->
        #url.name#
        <cfabort>
    </cfif>

    <!---
    ASCII 32 thru 126
    !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
    In the line below I double up on the double-quotes and pounds in order to get the cfset to work
    --->
    <!--- Using Chr() to bypass character escaping. --->
    <cfset ascii32to126 = "!#chr(34)##chr(35)#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~">
    <cfdump var="#ascii32to126#" />

    <script>
        function locateTo(a, b) {
            console.log(a); // 1. JavaScript Encoded.
            console.log(b); // 2. URL encoded, then JavaScript encoded.
            console.log(decodeURIComponent(b));// 3. Matches JavaScript encoded.
            console.log( 'thisPage.cfm?name=' + b ); // 4. Correct string.
        }

        locateTo('#encodeForJavaScript(ascii32to126)#', '#encodeForJavaScript(encodeForURL(ascii32to126))#');
    </script>
</cfoutput>

Вывод в консоль


!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 

%21%22%23%24%25%26%27%28%29*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E 

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 

thisPage.cfm?name=%21%22%23%24%25%26%27%28%29*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E 
person Adrian J. Moreno    schedule 30.04.2014
comment
Ах, да, сначала закодируйте URL, а затем js. Я действительно знал это и упомянул то же самое несколько дней назад: rule">stackoverflow.com/questions/10488992/what-xss-owasp-rule/ Как легко я забываю, нужно больше RedBull :) НО, я взял ваш код и запустил его как есть, и я не получаю такие же результаты. В строках 1 и 2 отсутствует обратная косая черта, а строка 3 decodeURIComponent умирает с Uncaught URIError: URI malformed. Действительно странно. У меня версия CF: 10,0,13,287689 и версия Java 1.7.0_51. - person gfrobenius; 01.05.2014
comment
Даже если я смогу заставить его работать, это не будет моим идеальным решением. locateTo — очень простой пример чего-то еще в моей системе. Он представляет собой низкоуровневую функцию, используемую тысячами вызовов. Я хочу, чтобы защита была там. Я бы предпочел, чтобы другие программисты не забывали всегда делать и то, и другое, как вы продемонстрировали: #encodeForJavaScript(encodeForURL(ascii32to126))#. Но я не могу придумать, как это обойти. - person gfrobenius; 01.05.2014
comment
Я понимаю, Гордон, но у нас строгие стандарты кодирования, и каждый разработчик (сейчас 60, скоро будет 80) должен убедиться, что он вызывает правильный кодировщик в правильном контексте. На самом деле мы развернули UDF для абстрагирования отдельных функций: safeOutput(text, encoder). У нас также есть развивающаяся библиотека JavaScript, полная стандартизированных функций, таких как ваш locateTo. Никто не сворачивает свои собственные, если это не относится к логике текущей страницы. - person Adrian J. Moreno; 01.05.2014
comment
safeOutput(), это хорошая идея. До сих пор не знаю, почему у меня не отображается обратная косая черта. - person gfrobenius; 01.05.2014
comment
Это в этой части строки? [\] - person Adrian J. Moreno; 01.05.2014
comment
Нет, я просмотрел исходный код и сделал console.log, его просто нет после использования encodeForHTML или encodeForJavascript. @PeterBoughton также имеет те же результаты, что и я. Поиграем с ним завтра, ушли из офиса. Спасибо. - person gfrobenius; 01.05.2014

У нас есть собственная функция кодирования, называемая ddj()...

<!---
Author: @Brian McGinity
custom version of jsStringFormat/encodeForJavaScript
--->
<cffunction name="ddj" returntype="string" output="false">
    <cfargument name="temp" required="yes" type="string">
    <!---
    <cfset var z = jsStringFormat(arguments.temp)>
    <cfreturn z>
    --->
    <cfset var buf = CreateObject("java", "java.lang.StringBuffer")>
    <cfset var len = Len(arguments.temp)>
    <cfset var char = "">
    <cfset var charcode = 0>
    <cfset var bad   = ' >%}\~];?@&<##{|^[`/:=$+"' & "'">
    <cfset buf.ensureCapacity(JavaCast("int", len+40))>
    <cfif NOT len><cfreturn arguments.temp></cfif>

    <cfloop from="1" to="#len#" index="xmlIdx">
        <cfset char = mid(arguments.temp,xmlIdx,1)>
        <cfset charcode = asc(char)>
        <cfif charcode LT 32 or charcode gt 126>
            <cfset buf.append(JavaCast("string", ""))>
        <cfelse>
            <cfif find(char, bad) gt 0>
                <cfset buf.append(JavaCast("string",  "\u00" & right("0" & formatBaseN(charcode,16),2) ))>
            <cfelse>
                <cfset buf.append(JavaCast("string", char))>
            </cfif>
        </cfif>
    </cfloop>
    <cfreturn buf.toString()>
</cffunction>

Используя ddj(), я могу передать строку ascii32to126 в функцию, затем выполнить для нее encodeURIComponent, затем перейти на страницу и распечатать ее, и строка будет точно такой же. Кажется, работает отлично. Но делая это таким образом, я сначала кодирую для JS, а затем для URL-адреса. Это не кажется правильным. Я всегда думал, что должно быть наоборот (см. здесь). Поэтому я пытаюсь понять, смогу ли я его сломать. Вот тестовый пример, который, кажется, работает...

<cfoutput>
    <cfif isDefined("url.name")>
        #url.name#
        <cfabort>
    </cfif>

    <!--- !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ --->
    <cfset ascii32to126 = "!""##$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~">

    <script>
        function goToUrl(value)
        {
            window.location='thisPage.cfm?name='+encodeURIComponent(value);
            //alert('thisPage.cfm?name='+encodeURIComponent(value));
        }
        goToUrl('#ddj(ascii32to126)#');
    </script>
</cfoutput>
person gfrobenius    schedule 30.04.2014
comment
Привет, Г. Я много узнал о xss с тех пор, как мой пост SO упоминался выше (stackoverflow.com/questions/10488992/ мои выводы: если вы перетаскиваете строку в javascript, то ей нужна кодировка js . Это должно произойти, чтобы любая и каждая строка была защищена, поскольку она находится в js. Если эта строка затем будет передана в URL-адрес (оставаясь при этом в javascript), используйте encodeURIComponent() javascirpt. Ошибка кодировать строку в URL, а затем помещать ее в javascript. - person Brian McGinity; 01.05.2014
comment
Что до Б?! Итак, вы говорите, что мой ответ выше правильный? Это то, что я делаю. - person gfrobenius; 01.05.2014
comment
Да, вы правы. Я добавил ответ на свой пост: stackoverflow. com/questions/10488992/what-xss-owasp-rule/ - person Brian McGinity; 01.05.2014

(2+ года спустя) Похоже, что с тех пор это было исправлено Adobe или людьми из ESAPI. Все символы, включая обратную косую черту, сохраняются. Я сейчас запускаю эти версии...

Серверный продукт: ColdFusion

Версия: 11,0,09,299201

Версия Tomcat: 7.0.68.0

Издание: Разработчик

Операционная система: Windows 10

Версия ОС: 10.0

Уровень обновления: C:/ColdFusion11/cfusion/lib/updates/chf11000009.jar

Драйвер Adobe: 5.1.3 (сборка 000094)

Java-версия: 1.8.0_91

Поставщик Java: корпорация Oracle

person gfrobenius    schedule 27.07.2016