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). Справедливо. Совершенство убивает. Я просто не хочу оставлять двери открытыми, как тот, который Дамиан любезно продемонстрировал. Если бы я выпустил систему и ее легко взломали в поле, я бы смутился по этому поводу.: -)

