Безопасность C# приложений: топ-10 уязвимостей на практике

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

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

Начать курс

Безопасность C# приложений: топ-10 уязвимостей на практике

Безопасность — одна из важнейших составляющих разработки современных приложений на C# и .NET. Даже небольшой пропущенный баг может привести к утечке данных или полной компрометации системы. В этой статье мы разберём 10 самых распространённых уязвимостей, с которыми сталкиваются разработчики C#, и покажем, как их избежать на практике.

1. SQL-инъекции (SQL Injection)

Самая старая и опасная уязвимость. Возникает, когда пользовательский ввод напрямую подставляется в SQL-запрос.

Уязвимый код:

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

Безопасный код (параметризованные запросы):

string login = txtLogin.Text;
string query = "SELECT * FROM Users WHERE Login = @login";
SqlCommand cmd = new SqlCommand(query, connection);
cmd.Parameters.AddWithValue("@login", login);

Дополнительная защита: используйте ORM (Entity Framework) — он автоматически параметризует запросы.

2. Межсайтовый скриптинг (XSS)

Злоумышленник внедряет вредоносный JavaScript-код на страницу через пользовательский ввод.

Уязвимый код:

string comment = Request.Form["comment"];
Response.Write("<div>" + comment + "</div>");

Безопасный код (кодирование вывода):

string comment = Request.Form["comment"];
Response.Write("<div>" + HttpUtility.HtmlEncode(comment) + "</div>");

В ASP.NET Core используйте @Html.Encode() или Razor-синтаксис с автоматическим кодированием.

3. Подделка межсайтовых запросов (CSRF)

Атака, при которой злоумышленник заставляет пользователя выполнить нежелательное действие на сайте, где он авторизован.

Уязвимый код (отсутствие защиты):

[HttpPost]
public IActionResult DeleteAccount(int userId)
{
    // Удаление аккаунта без проверки токена
    return Ok();
}

Защита с помощью антифордж-токенов в ASP.NET Core:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult DeleteAccount(int userId)
{
    // Безопасное удаление
    return Ok();
}

На клиенте токен передаётся через скрытое поле формы или заголовок.

4. Небезопасная десериализация

При десериализации данных из ненадёжного источника злоумышленник может выполнить произвольный код.

Уязвимый код (BinaryFormatter):

BinaryFormatter formatter = new BinaryFormatter();
using (FileStream fs = new FileStream("data.bin", FileMode.Open))
{
    var obj = formatter.Deserialize(fs); // Опасно!
}

Безопасные альтернативы:

  • Используйте System.Text.Json или Newtonsoft.Json с ограничением типов.
  • Включите TypeNameHandling.None.
  • Избегайте BinaryFormatter, SoapFormatter и LosFormatter.

5. Недостатки аутентификации и управления сессиями

Слабая аутентификация, хранение паролей в открытом виде, предсказуемые токены сессий.

Ошибки:

  • Хранение пароля в открытом виде: User.Password = txtPassword.Text;
  • Собственная реализация хеширования без соли.
  • Использование Guid.NewGuid() для генерации токенов — слишком предсказуемо.

Правильный подход:

  • Используйте ASP.NET Core Identity — встроенное решение.
  • Хешируйте пароли с помощью BCrypt.Net или PBKDF2.
  • Токены сессий генерируйте через RandomNumberGenerator.

6. Неправильная обработка ошибок и раскрытие информации

Вывод стека вызовов, строк подключения или путей к файлам в ответе сервера.

Уязвимый код:

try
{
    // код
}
catch (Exception ex)
{
    Response.Write(ex.ToString()); // Опасно!
}

Безопасный код:

try
{
    // код
}
catch (Exception ex)
{
    _logger.LogError(ex, "Ошибка при обработке");
    return StatusCode(500, "Внутренняя ошибка сервера");
}

Настройте UseDeveloperExceptionPage только для разработки, в продакшене используйте UseExceptionHandler.

7. Недостатки контроля доступа

Пользователь может получить доступ к данным или функциям, на которые у него нет прав.

Уязвимый код:

[HttpGet("{id}")]
public IActionResult GetOrder(int id)
{
    var order = _context.Orders.Find(id);
    return Ok(order); // Нет проверки, принадлежит ли заказ текущему пользователю
}

Безопасный код:

[HttpGet("{id}")]
public IActionResult GetOrder(int id)
{
    var userId = User.FindFirst(ClaimTypes.NameIdentifier).Value;
    var order = _context.Orders
        .FirstOrDefault(o => o.Id == id && o.UserId == userId);
    if (order == null) return Forbid();
    return Ok(order);
}

8. Небезопасное хранение конфиденциальных данных

Хранение строк подключения, API-ключей или паролей в коде или конфигурационных файлах без шифрования.

Ошибка:

<connectionStrings>
    <add name="MyDb" connectionString="Server                

Блоги

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