TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.74K subscribers
Post #3318 1.36K
День 2773. #BestPractices
Лучшие Практики Безопасности REST API в
ASP.NET Core. Окончание
1-3
4-7
8-12

13. Настройка заголовков безопасности
Заголовки, такие как Content-Security-Policy, X-Content-Type-Options и Referrer-Policy, указывают браузеру, как обрабатывать ваши ответы — какие скрипты могут выполняться, следует ли угадывать тип контента, какой объём информации об источнике следует раскрывать. Добавьте их с помощью небольшого промежуточного ПО, которое запускается при каждом ответе:
app.Use(async (context, next) =>
{
var hdrs = context.Response.Headers;
hdrs["X-Content-Type-Options"] = "nosniff";
hdrs["Referrer-Policy"] = "no-referrer";
hdrs["Content-Security-Policy"] = "default-src 'self'";
hdrs["X-Frame-Options"] = "DENY";

await next();
});

- X-Content-Type-Options: nosniff предотвращает попытки браузера угадывать (и неправильно обрабатывать) тип контента;
- Content-Security-Policy ограничивает источники загрузки скриптов, стилей и других ресурсов;
- Referrer-Policy контролирует, какая часть вашего URL-адреса отправляется на другие сайты;
- X-Frame-Options: DENY предотвращает встраивание ваших ответов во фрейм (кликджекинг).
Для чистого JSON API эти параметры больше имеют смысл при отображении ответов в браузере, но они являются недорогой страховкой для любого API.
Примечание: в продакшене рекомендуется использовать поддерживаемую библиотеку или обратный прокси для управления этими заголовками и более строгую Content-Security-Policy, адаптированную под ваше приложение.

14. Безопасное хранение секретов
Ключи, строки подключения и токены никогда не должны храниться в системе контроля версий. Секрет, добавленный в файл appsettings.json, является утечкой — он навсегда остаётся в истории Git и виден всем, кто имеет доступ к репозиторию. Кроме того, ИИ-агенты могут напрямую считывать ваши секреты из конфигурации, если вы не запретите им доступ.

В процессе разработки используйте менеджер секретов .NET. В производственной среде используйте переменные среды или управляемое хранилище секретов, например Azure Key Vault:
builder.Configuration.AddAzureKeyVault(
new Uri("https://myapi.vault.azure.net/"),
new DefaultAzureCredential());

var connectionString = builder
.Configuration
.GetConnectionString("Myapi");

Ваш код затем считывает конфигурацию одинаково, независимо от того, откуда взялось значение. Приложению не важен источник — важно лишь то, чтобы значение не находилось в файле репозитория.

15. Защита от CSRF, где это необходимо
Защита от межсайтовой подделки запросов (CSRF) важна, когда вы аутентифицируете с помощью cookie. CSRF обманывает браузер авторизованного пользователя, заставляя его отправлять нежелательный запрос, используя cookie, который браузер автоматически добавляет. Если ваш API аутентифицирует с помощью cookie, вам необходимы токены защиты от подделки запросов:
builder.Services.AddAntiforgery(opts =>
{
opts.HeaderName = "X-CSRF-TOKEN";
});

var app = builder.Build();
app.UseAntiforgery();

Затем требуйте валидный токен в конечных точках, изменяющих состояние:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(CreateOrderRequest request)
{ /* … */ }

Замечание: API, основанные исключительно на токенах, в значительной степени защищены от CSRF-атак. Если ваш клиент отправляет JWT в заголовке Authorization (а не cookie), браузер не добавляет его автоматически, поэтому поддельный межсайтовый запрос не содержит учётных данных. Защита от подделки запросов в основном необходима для конечных точек, аутентифицируемых с помощью cookie — приложений, отрисовываемых сервером, и API, использующих аутентификацию на основе cookie. Согласуйте защиту с вашей моделью аутентификации: cookie нуждаются в защите от CSRF, а bearer-токены, как правило, нет.

16. Версионирование и удаление устаревших небезопасных конечных точек
Версионирование позволяет отказаться от неудачного дизайна, не нарушая работу клиентов. Когда конечная точка оказывается небезопасной или плохо структурированной, нужен способ ввести исправленную версию и поэтапно вывести из эксплуатации старую.
Добавьте пакет Asp.Versioning.Mvc и отметьте старую версию как устаревшую:
builder.Services.AddApiVersioning(opts =>
{
opts.DefaultApiVersion = new ApiVersion(2, 0);
opts.ReportApiVersions = true;
});

…

[ApiController]
[ApiVersion("1.0", Deprecated = true)]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/orders")]
public class OrdersController : ControllerBase
{
…
}

ReportApiVersions добавляет заголовки api-supported-versions и api-deprecated-versions к вашим ответам, чтобы клиенты видели предстоящее устаревание и могли перейти на новую версию до того, как вы удалите v1. Это превращает ситуацию «мы не можем это исправить, потому что клиенты зависят от этого» в управляемую миграцию.

17. Журналирование и аудит событий безопасности
События безопасности — неудачные попытки входа в систему, отказы в авторизации, подозрительные шаблоны запросов — необходимо логировать с достаточным контекстом для восстановления произошедшего. Записывайте их в виде структурированных журналов:
[HttpPost("login")]
public async Task<IActionResult> Login(LoginRequest request)
{
var result = await _authService.AuthenticateAsync(request);
if (!result.Succeeded)
{
_logger.LogWarning(
"Неудачный вход для {Email}, IP: {IpAddress}",
request.Email, HttpContext.Connection.RemoteIpAddress);

return Unauthorized();
}

return Ok(result.Token);
}

Регистрируйте сбои аутентификации, отказы в авторизации и всё, что выглядит как попытка взлома. Записывайте достаточно контекста для проведения настоящего криминалистического расследования, что может включать конфиденциальные данные, если этого требует ваша модель угроз: учётная запись, исходный IP и предпринятое действие.
Т.к. эти журналы могут содержать конфиденциальные данные, относитесь к ним как к конфиденциальным: храните их там, где их могут читать только авторизованные лица, и применяйте правила хранения и контроля доступа.

18. Поддерживайте актуальность зависимостей
Ваш API зависит от десятков NuGet-пакетов и среды выполнения .NET, и каждый из них является потенциальной точкой взлома, когда обнаруживается уязвимость. Поддержание актуальности — одна из самых важных вещей. .NET может предоставить вам список уязвимых пакетов:
dotnet list package --vulnerable --include-transitive
dotnet list package --outdated

Выполняйте это регулярно и привяжите сканирование в ваш конвейер CI, чтобы обнаружение уязвимости зависимости роняло сборку.
Обновляйте NuGet-пакеты и среду выполнения .NET по расписанию, а не только при возникновении проблем. В сочетании с такими инструментами, как Dependabot или оповещениями безопасности GitHub, это устраняет уязвимость, на которую чаще всего полагаются злоумышленники.

Источник:
https://antondevtips.com/blog/rest-api-security-best-practices-in-aspnetcore
  • 👍 6
More from @netdeveloperdiary
  1. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
  2. Sep 25, 2026День 2795. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Начало Проблема с позиц…
  3. Sep 24, 2026День 2794. #Оффтоп #Здоровье Сегодня будет необычный пост. Завтра в Москве стартует конфер…
  4. Sep 23, 2026День 2793. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
  5. Sep 22, 2026День 2792. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
  6. Sep 21, 2026🔍Тестовое собеседование с Senior C# разработчиком уже завтра 22 сентября(уже завтра!) в 1…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →