Thread.CurrentPrincipal неправильно утверждает, что он является каким-либо ненормальным - PullRequest
30 голосов
/ 31 августа 2010

Я вижу запросы на моем сервере, которые, как представляется, были сделаны каким-либо ненормальным клиентом, хотя я уверен, что они были сделаны аутентифицированным пользователем - у меня есть журналы fiddler, показывающие, что клиент отправил действительные куки-файлы аутентификации asp.net, и журналы сервера, указывающие, что cookie-файл прибыл и является действительным. Проблема наблюдается во всех браузерах.

Поток данных:

  1. Пользователь посещает URL-адрес входа на компьютере, являющемся частью веб-фермы (все на одном компьютере, ключи дешифрования)
  2. При успешной аутентификации форм пользователь перенаправляется на ограниченный URL-адрес, его домашнюю страницу
  3. Домашняя страница отображается правильно, знает имя пользователя и включает в себя javascript для выполнения 7 асинхронных постбэков для получения дополнительных данных
  4. Javascript запускает 7 запросов http.get, обращаясь к различным машинам в веб-ферме (предположим, круговой прием)
  5. Сервер проверяет запрос: ~ 0,01% не могут пройти проверку подлинности.

Мысли

Теперь в деталях:

Очень небольшое количество асинхронных запросов попадает на мой сервер (с доказательством того, что ими не манипулировали и не фальсифицировали) и, по-видимому, является анонимным. Из 7 сделанных запросов некоторое число может работать или не работать (т.е. 5/7 будет успешным, 2 - неудачным). Кажется, что нет никаких шаблонов в успехе / неудаче. В тех случаях, когда мои запросы кажутся анонимными, CurrentPrincipal.Identity записывает:

Thread.CurrentPrincipal.Identity.IsAuthenticated; // false
Thread.CurrentPrincipal.Identity.Name; // null (or empty, unsure off hand)

Сбрасывая коллекцию http.context.request.params в файл журнала, я вижу следующие подходящие (и очищенные) свойства (полные параметры приведены ниже):

context: {"userId":10000,"userName":"johnsmith"}
HTTP_COOKIE:.ASPXAUTH=[valid auth cookie value]
HTTP_X_REQUESTED_WITH:XMLHttpRequest
X-Requested-With: XMLHttpRequest
    AUTH_TYPE: 
    AUTH_USER: 
    AUTH_PASSWORD: 
    LOGON_USER: 
    REMOTE_USER: 
    HTTP_COOKIE: .ASPXAUTH=[valid auth cookie value]

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

CookiePath: /
Expiration: 9/23/2105 8:14:22 PM
Expired: False
IsPersistent: True
IssueDate: 8/30/2010 2:54:22 PM
Name: johnsmith
UserData: 
Version: 2

Не уверен, как действовать в этой точке. Эта проблема, похоже, обострилась в связи с нашей недавней миграцией на mvc 2.0 / asp.net 4.0, но моя уверенность в этом не так высока.

Я обратился к горстке моих клиентов, у которых была эта проблема, и это было еще более неприятно (но отражает то, что я могу прочитать в своих журналах). Оказавшись в этом состоянии, трудно выйти из него. Очистка кэша и файлов cookie, похоже, не имеет никакого эффекта. Но, переключаясь на новый браузер, и это в целом нормально. Аналогично, подождать несколько часов и вернуться с тем же браузером, и это тоже в целом нормально, но не всегда. Как было сказано ранее, это наблюдается во всех браузерах.

Есть предложения?
Kevin




------------
Вот оставшаяся часть фрагмента журнала (очищенного для pii), который я записал:

8/30/2010 2:54:43 PM: Anonymous user detected:
    Identity Name:
    IsAuthenticated::False
HttpContextInformation to follow:

8/30/2010 2:54:43 PM: Request Param collection contents:
context: {"userId":10000,"userName":"johnsmith"}
    .ASPXAUTH: A3C6615642F1F543397160C84C0E016C8439BDF400B0130AADAB82C93E77FFF3BEAD7726223F02049FA65B2C3E1773928C0371C4F580F2432C1538551BC5654020AD76F37159BA6BB68D7A68744AE036
    ASP.NET_SessionId: m5vit3cyv0rsiosqg5xmhhuu
    ALL_HTTP: HTTP_CONNECTION:close
HTTP_ACCEPT:text/javascript, text/html, application/xml, text/xml, */*
HTTP_ACCEPT_ENCODING:gzip, deflate
HTTP_ACCEPT_LANGUAGE:en-us
HTTP_COOKIE:.ASPXAUTH=A3C6615642F1F543397160C84C0E016C8439BDF400B0130AADAB82C93E77FFF3BEAD7726223F02049FA65B2C3E1773928C0371C4F580F2432C1538551BC5654020AD76F37159BA6BB68D7A68744AE036
HTTP_HOST:www.host.com
HTTP_REFERER:http://www.host.com/
HTTP_USER_AGENT:Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
HTTP_X_FORWARDED_FOR:166.137.139.139
HTTP_X_REQUESTED_WITH:XMLHttpRequest

    ALL_RAW: Connection: close
Accept: text/javascript, text/html, application/xml, text/xml, */*
Accept-Encoding: gzip, deflate
Accept-Language: en-us
Cookie: .ASPXAUTH=A3C6615642F1F543397160C84C0E016C8439BDF400B0130AADAB82C93E77FFF3BEAD7726223F02049FA65B2C3E1773928C0371C4F580F2432C1538551BC5654020AD76F37159BA6BB68D7A68744AE036
Host: www.host.com
Referer: http://www.host.com/
User-Agent: Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
X-Forwarded-For: 166.137.139.139
X-Requested-With: XMLHttpRequest

    APPL_MD_PATH: /LM/W3SVC/792523/Root
    APPL_PHYSICAL_PATH: d:\localpath\
    AUTH_TYPE: 
    AUTH_USER: 
    AUTH_PASSWORD: 
    LOGON_USER: 
    REMOTE_USER: 
    CERT_COOKIE: 
    CERT_FLAGS: 
    CERT_ISSUER: 
    CERT_KEYSIZE: 
    CERT_SECRETKEYSIZE: 
    CERT_SERIALNUMBER: 
    CERT_SERVER_ISSUER: 
    CERT_SERVER_SUBJECT: 
    CERT_SUBJECT: 
    CONTENT_LENGTH: 0
    CONTENT_TYPE: 
    GATEWAY_INTERFACE: CGI/1.1
    HTTPS: off
    HTTPS_KEYSIZE: 
    HTTPS_SECRETKEYSIZE: 
    HTTPS_SERVER_ISSUER: 
    HTTPS_SERVER_SUBJECT: 
    INSTANCE_ID: 792523
    INSTANCE_META_PATH: /LM/W3SVC/792523
    LOCAL_ADDR: 10.248.50.207
    PATH_INFO: /resource
    PATH_TRANSLATED: d:\localpath\resource
    QUERY_STRING: context={%22userId%22:10000,%22userName%22:%22johnsmith%22}
    REMOTE_ADDR: 10.208.205.171
    REMOTE_HOST: 10.208.205.171
    REMOTE_PORT: 37966
    REQUEST_METHOD: GET
    SCRIPT_NAME: /resouce
    SERVER_NAME: www.host.com
    SERVER_PORT: 80
    SERVER_PORT_SECURE: 0
    SERVER_PROTOCOL: HTTP/1.0
    SERVER_SOFTWARE: Microsoft-IIS/6.0
    URL: /resource
    HTTP_CONNECTION: close
    HTTP_ACCEPT: text/javascript, text/html, application/xml, text/xml, */*
    HTTP_ACCEPT_ENCODING: gzip, deflate
    HTTP_ACCEPT_LANGUAGE: en-us
    HTTP_COOKIE: .ASPXAUTH=A3C6615642F1F543397160C84C0E016C8439BDF400B0130AADAB82C93E77FFF3BEAD7726223F02049FA65B2C3E1773928C0371C4F580F2432C1538551BC5654020AD76F37159BA6BB68D7A68744AE036
    HTTP_HOST: www.host.com
    HTTP_REFERER: http://www.host.com/
    HTTP_USER_AGENT: Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
    HTTP_X_FORWARDED_FOR: 166.137.139.139
    HTTP_X_REQUESTED_WITH: XMLHttpRequest


8/30/2010 2:54:43 PM: Auth Ticket collection contents:
    CookiePath: /
    Expiration: 9/23/2105 8:14:22 PM
    Expired: False
    IsPersistent: True
    IssueDate: 8/30/2010 2:54:22 PM
    Name: johnsmith
    UserData: 
    Version: 2

Ответы [ 6 ]

20 голосов
/ 20 октября 2010

Этот ответ работает, но разочаровывает и тревожит одновременно.

Я провел 2 месяца, работая неполный рабочий день с технической поддержкой MSDN, и мы наконец нашли способ обойти эту проблему. Я собираюсь оставить это для Microsoft, чтобы решить проблему, поскольку это почти наверняка проблема в .net framework. Но сначала позвольте мне кратко изложить проблему, дать дополнительную соответствующую справочную информацию и несколько интересных вещей, которые мы нашли на этом пути.

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

Также по симптомам: при ведении журнала мы увидели, что мобильные браузеры (iphone, ipad и android) подвергались непропорционально сильному воздействию, хотя все браузеры и операционные системы подвергались воздействию в некоторой степени. И последний случайный симптом: он будет работать для пользователя один день, а не на следующий, а позже днем, снова работать. Конечно, переключение браузеров почти всегда решало проблему.

Мы быстро решили проблему с аутентификацией, вероятно, вокруг файла cookie аутентификации. Странная часть заключалась в том, что я смог доказать (отслеживая), что запросы, содержащие ошибки, содержали надлежащий файл cookie, который я смог расшифровать, но что инфраструктура .net игнорировала недетерминированным способом. В конце концов я начал регистрировать все запросы, которые были в этом состоянии - файл cookie авторизации игнорировался платформой .net, но, по-видимому, действительным для меня, и обнаружил, что это затронуло около 2% моих пользователей.

Я переключился с использования Thread.CurrentPrincipal.Identity на HttpContext.Current.User.Identity, но безрезультатно, и перепробовал несколько других настроек. Любопытно, что единственное изменение, которое я смог сделать, сделав вмятину, - это миграция на .net 4 framework (с 3.5). Проблема стала на порядок хуже. Также пробовал различные конфигурации балансировщика нагрузки и был в состоянии исключить конфигурации нескольких компьютеров - тот же компьютер, который выдал cookie-файл auth, позже отклонил бы его.

Чтобы повторить симптомы: у нас были определенные пользователи (недетерминированные), которые иногда не могли бы использовать наш веб-сайт в аутентифицированном режиме (также недетерминированном). Милый.

К этому моменту команда разработчиков в Редмонде была вовлечена, а также в тупик. Но они выдвинули предложение, которое в конечном итоге решило проблему, вот так: Попробуйте заставить каркас Microsoft.net использовать куки в качестве режима аутентификации, а не использовать состояние без куки:

<authentication mode="Forms">
  <forms cookieless="UseCookies" />
</authentication>

Перевернул коммутатор, и мгновенно проблемные запросы закончились (как только я истек сеанс тех, кто находился в нечетном состоянии).

Хотя я рад, что проблема была решена - или, скорее, обойдена, меня беспокоит недетерминированная обработка различных браузеров. Почему .net Framework однажды увидит браузер и будет относиться к нему как к поддерживающим куки, а позже в тот же день скажет, что должен использовать сеанс без куки?

Мое последнее беспокойство связано с тем, сколько других сайтов теряют 2% своего аутентифицированного трафика, не зная? Учитывая исправление, это очень похоже на ошибку в .net 4 framework.

1 голос
/ 22 сентября 2010

Не используйте это в аутентификации ASP.NET:

Thread.CurrentPrincipal = principal;

Вместо этого придерживайтесь:

HttpContext.Current.User = principal;

Для получения информации см. Эту статью текст ссылки , но что более важно, комментарии, включая первый и последний, - статья устарела в 2004 году, но аргументы все еще действительны сегодня.

Поэтому вместо:

Thread.CurrentPrincipal.Identity.IsAuthenticated; // false Thread.CurrentPrincipal.Identity.Name; // null (or empty, unsure off hand)

Вы должны использовать:

 HttpContext.Current.User.Identity...

В этом случае вы также можете использовать AuthenticateRequest вместо PostAuthenticateRequest, потому что нет проблемы с потоком для обхода.

0 голосов
/ 29 октября 2014

Я полагаю, исходя из моего прошлого опыта, что эта проблема на самом деле вызвана тем, что ASP.NET не распознает IE10 +.Неизвестный браузер и его возможности, он использует аутентификацию без файлов cookie (неверное или, по крайней мере, устаревшее предположение).

Обновления для файлов определений браузера были выпущены здесь.Проблема отсутствует в .NET 4.5

https://support.microsoft.com/kb/2600088

http://support.microsoft.com/kb/2600100

http://support.microsoft.com/kb/2608565

0 голосов
/ 10 декабря 2012

re bounty:

Я вижу это в приложении Azure с asp.net 4.0, cookie есть, и вы можете расшифровать его с помощью FormsAuthentication.Decrypt и прочитать все (не просрочено, исправитьстоимость и т. д. и т. д.);так же, как описанный ОП.В отличие от сценария OP, я уже использовал UseCookies, и все равно получаю то же самое.Баунти по особой причине в asp.net, которая может вызвать эту проблему и решение.

Мой случай был такой глупой:

  1. Выдача токенов через FormsAuthentication.SetAuthCookieи соответствующее перенаправление
  2. Настройка тега <forms> в web.config
  3. Проверка User.Identity.IsAuthenticated на странице / ложь
  4. Файл cookie есть, и вы можетедаже расшифровать его с помощью FormsAuthentication.Decrypt

проблема: не забудьте установить <authentication mode="Forms">, lol, total fail ...

Мои 2 цента на OP: некоторые внутренниеСсылки / перенаправления / JS могут нарушить работу, когда пытается использовать авторизацию без файлов cookie.Кроме того, обнаружение поддержки cookie не очень точное.

0 голосов
/ 21 сентября 2010

Вот аутентификация, которую я использую с большинством моих приложений ASP.NET / Mvc, для которых требуется базовая аутентификация. Я считаю, что это поможет и позволит вам хранить дополнительные данные в AuthenticationCookie. Если вы используете это до того, как .Net выполнит их аутентификацию .Net переопределит ваши настройки текущего принципала и пользовательских свойств, использование PostAuthenticateRequest решит проблему переопределения. Дайте мне знать, если у вас есть какие-либо вопросы.


// Code that goes in the Global.asax.cs
// that runs after .Net has done it's authentication
protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
    IPrincipal user = HttpContext.Current.User;

    if (user == null) { return; }

    FormsIdentity formsIdentity = user.Identity as FormsIdentity;

    if (formsIdentity == null || !formsIdentity.IsAuthenticated) { return; }

    Principal principal = new Principal(new Identity(formsIdentity.Ticket));
    HttpContext.Current.User = principal;
    Thread.CurrentPrincipal = principal;
}

// Base implementation of the System.Security.Principal.IPrincipal interface.
public class Principal : System.Security.Principal.IPrincipal
{
    #region Fields

    private IIdentity _identity = null;

    #endregion

    #region Constructors

    public Principal(IIdentity identity)
    {
        _identity = identity;
    }

    #endregion

    #region Properties

    public IIdentity Identity
    {
        get
        {
            return _identity;
        }
    }

    #endregion

    #region Methods

    public bool IsInRole(string role)
    {
        return (_identity != null && _identity.IsAuthenticated);
    }

    #endregion
}



// Base implementation of the System.Security.Principal.IIdentity interface. 
public class Identity : System.Security.Principal.IIdentity
{
    #region Fields

    private readonly int _userId;
    private readonly bool _isAuthenticated;
    private readonly string _userName;

    #endregion

    #region Constructors

    public Identity(FormsAuthenticationTicket formsAuthTicket)
    {
        if (formsAuthTicket == null)
        {
            throw new NullReferenceException("FormsAuthenticationTicket may not be null.");
        }

        if (string.IsNullOrEmpty(formsAuthTicket.UserData))
        {
            throw new NullReferenceException("FormsAuthenticationTicket.UserData may not be null or empty.");
        }

        string[] userData = formsAuthTicket.UserData.Split(new[] {"|"}, StringSplitOptions.RemoveEmptyEntries);

        if (userData.Length < 1)
        {
            throw new ArgumentOutOfRangeException("formsAuthTicket", userData, "UserData does not contain a UserId and or a SiteId");
        }

        _userId = Convert.ToInt32(userData[0]);
        _isAuthenticated = !formsAuthTicket.Expired;
        _userName = formsAuthTicket.Name;
    }

    #endregion

    #region Properties

    public int UserId
    {
        get
        {
            return _userId;
        }
    }
    public string AuthenticationType
    {
        get
        {
            return "Forms";
        }
    }
    public bool IsAuthenticated
    {
        get
        {
            return _isAuthenticated;
        }
    }
    public string Name
    {
        get
        {
            return _userName;
        }
    }

    #endregion
}

Надеюсь, это поможет решить вашу проблему.

0 голосов
/ 11 сентября 2010

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

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

ForsmAuthentication.Decrypt(...)
...