TL; DR Может ли пользовательский токен, содержащийся в свойстве WindowsIdentity
Token
(например, someIdentity.Token
), подделываться так, что:
var validated = new WindowsIdentity(someIdentity.Token);
... вернет экземпляр, который утверждает, что представляет пользователя, который на самом деле не был аутентифицирован, но имеет IsAuthenticated
установить true
, допустимые .Name
и .User
свойства и т.д.?
Ниже я наложил несколько ограничений на это; это, по-видимому, невозможно для полностью ложного доказательства.
Полная история:
В этот ответ, Damien_The_Unbeliever ловко продемонстрировал, что какой-то мой код можно обмануть, полагая, что он действительный аутентифицированный пользователь в экземпляре WindowsIdentity
, когда он этого не сделал. Короче говоря, мой код предполагал, что если Thread.CurrentPrincipal.Identity
был экземпляром WindowsIdentity
, а IsAuthorized
был true
, он представлял аутентифицированного пользователя, и я мог полагаться на SID в .User
:
WindowsIdentity identity = Thread.CurrentPrincipal == null
? null
: Thread.CurrentPrincipal.Identity as WindowsIdentity;
if (identity != null && identity.IsAuthenticated && !identity.IsAnonymous) {
// ...use and trust the SID in identity.User, the
// username in identity.Name, etc....
}
(Есть причина, по которой этот код использует поток, а не WindowsIdentity.GetCurrent()
.)
Его код, чтобы обмануть (слегка измененный):
var ident = WindowsIdentity.GetCurrent();
Thread.CurrentPrincipal = new WindowsPrincipal(ident);
var fakeSid = new SecurityIdentifier("S-1-3-0"/* E.g., some SID you want to trick me into believing is the real user */);
typeof(WindowsIdentity).GetField("m_user", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(ident, fakeSid);
И конечно, если вы это сделаете, тогда позвоните моему коду выше, мой код обманут. Кудос Дэмиен.
Итак, в настоящей моде гонки гонок, здесь мой пересмотренный код, который ловит пародию и отрицает ее:
WindowsIdentity identity = Thread.CurrentPrincipal == null
? null
: Thread.CurrentPrincipal.Identity as WindowsIdentity;
if (identity != null && identity.IsAuthenticated && !identity.IsAnonymous) {
var validated = new WindowsIdentity(identity.Token);
if (!validated.User.Equals(identity.User) || !validated.IsAuthenticated || validated.IsAnonymous) {
// Something fishy is going on, don't trust it
} else {
// Good! Use the validated one
identity = validated;
// ...use and trust the SID in identity.User, the
// username in identity.Name, etc....
}
}
Как вы можете видеть, он принимает Token
из предоставленного идентификатора и создает новый экземпляр WindowsIdentity
, используя этот токен. Если идентификаторы идентификаторов идентификаторов совпадают, мы продолжаем, доверяя проверке. (Документация для WindowsIdentity(IntPtr token)
говорит, что начальное значение IsAuthenticated
будет false
, но это просто неправильно в моих тестах, предполагающих Я создал его с действующим токеном пользователя.)
Единственный способ, которым я могу видеть, что это может быть обмануто, будет заключаться в поддельном токене пользователя, который тем не менее передает проверки, которые Windows делает с ним. Мне это кажется маловероятным. Но тогда это область невежества для меня.
Границы
Я должен отметить, что я просто стреляю в разумную степень безопасности единого входа здесь, делая все возможное. Если вредоносное приложение успешно начало перехватывать системные вызовы/скомпрометированные ОС Windows, ну, просто не так много, что я смогу сделать с этим. Как заметил Дэмиен в комментариях к этому другому вопросу, он мог бы создать контейнер-контейнер, который полностью игнорировал бы сильное именование (и, таким образом, мог бы дать мне совершенно поддельный тип WindowsIdentity
). Справедливо. Совершенство убивает. Я просто не хочу оставлять двери открытыми, как тот, который Дамиан любезно продемонстрировал. Если бы я выпустил систему и ее легко взломали в поле, я бы смутился по этому поводу.: -)