Много было написано о сканировании уязвимостей XSS. В этой статье мы постараемся пойти немного дальше и показать, как их исправить.
Чтобы проиллюстрировать весь процесс, от начального обнаружения до предоставления исправления, мы будем использовать очень простое приложение, состоящее из двух страниц JSP: одна представляет собой форму оплаты для транзакций по кредитным картам и содержит некоторый код XSS, пригодный для использования. У другого такой код исправлен: последний — просто исправленная версия первого. Мы увидим, как злоумышленник может обмануть пользователей, используя существующую уязвимость XSS, для сбора данных их кредитных карт.
- (Скачать уязвимое приложение )
XSS-атаки
Цель XSS-атак состоит в том, чтобы внедрить скрипт, выполняемый веб-браузером пользователя. В большинстве случаев пользователь даже не знает, что происходит. Для получения дополнительной информации о XSS, пожалуйста, ознакомьтесь с описанием OWASP XSS Attack .
Давайте посмотрим на наше приложение. Уязвимый JSP ( xss_html.jsp ) содержит следующий фрагмент кода:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<% final String amount = request.getParameter( "amount" ); Enumeration pNames = request.getParameterNames(); while (pNames.hasMoreElements()){ final String pName = pNames.nextElement(); final String pVal = request.getParameter(pName); %> <input type= "hidden" name= "<%=pName%>" /> " value=" " />;</pre> <table> <tbody> <tr> <td>Credit card</td> <td><input type= "text" maxlength= "16" name= "cc" size= "16" value= "" /></td> </tr> <tr> <td>Exp Date (mm/yy)</td> <td><input type= "text" maxlength= "2" name= "expMonth" size= "2" value= "" /> /<input type= "text" maxlength= "2" name= "expYear" size= "2" value= "" /></td> </tr> <tr> <td>CVV2</td> <td><input type= "text" maxlength= "2" name= "expMonth" size= "2" value= "" /> /<input type= "text" maxlength= "2" name= "expYear" size= "2" value= "" /></td> </tr> <tr> <td colspan= "2" ><input id= "button1" type= "submit" name= "button1" value= "Pay" /></td> </tr> </tbody> </table> |
Форма получает сумму для начисления в виде параметра HTTP-запроса, собирает данные с кредитной карты пользователя и затем списывает их с нее (конечно, такой последний шаг не включен, вы можете попробовать использовать любые нереальные данные кредитной карты). Пользователи могут быть перенаправлены сюда с любого сайта электронной коммерции, используя URL-адрес, такой как http: //……/XSS_Vulnerable/xss_html.jsp? Amount = 12.25 (опять же, никто не выберет такой путь для платежного шлюза, притворяющегося доверенным) , Но давайте посмотрим, что произойдет, если злоумышленник обманом заставит кого-то загрузить вредоносный URL-адрес, который входит в index.jsp, вместо того, когда пользователь нажимает кнопку « Оплатить» (Firefox 24.0 для Linux):
Просто предупреждение, но внедренный код Javascript мог создать изображение или какую-то другую ссылку, поэтому злоумышленник мог бы собирать данные, просто просматривая журналы доступа Apache. Действительно, некоторые браузеры могут выявлять такие угрозы и не будут выполнять внедренные сценарии, как показано (Chromium 28.0 для Linux).
Обнаружение XSS
К счастью, существует множество инструментов, выполняющих сканирование на наличие угроз XSS, поэтому при самых распространенных проблемах не нужно просматривать каждую строку кода на каждой веб-странице при попытке обнаружить такие уязвимости. Одним из таких инструментов является OWASP Zed Attack Proxy Object (ZAP) . Хотя было бы несправедливо сказать, что это всего лишь XSS-сканер, поскольку он предоставляет множество других интересных функций.
ZAP можно использовать в качестве прокси-сервера (на самом деле он основан на более раннем прокси-сервере Paros), который может сканировать все страницы, принятые во время сеанса. Однако мы просто введем URL-адрес ( http: //……/XSS_Vulnerable/xss_html.jsp? Amount = 12.25 ) и нажмите кнопку « Атака» (мы используем ZAP 2.2.2). Чтобы избежать нескольких предупреждений и ускорить сканирование, мы отключили все типы сканирования, кроме XSS.
Начиная с предоставленного URL-адреса ( http: //……/XSS_Vulnerable/xss_html.jsp? Amount = 12.25 ) ZAP сделал несколько проверок, добавляя код JavaScript для инъекции.
Вкладка внизу показывает одну успешную попытку атаки XSS. ZAP заменил числовое значение параметра количества на код JavaScript и закодированный URL-адрес (как видно из поля URL), который представляет собой просто «> <script> alert (1); </ script> в виде простого текста (как видно из поля Evidence).
Кроме того, на вкладке выше, где показан ответ HTTP, отчетливо показан результат атаки XSS: введенный код в параметре суммы сначала закрывает двойные кавычки («) вокруг значения для поля количества и закрывает ввод HTML (>). После этого он добавляет предупреждение скрипта (1); (<Скрипт> оповещения (1); </ скрипт>). Полученный HTML-код, который будет выполнен веб-браузером, содержит:
1
|
< input type = "hidden" name = "amount" value = "" >< script >alert(1);</ script >" /> |
XSS Fix
Хотя не существует единого исправления для всех атак XSS, все они основаны на проверке ввода, где «вход» может быть любым из параметров запроса HTTP, значений заголовков HTTP или даже имен … все зависит от того, что код использует в качестве ввода.
В нашем примере приложения параметр HTTP Request используется для написания HTML-кода.
OWASP предоставляет OWASP Enterprise Security API (ESAPI) на нескольких языках, включая, конечно, Java. ESAPI включает в себя гораздо больше функций, связанных с безопасностью, от XSS и CSRF до криптографии.
Чтобы исправить нашу XSS-уязвимость, мы просто используем кодировщик ESAPI (ESAPI 2.1.0). Исправление основано на написании полученного параметра количества HTML, закодированного вместо только что полученного. Таким образом, пользовательский веб-браузер не будет выполнять код javascript, так как он будет рассматриваться как значение параметра суммы.
Для исправления требуется только HTML-кодировка параметра количества (см. Xss_html_esapi.jsp ) следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
<form method= "POST" name= "sendForm" id= "sendForm" onsubmit= "return sendPaymentRequest()" > <% final String amount = request.getParameter( "amount" ); Enumeration<String> pNames = request.getParameterNames(); while (pNames.hasMoreElements()){ final String pName = pNames.nextElement(); final String pVal = request.getParameter(pName); final org.owasp.esapi.Encoder esapiEnc = DefaultEncoder.getInstance(); final String encPVal = esapiEnc.encodeForHTML(pVal); %> <input type= "hidden" name= "<%=pName%>" value= "<%=encPVal%>" /> <% } %> <table> |
Запуск ZAP для фиксированной JSP ( xss_html_esapi.jsp ) не сообщает об уязвимостях XSS.