Создание AntiForgeryToken посредством внедрения зависимостей

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

public class AntiForgeryToken
{
    private readonly string _referenceToken;

    public AntiForgeryToken()
    {
        _referenceToken = Guid.NewGuid().ToString();
    }
    public string ReferenceToken
    {
        get { return _referenceToken; }
    }
}

В моем базовом классе для моей MasterPage у меня есть HiddenField, обернутый свойством с именем: ReferenceToken

protected virtual void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        InjectToken();
    }

    ValidateToken();
}

private void InjectToken()
{
    var token = ObjectFactory.GetInstance<AntiForgeryToken>();
    ReferenceToken = token.ReferenceToken;
}

private void ValidateToken()
{
    var token = ObjectFactory.GetInstance<AntiForgeryToken>();
    if (ReferenceToken.Equals(token.ReferenceToken, SC.InvariantCultureIgnoreCase)) 
            return;
    ...do stuff for failed token
}

У меня есть дескриптор StructureMap, хранящий токен внутри сеанса, поэтому он сохраняется для каждого сеанса пользователя, будет ли все это действительной реализацией схемы AntiForgery?

Редактировать: Кажется, в моем вопросе есть некоторая путаница, да, я понимаю, что ASP.NET MVC имеет встроенную схему AntiForgeryToken, этот вопрос явно о том, как воссоздать это для WebForms для предотвращения использования атаки CSRF (подделка межсайтовых запросов). Я так понимаю, это никоим образом не отменяет необходимости правильной авторизации прав пользователя.

Я собирался привести ту самую ссылку, которую разместили @Neal и @solairaja: Предотвратите подделку межсайтовых запросов (CSRF) с помощью помощника AntiForgeryToken() ASP.NET MVC. В этой статье объясняется больше о том, что такое CSRF-атака и как MVC останавливает ее, однако их решение неприменимо к веб-формам, поэтому я решил реализовать свое собственное.

Увидев ответ @Neal, я думаю, что это, скорее всего, будет принятым ответом, поскольку я не осознавал, что могу просто получить фактический исходный код из инструмента MVC, который, скорее всего, заменит создание руководства. Но я оставлю вопрос открытым, если у кого-то еще есть ценная информация для добавления.


person Chris Marisic    schedule 09.11.2009    source источник
comment
Я хотел использовать токены MVC на странице WebForms, т.е. опубликовать из WebForm в MVC и все еще проверять. См. этот ответ: stackoverflow.com/questions/1347728/   -  person Keith    schedule 01.04.2010


Ответы (8)


Крис,

ваш подход более или менее имитирует подход к защите от подделки в MVC, за исключением того, что они используют массив байтов в кодировке base64, сгенерированный из RNGCryptoServiceProvider, и сохраняют токен как на странице (поле скрытой формы), так и в файле cookie. Я бы рекомендовал перенести больше логики в реализацию токена (например, инкапсулировать большую часть логики проверки внутри токена).

Код для реализации MVC находится в свободном доступе по адресу http://aspnet.codeplex.com/sourcecontrol/changeset/view/23011?projectName=aspnet#391757, если возможно, вам, вероятно, следует просмотреть это, а также http://blog.codeville.net/2008/01.09/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/ для анализа и идей.

person Neal    schedule 17.11.2009
comment
Я не знал, что могу получить источник для этого! И да, у меня гораздо лучшая инкапсуляция инъекции/проверки токена. Я просто удалил все это для краткости, особенно когда это ничего не дает для моего фактического вопроса. Я также добавлю часть cookie, чтобы следить за их реализацией. - person Chris Marisic; 17.11.2009
comment
Ваша текущая реализация имеет важное двойное назначение: файл cookie сеанса используется в качестве заполнителя для файла cookie защиты от подделки, поэтому он не совсем необходим (но снижает нагрузку на сеанс). - person Neal; 17.11.2009

Веб-формы ASP.NET по умолчанию предотвращают атаки CSRF, если вы используете View State. Если только вы не отключили состояние представления в своем приложении, вы добавляете код для решения проблемы, которой у вас нет.

Состояние просмотра предотвращает атаки CSRF
.Net CSRF Guard — OWASP< /а>

person Bryan Rehbein    schedule 16.12.2010

Во-первых, полагаю, мне следует спросить... что вы на самом деле подразумеваете под "антифальсификацией"? Что вас беспокоит в том, что вас подделывают? Остальное из того, что следует ниже, это просто общая информация, которая приходит на ум...

Одна вещь, которую я бы изменил, - не использовать Guid.NewGuid. Ведутся споры о том, является ли это случайным или нет и, следовательно, не подходит для целей безопасности. Тем не менее, я думаю, что это будет очень сложная атака.

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

Вы делаете это через ssl? Во-первых, ssl — это линия защиты номер один от атак «человек посередине». Это может быть недостаточно безопасно (и другие могут спорить об этом) для всех нужд, но если вас беспокоят такие вещи, это отправная точка, если ничего другого. Если нет, то как убедиться, что вы получаете ответ от правильной машины, а не от посредника, который отвечает первым? Без SSL или его эквивалента ваш токен так же легко украдут, как и все остальное, что вы делаете.

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

Я бы не пытался заменить SSL чем-то другим, созданным вами, если вы так думаете. Однако, если вы беспокоитесь о повторном воспроизведении, однократная генерация токенов — это один из способов остановить его. Если вы беспокоитесь о том, что пользователь отправит одни и те же данные формы дважды, это один из способов сделать это. Я бы также рассмотрел ваш общий дизайн приложения, если вы обеспокоены этим. Многие повторы и подобные сценарии можно обойти, если правильно разработать бизнес-логику, например, не доверяя клиенту отправлять вам конфиденциальную информацию, например цену товара в корзине.

Также ознакомьтесь с различными руководствами Microsoft по безопасности ASP.NET и IIS (например, Google ASP.NET или сайт безопасности IIS: microsoft.com) в качестве отправной точки. Многие умные люди уже решили многие вопросы за нас.

person Jim L    schedule 12.11.2009
comment
Да, этот токен будет поверх SSL, чтобы еще больше предотвратить атаки повторного воспроизведения/человека посередине. Я не думал, что токен одноразового использования обеспечит гораздо большую надежность как в реальной безопасности, так и просто не даст идиотам щелкнуть по материалу до того, как последняя обратная передача даже не завершится, пока вы не подняли этот вопрос. - person Chris Marisic; 13.11.2009
comment
Единственное, о чем я начал думать с одноразовыми токенами, это то, что было бы эффективным способом отслеживания действительных токенов, поскольку у пользователя может быть открыто несколько окон, чтобы сохранить список всех токенов в сеансе, а затем при отправке для истечения срока действия. токен, удалив его из списка, чтобы любые последующие попытки отправить ту же форму не увенчались успехом, пока страница не завершит ее в оба конца и не сохранит новый токен в состоянии просмотра? - person Chris Marisic; 13.11.2009

будет ли все это действительной реализацией схемы AntiForgery?

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

Я не знаю, каковы ваши требования, поэтому я не могу сказать, действительно ли схема «действительна». Тем не менее, я могу отметить несколько вещей:

  1. Если GUID живет только на странице, то что помешает пользователю прочитать страницу на одном компьютере и отправить форму на другом? Было бы хорошо связать его с файлом cookie или сеансом (который также использует файл cookie), если вы еще этого не сделали.
  2. Если GUID записан на странице в виде статического скрытого поля <input>, то форма может быть прочитана и отправлена ​​ботами. Вы можете обойти это, потребовав скрипт на странице для обработки токена перед его отправкой.
  3. Вы используете ViewState? Если это так, вы можете просто установить ViewStateUserKey на какое-то повторяющееся значение, уникальное для каждого клиента; он выполняет функцию, аналогичную той, что вы описали здесь.
person RickNZ    schedule 15.11.2009
comment
У меня есть дескриптор StructureMap, хранящий токен внутри сеанса, поэтому он сохраняется для каждого сеанса пользователя. - person Chris Marisic; 16.11.2009

Как сказал НИК, для меня тоже код, который вы дали, выглядит так, как будто вы вставляете GUID на страницу, а затем ищете тот же GUID, когда страница возвращается. Это тоже хорошая идея, когда вы используете карту структуры, хранящуюся в сеансе.

Но для этой концепции AntiForgery доступны некоторые встроенные методы.

Пожалуйста, сначала обратитесь к приведенной ниже ссылке и поймите

http://blog.maartenballiauw.be/post/2008/09/01/ASPNET-MVC-preview-5s-AntiForgeryToken-helper-method-and-attribute.aspx

В настоящее время,

Проверьте приведенную ниже ссылку для подробного описания и методологии подхода.

http://msdn.microsoft.com/en-us/library/system.web.mvc.htmlhelper_methods.aspx

http://blog.codeville.net/2008/09/01/prevent-cross-site-request-forgery-csrf-using-%20aspnet-mvcs-antiforgerytoken-helper/

Спасибо !!

person solairaja    schedule 17.11.2009

Мне кажется, что он генерирует канарейку с каждым запросом. Что произойдет, если пользователь откроет несколько вкладок? :)

Проблема с вашим подходом (и реализацией ASP.NET MVC) заключается в том, что его реализация зависит от разработчиков. Безопасность, подобная этой, должна быть отключена, а не включена. Когда я написал модуль AntiCSRF, вместо этого я использовал жизненный цикл страницы ASP.NET, что означает отсутствие изменений в базовый код, если только разработчик не захотел исключить страницу из проверок CSRF. Вы заметите, что он использует один токен, который действует в течение всего времени существования сеанса браузера этого пользователя — нет необходимости менять токен при каждом запросе.

Теперь я написал модуль в основном как способ проиллюстрировать некоторые концепции моей будущей книги (вставьте здесь рекламу усмехается), вы, конечно, можете использовать ViewStateUserKey, но опять же, это согласие, а не отказ.

person blowdart    schedule 17.11.2009
comment
Я думаю, вы также пропустили, где я сказал, что токены будут храниться в сеансе с помощью StructureMap. И код, размещенный здесь, предназначен для краткости, поскольку я объяснил, что я верю @Neal, у меня гораздо лучшая инкапсуляция инъекции/проверки, которая фактически не реализуется на странице (поэтому она совместима с DRY), это просто не имеет значения для моего вопрос. - person Chris Marisic; 17.11.2009
comment
Я хотел сказать, что вы все еще полагаетесь на разработчиков, наследующих от вашего базового класса страницы. Если вы подключаетесь к событию page_prerender через HTTP-модуль, вам не нужно беспокоиться о наследовании разработчиками нужного класса. Неважно, где вы храните токен, который вы проверяете (хотя легко ли работает StructureMap в веб-ферме?) - person blowdart; 17.11.2009
comment
Я взглянул на ваш модуль, он выглядит действительно хорошо, я, должно быть, искал неправильные ключевые слова в Google, и я не мог найти это раньше! - person Chris Marisic; 17.11.2009
comment
Я сомневаюсь, что мое приложение когда-либо понадобится размещать на веб-ферме в ближайшее время, однако, если бы это было так, я бы заменил фактическое состояние сеанса на распределенный кеш, а затем, возможно, потребовалось бы написать собственный поставщик кэширования для SM. На самом деле он у меня есть внутри базового класса для моей главной страницы, из которой получаются все главные страницы, поскольку он имеет другие функциональные возможности, глобальные для сайта. - person Chris Marisic; 17.11.2009
comment
Хех, ну я написал модуль, чтобы быть параноиком. Если вы единственный разработчик, и вы всегда будете использовать главную страницу, то это справедливо. Но как только кто-то другой начнет редактировать ваш код... :D - person blowdart; 17.11.2009
comment
Большую часть времени я предпочитаю условности конфигурации. Слишком много раз я видел конфигурационный ад. - person Chris Marisic; 17.11.2009
comment
Ну, это одна строка конфигурации. Я не уверен, что все ваши страницы используют определенную мастер-страницу, это нормально... - person blowdart; 17.11.2009

Первое правило безопасности: Не пытайтесь установить собственную безопасность.

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

Извините, если я совершенно неправильно понял ваше описание...

person Mark Seemann    schedule 10.11.2009
comment
Я почти уверен, что именно так написан токен Microsoft AntiForgery для MVC, который использует скрытое поле на странице. Если бы я использовал MVC, я бы использовал их функциональные возможности независимо от того, что они не включены в веб-формы. - person Chris Marisic; 10.11.2009
comment
Мне придется пойти с DV по этому вопросу, поскольку вы не добавили никакой информации или не предоставили уже существующее решение для резервного копирования вашего первого правила. - person Chris Marisic; 10.11.2009

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

Например. является ли веб-страница «страницей создания пользователя», я бы проверил, что аутентифицированный пользователь имеет разрешение на создание новых пользователей. Является ли страница «страницей редактирования пользователя X», я бы проверил, что аутентифицированный пользователь имеет право изменять пользователя X. Возможно, потому, что он сам является пользователем X или администратором.

Тем не менее, использование GUID не очень безопасно. Гиды генерируются на основе алгоритма, написанного для уникальности, а не случайности. Насколько я знаю, существует три допустимых алгоритма: основанный на имени, основанный на времени и случайный. Если алгоритм Guid, используемый системой (который может быть изменен в будущей версии .NET), основан на времени, то угадать действительные Guid не очень сложно.

person Pete    schedule 17.11.2009
comment
DV, так как мой вопрос не касается авторизации/доступа пользователей - person Chris Marisic; 17.11.2009
comment
Пит, иди и прочитай blog.codeville.net/2008/09/01/, чтобы понять, почему и как токены защиты от подделки. CSRF отправит файл cookie сеанса пользователя и, следовательно, будет выглядеть как аутентифицированный пользователь, пока атака происходит в рамках активного сеанса. Токены защиты от подделки предназначены для одноразового использования, поэтому окно эксплойта значительно сокращается. - person Neal; 17.11.2009
comment
@Neal - спасибо за эту ссылку, она не знала об этой конкретной уязвимости. - person Pete; 18.11.2009