XSS-атаки

168

Часто разработчики не подозревают об вносимых ими уязвимостях в плане безопасности. Это связано с тем, что со многими распространенными угрозами - включая внедрение сценариев и внедрение SQL - удивительно легко столкнуться. Чтобы минимизировать эти риски, поставщики технологических решений, такие как Microsoft, стремятся найти способы интегрирования проверок безопасности непосредственно в платформу программирования, тем самым защищая разработчиков приложений.

Одна из атак, в отношении которой обычно уязвимы веб-страницы - это атака внедрением сценария. Атака внедрением сценария происходит, когда злонамеренные дескрипторы или код сценария отправляются пользователем (обычно через простой элемент управления вроде TextBox), а затем позже визуализируются в HTML-странице. Хотя этот процесс визуализации предназначен для отображения предоставленных пользователем данных, фактически он выполняет сценарий. Атака внедрением сценария может иметь любое из множества последствий, от тривиального до существенного. Если переданные пользователем данные хранятся в базе и позже вставляются в страницы, используемые другими людьми, атака может повлиять на работу веб-сайта для всех пользователей.

Основной метод атаки внедрением сценария заключается в отправке клиентом содержимого со встроенными дескрипторами сценариев. Этими дескрипторами сценариев могут быть <script>, <object>, <applet> и <embed>. Хотя приложение может специально выполнять проверку на наличие этих дескрипторов и использовать HTML-кодирование для их замены безопасными HTML-сущностями, часто эта базовая проверка достоверности не производится.

Проверка достоверности запроса

Атаки внедрением сценария должны заботить всех веб-разработчиков, используют ли они ASP.NET, PHP или другие технологии разработки веб-приложений. ASP.NET включает средство, предназначенное для автоматического пресечения атак внедрением сценариев, которое называется проверкой достоверности запроса. Проверка достоверности запроса верифицирует информацию, введенную в отправленную форму, и генерирует ошибку при обнаружении потенциально опасных дескрипторов (подобных <script>).

Фактически, проверка достоверности запроса запрещает любые нечисловые дескрипторы, включая HTML-дескрипторы (такие как <b> и <img>), и дескрипторы, которые ничему не соответствуют (вроде <abcd>). Чтобы протестировать это средство проверки достоверности, создадим простую веб-страницу, подобную показанной на рисунке ниже. В этом простом примере содержатся текстовое поле и кнопка.

<form id="form1" runat="server">
    <div>
        <asp:TextBox ID="txtInput" runat="server" Width="298px"></asp:TextBox>
        <asp:Button ID="cmdSubmit" runat="server" Text="Отправить" OnClick="cmdSubmit_Click" />
        <br /><br />
        <asp:Label ID="Label1" runat="server" />
    </div>
</form>
protected void cmdSubmit_Click(object sender, EventArgs e)
{
    Label1.Text = "Вы вставили: " + txtInput.Text;
}
Тестирование атаки внедрением сценария

Теперь попытайтесь ввести блок содержимого с дескриптором сценария, а затем щелкните на кнопке, ASP.NET обнаружит потенциально опасное значение и сгенерирует ошибку. Если выполнить код локально, отобразится страница сообщения об ошибке с подробной информацией, как показано на рисунке ниже. (В случае удаленного запроса отобразится только общая страница сообщения об ошибке.)

Провалившаяся атака внедрением сценария

Отключение проверки достоверности запроса

В некоторых ситуациях правила проверки достоверности запроса оказываются слишком жесткими. Например, может существовать приложение, в котором пользователям требуется указывать HTML-дескрипторы или блоки XML-данных. (Примером может служить веб-приложение, ожидающее от пользователя блока сформатированной HTML-разметки, которая представляет перечень товаров, выставленных на аукцион, рекламу и т.п.) В этих ситуациях можно специально отключить проверку достоверности сценария, выполнив описанные ниже два действия.

Сначала установите свойство ValidateRequest директивы Page в false:

<%@ Page Language="C#" ValidateRequest="false" ... %>

Однако одно это изменение не оказывает никакого эффекта. Дело в том, что в версии ASP.NET 4 изменен способ проверки достоверности запроса за счет ее применения на более раннем этапе жизненного цикла обработки страницы. Цель этого изменения - предоставить проверке достоверности запроса возможность работать с другими. отличными от ASP.NET типами файлов. Недостаток этого подхода в том, что проверка достоверности запроса выполняется всегда, даже в случае установке свойства ValidateRequest в false.

Чтобы изменить это поведение, можно либо добавить специальный код проверки достоверности (как объяснено в следующем разделе), либо указать ASP.NET, чтобы она вернулась к поведению проверки достоверности, принятому в предшествующих версиях. Для этого добавьте элемент <httpRuntime> в свой файл web.config и установите атрибут requestValidationMode в 2.0, как показано в следующем примере:

<configuration>
  <system.web>
    <httpRuntime requestValidationMode="2.0" />
  </system.web>
</configuration>

Теперь посмотрим, что происходит при попытке отображения предоставленного пользователем значения в метки Label1. Если злоумышленник вводит текст <script>alert('Hello XSS');</script>, возвращенная веб-страница выполнит сценарий, как показано на рисунке ниже:

Успешная атака внедрением сценария

Имейте в виду, что во время атак внедрением сценариев этот сценарий всегда выполняется на стороне клиента. Однако это не означает, что влияние ограничивается единственным пользователем.

Во многих ситуациях предоставленные пользователем данные хранятся в таком расположении, как база данных, и могут просматриваться другими пользователями. Например, если пользователь предоставит блок сценария вместо названия компании, которое добавляется в базу данных, сценарий окажет влияние на другого пользователя, который запросит из базы полный список компаний.

Для предотвращения атак внедрением сценариев при отключенной проверке достоверности запросов нужно закодировать содержимое перед его отображением с помощью объекта Server. Измененная версия обработчика события Button.Click, неуязвимая для XSS-атак внедрением сценариев, имеет следующий вид:

protected void cmdSubmit_Click(object sender, EventArgs e)
{
    Label1.Text = "Вы вставили: " + Server.HtmlEncode(txtInput.Text);
}

Результат предпринятой атаки внедрением сценария на этой странице показан на рисунке ниже:

Обезвреженная атака внедрением сценария

Расширение проверки достоверности запроса

Для большинства веб-приложений стандартная проверка достоверности запроса ASP.NET будет работать отлично. Но в ситуациях, когда требуется выборочно разрешить определенные значения, которые обычно запрещены, или запретить дополнительные значения, систему проверки достоверности запроса можно расширить за счет написания собственного кода.

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

Чтобы расширить систему проверки достоверности запроса, понадобится создать класс, унаследованный от RequestValidator (из пространства имен System.Web.Util), и переопределить в нем метод IsValidRequestString():

public class CustomRequestValidator : RequestValidator
{
    protected override bool IsValidRequestString(
        HttpContext context, string value,
        RequestValidationSource requestValidationSource,
        string collectionKey,
        out int validationFailureIndex)
    {
        // ...
    }
}

Метод IsValidRequestString() принимает пять аргументов:

Используя эту информацию, легко создать подпрограмму быстрой и грубой проверки достоверности, которая изменит встроенное поведение ASP.NET. В следующем примере блок проверки достоверности выясняет, выполняется ли проверка достоверности формы. Если это не так, блок проверки достоверности запускает реализацию, заданную по умолчанию, перепоручая задачу ей. Если проверка выполняется, блок проверки достоверности ищет дескрипторы <script> в отправленном вводе. Он отклоняет значения, которые содержат этот фрагмент, но принимает все остальное, делая проверку значительно менее строгой, чем обычная проверка достоверности ASP.NET:

public class CustomRequestValidator : RequestValidator
{
    protected override bool IsValidRequestString(
        HttpContext context, string value,
        RequestValidationSource requestValidationSource,
        string collectionKey,
        out int validationFailureIndex)
    {
        if (requestValidationSource == RequestValidationSource.Form)
        {
            int errorIndex = value.IndexOf("<script>");
            if (errorIndex != -1)
            {
                validationFailureIndex = errorIndex;
                return false;
            }
            else
            {
                validationFailureIndex = 0;
                return true;
            }
        }
        else
        {
            return base.IsValidRequestString(context, value,
                requestValidationSource, collectionKey, out validationFailureIndex);
        }
    }
}

Этот пример - лишь простая демонстрация того, как работает специальная проверка достоверности. Однако его достаточно для понимания, что вставлять можно столько специального кода проверки достоверности, сколько требуется.

Чтобы усилить стандартную проверку достоверности ASP.NET, собственную реализацию целесообразно включить в одну цепочку со стандартной. После того, как значение пройдет специальную проверку, можно вызвать основную реализацию метода IsValidRequestString(), чтобы выполнить дополнительные встроенные проверки.

Для использования метод CustomRequestValidator должен быть зарегистрирован в файле web.config с помощью атрибута requestValidationType элемента <httpRuntime>:

<system.web>
    <httpRuntime requestValidationType="CustomRequestValidator"  />
</system.web>
Пройди тесты
Лучший чат для C# программистов