Как исправить уязвимость разделения HTTP-ответов с помощью ESAPI

После недавнего запуска findbugs (FB) он жалуется на: Безопасность - уязвимость расщепления ответов HTTP Следующий код вызывает это:

String referrer = req.getParameter("referrer");
 if (referrer != null) {
  launchURL += "&referrer="+(referrer);
 }
resp.sendRedirect(launchURL);

По сути, параметр http "referrer" содержит URL-адрес, по которому при нажатии кнопки "Назад" в нашем приложении браузер возвращается. Он добавляется к URL в качестве параметра. После небольшого исследования я знаю, что мне нужно очистить URL реферала. После небольшого исследования я нашел проект esapi, который, кажется, предлагает такую ​​функциональность:

//1st canonicalize
import org.owasp.esapi.Encoder;
import org.owasp.esapi.Validator;
import org.owasp.esapi.reference.DefaultEncoder;
import org.owasp.esapi.reference.DefaultValidator;
[...]
Encoder encoder = new DefaultEncoder(new ArrayList<String>());
String cReferrer = encoder.canonicalize(referrer);

Однако я не выяснил, как обнаружить, например, код jscript или другой материал, который не принадлежит URL-адресу реферера. Так как я могу достичь этого с помощью esapi?

Я старался:

Validator validator = new DefaultValidator(encoder);
validator.isValidInput("Redirect URL",referrer,"HTTPParameterValue",512,false);

Однако это не работает. Что мне нужно, это функция, которая приводит к:

http://www.google.com/ (хорошо)

http://www.google.com/login?dest=http://google.com/%0D%0ALocation: javascript:% 0D% 0A% 0D% 0Aalert (document.cookie) (не в порядке)

Или достаточно назвать следующее утверждение?

encoder.encodeForHTMLAttribute(referrer);

Любая помощь приветствуется.

3 ответа

Решение

Вот мое окончательное решение, если кому-то интересно. Сначала я канонизирую, а затем URL декодирую строку. Если существует CR или LF (\n \r), я просто отрезаю остальную часть этой потенциальной строки "атаки", начиная с \ n или \r.

String sanitize(String url) throws EncodingException{

    Encoder encoder = new DefaultEncoder(new ArrayList<String>());
    //first canonicalize
    String clean = encoder.canonicalize(url).trim();
    //then url decode 
    clean = encoder.decodeFromURL(clean);

    //detect and remove any existent \r\n == %0D%0A == CRLF to prevent HTTP Response Splitting
    int idxR = clean.indexOf('\r');
    int idxN = clean.indexOf('\n');

    if(idxN >= 0 || idxR>=0){
        if(idxN>idxR){
            //just cut off the part after the LF
            clean = clean.substring(0,idxN-1);
        }
        else{
            //just cut off the part after the CR
            clean = clean.substring(0,idxR-1);
        }
    }

    //re-encode again
    return encoder.encodeForURL(clean);
}

Теоретически я мог бы позже проверить значение по регулярному выражению "HTTPParameterValue", которое определено в ESAPI.properties, однако ему не понравилось двоеточие в http://, и я больше не исследовал его.

И еще одно замечание после тестирования: большинство современных браузеров (Firefox > 3.6, Chrome, IE10 и т. Д.) Обнаруживают подобные уязвимости и не выполняют код...

Я думаю, у вас есть правильная идея, но вы используете неподходящий кодировщик. Значение заголовка Referer [sic] на самом деле является URL, а не атрибутом HTML, поэтому вы действительно хотите использовать:

encoder.encodeForURL(referrer);

Кевин

Я хотел бы предложить подход белого списка, где вы проверяете referrer строка только для допустимых символов. Regex будет хорошим вариантом.

РЕДАКТИРОВАТЬ:

Класс org.owasp.esapi.reference.DefaultEncoder использование вами на самом деле ничего не кодирует. Посмотрите на исходный код метода encodeForHTMLAttribute(referrer) здесь, в grepcode. Типичная кодировка URL (кодирование возврата каретки и перевода строки) тоже не поможет.

Таким образом, дальнейшим шагом будет устройство логики проверки, которая проверяет правильность набора символов. Вот еще одна проницательная статья.

Принятый ответ не будет работать, если в строке есть "\n\r". Пример: если у меня есть строка:"This is str\n\rstr", он возвращается "This is str\nstr"

Исправленная версия принятого выше ответа:

 String sanitizeCarriageReturns(String value) {
        int idxR = value.indexOf('\r');
        int idxN = value.indexOf('\n');

        if (idxN >= 0 || idxR >= 0) {
            if ((idxN > idxR && idxR<0) || (idxR > idxN && idxR>=0)) {
                    value = value.substring(0, idxN);
                } else if (idxN < idxR){
                    value = value.substring(0, idxR);
                } 

        }
        return value;
    }
Другие вопросы по тегам