Атрибут AllowAnonymous полезен для любых разработчиков ASP, когда речь идет о тестировании во время активной разработки, поскольку он позволяет разработчику обходить аутентификацию и/или авторизацию. Однако только в очень специфических обстоятельствах вы хотите проверить это в своем исходном коде. Если вы сделаете это в неправильных условиях, это приведет к уязвимостям в системе безопасности. Хорошо продуманный процесс запроса на включение может снизить вероятность того, что такие изменения попадут в кодовую базу. Тем не менее, люди могут ошибаться, и жуки могут проскользнуть незамеченными. Более надежный подход — ввести автоматические тесты для сканирования наличия атрибута в ваших контроллерах и их методах. Если они будут найдены там, где их быть не должно, тесты провалятся, и сборка не будет успешной (при условии наличия приличного процесса CI).

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

В моем примере кода я буду использовать шаблонный проект ASP, ориентированный на .NET 6, и я буду использовать MSTest в качестве среды тестирования. При желании тесты можно легко перенести в NUnit, XUnit или любую другую среду тестирования C#. Полностью проект можно посмотреть здесь: https://github.com/Zailef/PreventAllowAnonymous.

Модульные тесты

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

Ранее я упоминал, что иногда имеет смысл использовать AllowAnonymousAttribute в рабочей среде (например, для конечной точки входа в систему). Таким образом, я рекомендую следовать чему-то вроде принципа наименьших привилегий, никогда не украшая весь класс контроллера с помощью AllowAnonymousAttribute, а скорее украшая определенные методы контроллера. Таким образом, вы разрешаете анонимные запросы на детальном уровне. GitHub Gist ниже показывает два модульных теста: один завершится ошибкой, если контроллер API будет украшен AllowAnonymousAttribute на уровне класса, а другой завершится ошибкой, если какие-либо методы в контроллере API будут украшены атрибутом, когда им явно не разрешено быть. Разрешается ли украшать метод или нет, зависит от принадлежности к списку _allowAnonymousPermittedMethods в верхней части определения класса.

Узкие интеграционные тесты

Узкие интеграционные тесты раскручивают приложение в памяти и выставляют клиента, через которого мы можем делать запросы к приложению, а затем мы можем делать утверждения об ответах и ​​их кодах состояния. Это означает, что если мы ожидаем, что неавторизованный и/или неавторизованный запрос получит ответ с кодом состояния 401, мы можем написать тест для конечной точки, который выявит проблему, вызванную наличием ошибки AllowAnonymousAttribute.

Заключение

Защита от AllowAnonymousAttribute попадания в исходный код довольно тривиальна и может решаться на разных уровнях тестирования. Я бы порекомендовал использовать модульные тесты, подобные тем, которые продемонстрированы в этой статье, специально для предотвращения этой проблемы. Наличие набора интеграционных тестов, настроенных для обнаружения множества потенциальных проблем на другом уровне, является просто хорошей практикой, к которой следует стремиться. Хотя пример проекта является базовым и полностью надуманным, концепции остаются верными.