Безопасность C# приложений: топ-10 уязвимостей, которые должен знать каждый разработчик
Разработка на C# и платформе .NET — мощный инструмент для создания корпоративных и веб-приложений. Однако даже самый надежный код может содержать бреши, которые приведут к утечке данных, потере репутации и финансовым убыткам. В этой статье мы разберем 10 самых распространенных уязвимостей C# приложений, основанных на OWASP Top 10, с практическими примерами и способами защиты.
1. SQL-инъекции (SQL Injection)
Это одна из старейших, но до сих пор актуальных угроз. Уязвимость возникает, когда пользовательский ввод напрямую конкатенируется в SQL-запрос.
Уязвимый код:
string userName = Request.QueryString["name"];
string query = "SELECT * FROM Users WHERE Name = '" + userName + "'";
SqlCommand cmd = new SqlCommand(query, connection);
Безопасный код (параметризованные запросы):
string userName = Request.QueryString["name"];
string query = "SELECT * FROM Users WHERE Name = @name";
SqlCommand cmd = new SqlCommand(query, connection);
cmd.Parameters.AddWithValue("@name", userName);
Рекомендация: Всегда используйте параметризованные запросы или Entity Framework, который автоматически экранирует ввод.
2. Межсайтовый скриптинг (XSS)
XSS-атаки позволяют злоумышленнику внедрить вредоносный скрипт в веб-страницу. В C# это часто происходит при выводе непроверенных данных через @Html.Raw().
Уязвимый код:
@Html.Raw(Model.Comment)
Безопасный код (кодирование вывода):
@Html.Encode(Model.Comment)
Рекомендация: Используйте Razor-синтаксис @Model.Comment (он автоматически кодирует HTML) и никогда не применяйте @Html.Raw() без проверки.
3. Подделка межсайтовых запросов (CSRF)
CSRF заставляет авторизованного пользователя выполнить нежелательное действие на сайте (например, перевод денег). В ASP.NET Core защита встроена, но ее нужно правильно включить.
Уязвимый код (отсутствие антифоргового токена):
<form method="post" action="/Account/Delete">
<button type="submit">Удалить аккаунт</button>
</form>
Безопасный код (с AntiForgeryToken):
<form method="post" action="/Account/Delete">
@Html.AntiForgeryToken()
<button type="submit">Удалить аккаунт</button>
</form>
Рекомендация: Добавьте атрибут [ValidateAntiForgeryToken] к вашим POST-методам и используйте @Html.AntiForgeryToken() в формах.
4. Небезопасное хранение паролей
Хранение паролей в открытом виде или с использованием слабых хешей (MD5, SHA1) — грубая ошибка.
Уязвимый код:
string passwordHash = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(password));
Безопасный код (использование bcrypt/Argon2):
using BCrypt.Net;
string passwordHash = BCrypt.HashPassword(password, workFactor: 12);
Рекомендация: Используйте библиотеки BCrypt.Net или Microsoft.AspNetCore.Identity, которые автоматически генерируют соль и используют современные алгоритмы.
5. Раскрытие конфиденциальных данных в исключениях
Вывод полного стека ошибок пользователю может раскрыть структуру приложения, строки подключения и пути к файлам.
Уязвимый код (в production):
catch (Exception ex)
{
return Content(ex.ToString());
}
Безопасный код:
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при обработке запроса");
return StatusCode(500, "Внутренняя ошибка сервера");
}
Рекомендация: Включите UseDeveloperExceptionPage() только в среде разработки. В production используйте глобальную обработку ошибок с логированием.
6. Небезопасная десериализация
Десериализация данных из ненадежных источников (например, из запроса) может привести к выполнению произвольного кода.
Уязвимый код:
var formatter = new BinaryFormatter();
using (var stream = Request.Body)
{
var obj = formatter.Deserialize(stream);
}
Безопасный код (использование JSON с валидацией):
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var model = JsonSerializer.Deserialize<MyModel>(Request.Body, options);
Рекомендация: Избегайте BinaryFormatter, SoapFormatter и JavaScriptSerializer. Используйте System.Text.Json или Newtonsoft.Json с явными контрактами.
7. Использование уязвимых компонентов
Старые версии библиотек и фреймворков содержат известные CVE (Common Vulnerabilities and Exposures).
Пример проблемы:
Библиотека Newtonsoft.Json версии 12.0.1 имеет уязвимость, позволяющую выполнить десериализацию с произвольным кодом.
Решение:
// Обновление через NuGet Package Manager
Update-Package Newtonsoft.Json -Version 13.0.3
Рекомендация: Используйте dotnet list package --vulnerable для аудита и настройте автоматическое обновление через Dependabot или Renovate.
8. Недостатки аутентификации и управления сессиями
Слабые пароли, отсутствие MFA, неправильная настройка JWT и кук — частые проблемы.