Не так давно прочитал очередную статью о SQL-инъекциях на хабре, статья была посвящена правда PHP, завязались споры как нужно поступать с данными от пользователя, через какие функции их прогонять, с PHP знаком поверхностно, но общую картину усвоил. Тогда и родилась идея показать как обстоят дела с безопасностью в ASP.NET MVC.
Прежде всего создадим простой сайт, пошаговое создание описывать не буду, скажу лишь связку используемых технологий: ASP.NET MVC4 и Entity Framework 4.3.1 (ORM для работы с БД). Проект можно будет скачать в конце статьи.
В итоге мы получили, сайт с одной статической новостью и возможностью добавлять комментарии.
Cross-Site Scripting (XSS)
Начнём наш взлом с XSS, будем внедрять скрипты на страницу с помощью добавления комментариев.
Сейчас мы попробуем добавить комментарий со скриптом:
Нажимаем добавить комментарий и получаем ошибку, увы до метода мы так и не дошли:
Что быстрее всего сделать, чтобы сайт заработал? Конечно отрубить валидацию для метода:
[ValidateInput(false)]
Вот не задача, снова наш скрипт не выполняется:
Происходит это потому-что, по умолчанию весь текст кодируется и выводится закодированным, ситуацию может изменить:
@Html.Raw()
Стоит помнить, что пользователю нельзя доверять, необходимо сохранять только проверенный контент, например, как это делает парсер хабра, удаляя потенциально опасный контент. Также с помощью XSS у вас могут быть украдены данные с помощью банально не закрытого тега img, при загрузке страницы конфиденциальные данные могут попасть третьему лицу. Ещё раз повторю, хоть я и привел пример как всё же записать скрипт в базу, но всегда стоит помнить, что в один прекрасный момент может появиться новый разработчик, который добавит ajax фич с использованием jquery и воспользовавшись $.html() вернёт XSS дыру в безопасности.
SQL-инъекция
Для взлома сайта с помощью инъекций я сделал отдельную страницу, на которой есть поле для поиска комментариев по имени автора, делать методы для работы с моделями чисел, bool`овских значений и прочего нет смысла, так как свою строку точно не передашь, на этапе связывания (binding) входных параметров и модели, эти данные будут отсеяны.
Собственно сколько я не пытался что-то сделать так и не получилось, всему виной использование ORM, никаких конкатенаций строк там нету, данные передаются параметрами и экранируются. Сложно представить человека, который не используется ORM при работе с БД, если он пишет проект с нуля и нет
ограничений по технологиям, возможно, если используются какие-то старые модули, на переписывание которых нет времени — это можно как-то оправдать, но тогда вся ответственность ложится на разработчика.
Cross-Site Request Forgery (CSRF)
Примером данной атаки может быть, например, какой-нибудь сайт с внутренней валютой и вам достаточно одного POST запроса, чтобы перевести деньги другому пользователю. Злоумышленник делает форму у себя на сайте, где в действии (form action) указывает на другой сайт, создает скрытые параметры: сумму,
кошелек и т.д… Будучи авторизованным на том сайте вы переведёте ему деньги (другие варианты: удаление чего-то, добавления, в общем большинство POST запросов).
Для борьбы с этим в MVC есть хелпер для представления, который должен быть в теле формы:
@Html.AntiForgeryToken()
Теперь атрибут для метода (Action) контроллера:
[ValidateAntiForgeryToken]
Проверим, что у нас получилось (я добавил эту логику на страницу с XSS), делаем обычный запрос:
Кроме скрытых полей у нас появились и куки:
Теперь удалим это скрытое поле и посмотрим на результат (варианта минимум три, удалить из представления, удалить с помощью Firebug и более интересный для меня это через Composer в Fiddler, перетаскиваем удачный запрос и просто удаляем этот параметр в Request Body):
Стоит помнить, что данный параметр не генерируется при каждом запросе и перехватив пакет в последующем можно осуществить взлом.
Скрытие информации
Многие не придают этому внимания, но я считаю, что данный пункт весьма важен. Выбирая когда-то замок для металлической двери я узнал, что многие замки вскрываются элементарно с помощью дрели, будь там три толстых ригеля (цилиндра, которые выезжают), но достаточно просверлить одно отверстие в нужном
месте (так сказать нанести точечных удар по слабым местам) и замок открыт. Аналогично, если вы говорите, что у вас такой-то IIS, такая-то версия ASP.NET и т.д. Вы оказываете неоценимую помощь взломщику! Я люблю чистить логи Elmah с кружкой чая и смотреть как у меня на сайте пытаются найти php, mysql, с
помощью чудных сервисов определить какая CMS используется и т.д.
Вот, что сейчас возвращает мой сайт:
Убираем X-Powered-By:
<system.webServer>
...
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
...
</system.webServer>
Версию ASP.NET:
<system.web>
...
<httpRuntime enableVersionHeader="false" />
...
</system.web>
Версию MVC в Application_Start:
MvcHandler.DisableMvcResponseHeader = true;
И самое сложное — это сервер, для чего мы сделаем HttpModule:
public class CustomServerHeaderModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PreSendRequestHeaders += OnPreSendRequestHeaders;
}
public void Dispose() { }
private void OnPreSendRequestHeaders(object sender, EventArgs e)
{
HttpContext.Current.Response.Headers.Set("Server", "Apache 2000 Server");
}
}
и добавим в конфиге:
<system.webServer>
...
<modules runAllManagedModulesForAllRequests="true">
...
<add name="CustomServerHeader" type="HackingMVC.HttpModules.CustomServerHeaderModule" />
</modules>
...
<system.webServer>
В итоге мы получили вот такой результат:
Вместо заключения
Не даром ASP.NET славиться своей безопасностью, очень активно развивается MVC, который с каждой версией становится всё интереснее и интереснее. Остались не рассмотрены некоторые моменты, что-то я упустил, а о чём-то достаточно просто упомянуть, в любом случае невозможно рассмотреть столь объемную тему в рамках одной статьи. Стоит заострить внимание на том, что очень важно использовать SSL на сайте, так как в противном случае ваши данные могут быть похищены при авторизации, украдена сессия на любой странице, токен авторизации или любые другие данные, что сводит на нет многую защиту. Помните и о JSON Hijacking и о том, что он не с проста кидает предупреждение, если пытаться получить данные через GET запрос без указания разрешения, таким способом стоит отдавать только те данные, которые не страшно потерять. Я показал лишь часть проблем, с которыми вы можете столкнуться и на которые стоит обращать внимание при разработке.
P.S. Приветствуются пожелания и варианты взлома данного сайта: архив. (11,6 Мб, так как в солюцию включены скаченные NuGet пакеты)
Автор: eforce
Спасибо, за статью!