В декабре 2021 года я начал работу над новым дополнением для Optimizely CMS 12. Это дополнение представило новый способ управления политикой безопасности контента в CMS, который был разработан, чтобы быть более доступным для нетехнических людей. Это дополнение позволяло администратору CMS определять для каждого источника, какому источнику разрешено выполнять какие действия с веб-сайтом, при этом каждое изменение подвергалось полной проверке. Это дополнение теперь доступно на ряде веб-сайтов Optimizely CMS и прошло ряд тестов на проникновение.
Я планировал, что следующая эволюция этого дополнения будет включать возможность управления заголовками совместного использования ресурсов между источниками (CORS) из интерфейса администрирования CMS. CORS позволяет API или веб-сайту определять, какие третьи стороны могут использовать ресурс, а также как они могут использовать этот ресурс. Это может быть важным требованием безопасности, если вы создаете управляемую или гибридную CMS, которая предоставляет конечные точки для использования другим веб-сайтом.
Цель этого обновления надстройки Stott Security заключалась в том, чтобы позволить редактору CMS устанавливать все следующие заголовки в удобном для управления интерфейсе:
Я добавил в надстройку Stott Security новую вкладку под названием «CORS», которая позволяет редактировать и сохранять все эти заголовки вместе.
Если опция «Включить совместное использование ресурсов между источниками (CORS)» отключена, при запросе на веб-сайт от третьей стороны ответ будет обрабатываться так, как будто CORS полностью запрещен. Если эта опция включена, по умолчанию разрешены все источники; Только после добавления записи в «Разрешенные источники» другим источникам снова будет отказано в доступе. То же самое поведение применимо к заголовкам и методам HTTP: все они считаются разрешенными до тех пор, пока определенные методы или заголовки не будут определены как разрешенные.
Возникла явная задача сделать пользовательский интерфейс отзывчивым и предоставить пользователю достаточно информации, не перегружая его информацией. На таких веб-сайтах есть множество онлайн-ресурсов, таких как Веб-документы MDN которые описывают CORS и различные заголовки CORS, более подробные описания которых были сочтены слишком большими для этого пользовательского интерфейса.
Внедрение CORS
Когда у меня появился пользовательский интерфейс для управления CORS и таблицы, отсортированные для хранения конфигурации, я смог приступить к поиску способа реализации такого поведения. Сначала я попытался создать собственное промежуточное программное обеспечение для управления этим, и меня быстро осенило, что добиться этого будет очень сложно. Access-Control-Allow-Origin
заголовок, например, может содержать только *
, происхождение сайта, сделавшего запрос, или его полное отсутствие. Это не позволяет веб-сайту раскрывать третьим лицам, которые могут их использовать, а только то, разрешено ли стороннему веб-сайту использовать их или нет.
Пытаясь понять, как лучше с этим справиться, я добавил CORS на свой образец веб-сайта, используя стандартные библиотеки Microsoft, вызвав метод AddCors()
и UseCors()
методы внутри моего startup.cs
.
Перейдя к декомпилированной версии UseCors()
Я смог увидеть CorsПромежуточное ПО который был реализован Microsoft, и увидеть, что он использовал реализацию ICorsPolicyProvider
чтобы получить CorsPolicy
объект и реализация ICorsService
оценить CorsPolicy сам. Глядя на декомпилированный код для AddCors()
Я видел, что внедрение зависимостей требует ICorsPolicyProvider
и ICorsService
мы использовали TryAdd, который добавляет реализации этих интерфейсов по умолчанию, только если они еще не были объявлены.
///
/// Adds cross-origin resource sharing services to the specified .
///
/// The to add services to.
/// The so that additional calls can be chained.
public static IServiceCollection AddCors(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.AddOptions();
services.TryAdd(ServiceDescriptor.Transient());
services.TryAdd(ServiceDescriptor.Transient());
return services;
}
Тогда реализация оказалась относительно простой. Создайте собственную реализацию ICorsPolicyProvider
который использовал данные, сохраненные моей надстройкой, для создания экземпляра CorsPolicy для использования реализациями по умолчанию ICorsService
. Интерфейс ICorsPolicyProvider
содержал только один метод, который я мог реализовать.
///
/// A type which can provide a for a particular .
///
public interface ICorsPolicyProvider
{
///
/// Gets a from the given
///
/// The associated with this call.
/// An optional policy name to look for.
/// A
Task GetPolicyAsync(HttpContext context, string? policyName);
}
Чтобы свести к минимуму проблемы с производительностью, мое хранилище данных представляет собой одну таблицу с очень плоской записью, которая преобразуется в объект домена с несколькими свойствами и коллекциями. Чтобы сократить дальнейшие обращения к SQL-серверу и создание объекта домена, а затем его сопоставление с CorsPolicy объект, я также сохранил скомпилированный CorsPolicy объект в Optimizely ISynchronizedObjectInstanceCache
который затем будет признан недействительным при любом последующем обновлении политики CORS.
public async Task GetPolicyAsync(HttpContext context, string? policyName)
{
var policy = _cache.Get(CacheKey);
if (policy == null)
{
policy = await LoadPolicy();
_cache.Add(CacheKey, policy);
}
return policy;
}
Конечным результатом является полностью функционирующая редактируемая политика CORS CMS, которую можно обновлять и которая может немедленно вступить в силу, не требуя каких-либо изменений кода или развертывания. Чтобы узнать больше о том, как CORS реализован в .NET Core, вы можете прочитать Глубокое погружение в библиотеку ASP.NET Core CORS. написано Эндрю Лок и просмотреть открытый исходный код для CorsПромежуточное ПО на Гитхабе.
В бета-версии
Я классифицирую версию 2.0.0 этого дополнения как находящуюся в стадии бета-тестирования до тех пор, пока один или несколько веб-сайтов CMS не будут запущены и не будут использовать конфигурацию CORS, а любые возникшие проблемы будут либо расставлены по приоритету, либо исправлены. Если вы хотите использовать бета-версию 2.0.0, не стесняйтесь установить ее на свой веб-сайт Optimizely CMS 12 и присоединиться к обсуждение страница на Репозиторий GitHub.
09 октября 2023 г.