Лучшие Практики Безопасности 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