Какое имя TargetName следует использовать при вызове InitializeSecurityContext (Negotiate)? - программирование
Подтвердить что ты не робот

Какое имя TargetName следует использовать при вызове InitializeSecurityContext (Negotiate)?

Вопрос

При вызове InitializeSecurityContext какое значение передается параметру TargetName?

Пересмотренный фон

Я вызываю функцию InitializeSecurityContext:

InitializeSecurityContextA(
      @pAS.hcred,           //[in] credentials
      phContext,            //[in] optional] Context handle structure
      pszTargetName,        //[in, optional] Target name
      0,                    //[in] context requirements
      0,                    //[in] reserved1, must be zero
      SECURITY_NATIVE_DREP, //[in] target data representation
      pInput,               //[in] optional] SecBufferDescription
      0,                    //[in] reserved2, must be zero
      @pAS.hctxt,           //[in, out] pointer to context handle structure
      @OutBuffDesc,         //[in, out] pointer to SecBufferDesc
      ContextAttributes,    //[out] context attributes
      @lifetime);           //[out] expiration timestamp

Что мне передать на pszTargetName?

Я пробовал

  • null: InitializeSecurityContextA(@pAS.hcred, phContext, null, ...);
  • "": InitializeSecurityContextA(@pAS.hcred, phContext, "", ...);
  • "spn/HOSTNAME": InitializeSecurityContextA(@pAS.hcred, phContext, "spn/HOSTNAME", ...);
  • spn/HOSTNAME.DOMAIN.COM: InitializeSecurityContextA(@pAS.hcred, phContext, "spn/HOSTNAME.DOMAIN.COM", ...);
  • "cargocult/PROGRAMMING": InitializeSecurityContextA(@pAS.hcred, phContext, "cargocult/PROGRAMMING", ...);
  • "http/TFS.DOMAIN.COM": InitializeSecurityContextA(@pAS.hcred, phContext, "http/TFS.DOMAIN.COM", ...);
  • "http/HOSTNAME": InitializeSecurityContextA(@pAS.hcred, phContext, "http/HOSTNAME", ...);
  • "qwertyasdf": InitializeSecurityContextA(@pAS.hcred, phContext, "qwertyasdf", ...);

  • "AuthSamp": InitializeSecurityContextA(@pAS.hcred, phContext, "AuthSamp", ...);

Все они либо сбой, либо переход на NTLM.

Примечание. Моя машина подключена к домену, но домен не с именем domain.com или даже hostname.domain.com или даже qwertyasdf. Поэтому я не удивлен, что эти попытки потерпят неудачу. Но люди сказали, что попробуйте такие вещи, как http/HOSTNAME, поэтому я вставляю http/HOSTNAME.

Фон

Функция InitializeSecurityContext (Negotiate) имеет необязательный параметр TargetName:

pszTargetName [in, optional]

Указатель на строку с завершающим нулевым символом, которая указывает имя участника службы (SPN) или контекст безопасности целевого сервера.
Приложения должны предоставлять действительный SPN, чтобы помочь смягчить атаки повтора.

Что это должно быть?

Дополнительные сведения

Я пытаюсь проверить набор учетных данных пользователя, например:

Boolean ValidateCredentials(String username, String password, String domain)
{
   ...
}

Для проверки набора учетных данных пользователя необходимо использовать API SSPI. Первая функция для вызова - InitializeSecurityContext. Одним из параметров InitializeSecurityContext является строка "TargetName".

Я попробовал оставить его null, но Application Verifier запускает точку останова, выписывая ошибку:

ПРОВЕРКА ОСТАНОВКИ 00005003: pid 0xF08:
InitializeSecurityContext использует цель NULL или искаженную цель для службы Kerberos.
Пожалуйста, см. PszTargetName для значения цели.
      00000000: Не используется.
      00000000: Не

На этом этапе было бы полезно помнить, что поставщик Negotiate попытается использовать Kerberos, но отступит к NTLM. В случае Negotiate, Kerberos или NTLM параметр TargetName задокументирован как:

Имя участника службы (SPN) или контекст безопасности целевого сервера.

Но тогда что я должен пройти?

Я попытался сделать то, что делает статья базы знаний SSPI, ничего (т.е. pass null):

Как проверить учетные данные пользователя в операционных системах Microsoft

ss = _InitializeSecurityContext(
        &pAS->hcred,
        pAS->fInitialized ? &pAS->hctxt : NULL, 
        NULL,        //<-------pszTargetName
        0, 
        0,
        SECURITY_NATIVE_DREP, 
        pAS->fInitialized ? &sbdIn : NULL,
        0, 
        &pAS->hctxt, 
        &sbdOut, 
        &fContextAttr, 
        &tsExpiry);

Но ничего (т.е. null) не работает.

Примечание. Статья в КБ была полностью перезаписана в 2007 году. В своем первоначальном воплощении 1999 года они передали "AuthSamp" в качестве цели, но это также терпит неудачу.

Бонус:

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

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

Бонусная чата 2

Из документации верификации приложения:

Проигрыватель Verifier обнаруживает следующие ошибки:

  • Пакет NTLM напрямую указан в вызове AcquireCredentialsHandle (или API-интерфейсе более высокого уровня).

  • Имя цели в вызове InitializeSecurityContext равно NULL.

  • Имя цели в вызове InitializeSecurityContext не является правильно сформированным доменным именем типа SPN, UPN или NetBIOS.

  • Последние два случая заставят Negotiate вернуться в NTLM либо напрямую (первый случай), либо косвенно (контроллер домена вернет ошибку "главный не найден" во втором случае, в результате чего Negotiate вернется),

  • Плагин также регистрирует предупреждения, когда обнаруживает понижение до NTLM; например, когда SPN не найден контроллером домена. Они регистрируются только как предупреждения, поскольку они часто являются законными случаями - например, при аутентификации в систему, не присоединенную к домену.

В моем случае домен, на который я проверяю, равен null (так как я не знаю имя домена машины или даже если есть домен). Но результаты одинаковы, если доменное имя моего машинного кода жесткого кода.

Обновление 3

Значения pszTargetName, которые вызывают ошибку AppVerifier, но вход в систему успешно:

  • null
  • ""
  • "AuthSamp"
  • "qwertyasdf"
  • * имя домена, в котором я проверяю (например, "avatopia.com")
  • * имя домена, к которому машина присоединена (например, "avatopia.com")
  • * имя домена, в котором находится учетная запись пользователя (например, "avatopia.com")

Значения pszTargetName, которые не вызывают ошибку AppVerifier, но вход в систему не работает:

  • "http/HOSTNAME"
  • "http/TFS.DOMAIN.COM"
  • "frob/GROBBER"
  • "cargocult/PROGRAMMING"
  • "spn/HOSTNAME"
  • "spn/HOSTNAME.DOMAIN.COM"

Значения pszTargetname, которые не вызывают ошибку AppVerifier, успешно завершены: и:

  • ни один

Обновление 4

Что я пытаюсь сделать: выяснить, действительно ли имя пользователя/пароль.

  • У меня есть имя пользователя: например. "ian"
  • У меня есть пароль: например. "pass1"

Теперь существует еще одна морщина, что учетная запись ian может быть локальной учетной записью или учетной записью домена. И вам нужно решить, есть ли ian локальная или доменная учетная запись, прежде чем вы сможете спросить. Это связано с тем, что ian может иметь две учетные записи:

  • ian в домене stackoverflow.com
  • ian на локальной машине

Поэтому мне нужно указать, хочу ли я:

  • запросить определенный домен (например, stackoverflow.com) или
  • спросите локальную машину (которую я буду представлять как ".")

Теперь мы можем найти перекрестную ссылку:

Username  Password  Domain             Machine on domain?  Validate as
========  ========  =================  ==================  ==============
iboyd     pass1     .                  No                  Local account
iboyd     pass1     (empty)            No                  Local account
iboyd     pass1     stackoverflow.com  No                  Domain account

iboyd     pass1     .                  Yes                 Local account
iboyd     pass1     (empty)            Yes                 Domain account
iboyd     pass1     stackoverflow.com  Yes                 Domain account

Обновление 5

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

enter image description here

Я попытаюсь войти в домен TURBOENCABULATOR. Я указал, что хочу попробовать аутентифицироваться в домене TURBOENCABULATOR, предварительно указав мое имя пользователя как:

TURBOENCABULATOR\ian

Примечание: Я очень сомневаюсь, что в сети есть домен, называемый turboencabulator, поскольку само имя приходит только от автоматизации Rockwell. Попытка входа в систему почти наверняка потерпит неудачу. Но как Windows проверяет их?

Как Windows пытается проверить эти учетные данные? Как Windows проверить учетные данные:

  • Имя пользователя: ian
  • Пароль: pass1
  • Домен: TURBOENCABULATOR

Использует ли Windows интерфейс пакета поддержки безопасности? Предполагая, что для проверки подлинности Windows использует Negotiate или Kerberos, что означает Windows как параметр pszTarget? Почти наверняка учетные данные, которые я вводил, не будут действительны. Как Windows определить, действительны ли они? Какой API будет Windows для проверки подлинности?

Windows может проверять credentails. Я хочу также проверить учетные данные.

Возможно, вместо того, чтобы пытаться подключиться к домену TURBOENCABULATOR, я пытаюсь подключиться к домену turboencabulator.com, добавив домен к моему имени пользователя как turboencabulator.com\ian:

enter image description here

Тот же вопрос. Как Windows проверять учетные данные? Я хочу делать то, что делает Windows. Предполагая, что Windows использует Kerberos для авторизации, что Windows передает в качестве параметра pszTargetName в SSPI?

Возможно, вместо того, чтобы пытаться подключиться к домену turboencabulator.com, я пытаюсь подключиться к домену turboencabulator.net:

enter image description here

Обратите внимание, что в этом примере я добавил доменное имя к своему имени пользователя, а не добавлял его.

Возможно, вместо того, чтобы пытаться подключиться к домену turboencabulator.net, я пытаюсь проверить пользователя как локальную (машинную) учетную запись, префикс моего имени пользователя .\ как:

enter image description here

Как Windows проверяет имя пользователя и пароль на базе локальной учетной записи? Использует ли он SSPI с пакетом Negotiate? Если да, то какое значение оно передается как pszTargetName?

Люди говорят о веб-серверах, http, сервере создания команды. я действительно не знаю, откуда они это взяли. Или они говорят об изменении пользователя в активном каталоге, чтобы убедиться, что что-то присутствует - я не понимаю, почему мне нужно что-либо редактировать: Windows ничего не редактирует.

Что TargetName использовать при вызове InitializeSecurityContext для проверки набора учетных данных?

Бонус-чат

В этой главе из документации Application Verifier о том, почему у них есть тест, если кто-то ошибочно использует NTLM:

Для чего нужен подключаемый модуль NTLM

NTLM - это устаревший протокол аутентификации с изъянами, которые потенциально могут поставить под угрозу безопасность приложений и система. Самым важным недостатком является отсутствие сервера аутентификация, которая может позволить злоумышленнику обмануть пользователей в подключение к поддельному серверу. В качестве следствия недостающего сервера аутентификации, приложения, использующие NTLM, также могут быть уязвимы для тип атаки, называемый атакой "отражения". Последнее позволяет атакующему, чтобы захватить сеанс аутентификации пользователей законного сервера и использовать его для аутентификации злоумышленника компьютер пользователей. Уязвимости NTLM и способы их использования являются целью увеличения исследовательской деятельности в сфере безопасности сообщества.

Хотя Kerberos уже много лет доступен для многих приложений все еще написаны для использования только NTLM. Это неизбежно уменьшает безопасность приложений. Однако Kerberos не может заменить NTLM во всех сценарии - в основном те, в которых клиент должен аутентифицироваться системы, которые не объединены с доменом (домашняя сеть, возможно, являющаяся наиболее распространенные из них). Пакет безопасности Negotiate позволяет обратный совместимый компромисс, который использует Kerberos по возможности и только возвращается в NTLM, когда нет другого варианта. Код переключения для использования Negotiate вместо NTLM значительно увеличит безопасность для наших клиентов при введении небольшого количества заявок или их отсутствие Совместимость. Переговоры сами по себе не являются серебряной пулей - там являются случаями, когда злоумышленник может принудительно понизить ставку до NTLM, но это значительно труднее эксплуатировать. Однако, сразу улучшение заключается в том, что приложения, написанные для правильного ведения переговоров автоматически невосприимчивы к атакам отражения NTLM.

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

Как работает подключаемый модуль

Проигрыватель Verifier обнаруживает следующие ошибки:

  • Пакет NTLM напрямую указан в вызове AcquireCredentialsHandle (или API-интерфейсе более высокого уровня).

  • Имя цели в вызове InitializeSecurityContext равно NULL.

  • Имя цели в вызове InitializeSecurityContext не является правильно сформированным доменным именем типа SPN, UPN или NetBIOS.

Последние два случая заставят Negotiate вернуться в NTLM либо напрямую (первый случай), либо косвенно (контроллер домена вернет ошибку "главный не найден" во втором случае, заставив Negotiate отступить).

Плагин также регистрирует предупреждения, когда обнаруживает понижение до NTLM; например, когда SPN не найден контроллером домена. Они регистрируются только как предупреждения, поскольку они часто являются законными случаями - например, при аутентификации в систему, не присоединенную к домену.

Остатки NTLM

5000 - приложение имеет явно выбранный пакет NTLM

Тяжесть - ошибка

Приложение или подсистема явно выбирает NTLM вместо Negotiate в вызове AcquireCredentialsHandle. Несмотря на то, что клиент и сервер могут аутентифицироваться с использованием Kerberos, это предотвращается явным выбором NTLM.

Как исправить эту ошибку

Исправление этой ошибки состоит в том, чтобы выбрать пакет Negotiate вместо NTLM. Это будет зависеть от конкретной подсистемы сети, используемой клиентом или сервером. Ниже приведены некоторые примеры. Вы должны проконсультироваться с документацией по конкретной библиотеке или набору API, которые вы используете.

APIs(parameter) Used by Application    Incorrect Value  Correct Value  
=====================================  ===============  ========================
AcquireCredentialsHandle (pszPackage)  "NTLM"           NEGOSSP_NAME "Negotiate"

См. также

4b9b3361

Ответ 1

Короткий ответ

TargetName - это имя пользователя, под которым будет запущен код "сервера".

Фон

Пакет аутентификации Negotiate попытается использовать Kerberos. Если он не может, он попытается вернуться к NTLM.

  • Вы хотите использовать Kerberos.
  • Вы не хотите использовать NTLM; он старый, устаревший, слабый, сломанный и не должен использоваться.
  • Чтобы использовать Kerberos, вы должны предоставить TargetName
  • .Без TargetNameKerberos в принципе не может выполнить функцию

Возникает вопрос, учитывая, что все стороны, участвующие во мне (Ian), аутентифицируются с помощью Стива, что TargetName мне указать?

enter image description here

Здесь важно знать, что TargetName означает для Kerberos:

  • я хочу доказать свою личность [email protected]
  • контроллер домена передает мне зашифрованный блоб, подтверждающий мою личность
  • BLOB-объект зашифрован, поэтому [email protected] - единственный, кто может его расшифровать.
  • контроллер домена знал, что нужно шифровать его для [email protected], потому что я указал [email protected] в TargetName
  • Стив является целью

То, как Стив узнает, что BLOB-объект действителен, он был зашифрован, поэтому только он может его расшифровать.

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

Таким образом, в приведенном выше списке возможных имен работают три значения:

enter image description here

InitializeSecurityContext(credHandle, context, "[email protected]", ...);    
InitializeSecurityContext(credHandle, context, "stackoverflow.local\steve", ...);    
InitializeSecurityContext(credHandle, context, "steve", ...); //if we're in the same forest

Дополнительная путаница из-за гибкости (добро пожаловать в SPN)

SPNs Короткая версия

  • при использовании Kerberos вы должны указать имя пользователя в качестве своего TargetName
  • имя участника-службы является псевдонимом для имени пользователя
  • поэтому вы можете указать имя участника-службы как TargetName

SPNs длинная версия

В приведенном выше случае я должен был знать, что код "сервера" будет работать как [email protected].

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

  • я должен выяснить, что IIS работает как [email protected]?
  • я должен выяснить, что SQL Server работает как [email protected]?
  • и что, если служба работает в локальной службе; что не доменный пользователь вообще

К счастью (?), Kerberos создал псевдонимы (называемые именами служебных принципов - или SPN):

  • если мне нужно пройти аутентификацию на веб-сервере http://bugtracker.stackoverflow.local
  • и служба IIS работает под учетной записью домена [email protected]
  • вместо того, чтобы указывать имя цели [email protected]
  • я могу указать HTTP/bugtracker.stackoverflow.local
  • потому что IIS зарегистрировал псевдоним на контроллере домена
  • HTTP/bugtracker.stackoverflow.local[email protected]

Все это требует, чтобы вы знали имя участника-службы, если хотите использовать его в качестве TargetName. Различные стандартные продукты Microsoft регистрируют имена участников-служб при установке:

  • IIS: HTTP/[servername]
  • SQL Server: MSSQLSvc/[servername]:1433
  • SMTP: SMTPSVC/[servername]
  • Обмен файлами: HOST/[servername]

Все они недокументированы и превращают вашу жизнь в ад, если кто-то не настроен правильно.

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

Это примерно эквивалентно попытке указать "stackoverflow.com" вместо простого использования "35.186.238.101".

Как работает SSPI

SSPI был разработан как универсальная оболочка для различных алгоритмов безопасности. Способ использования API довольно прост:

  • Клиент: звонит InitializeSecurityContext и получает блоб
  • клиент отправляет этот BLOB-объект на сервер
  • Сервер: вызывает AcceptSecurityContext(blob) и получает большой назад
  • сервер отправляет этот блоб обратно клиенту
  • Клиент: звонит InitializeSecurityContext(blob) и получает обратно блоб
  • клиент отправляет этот блоб обратно на сервер
  • Сервер: вызывает AcceptSecurityContext(blob) и получает большой ответ
  • ... продолжайте повторять, пока не скажете остановиться...

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

enter image description here

И поэтому с помощью SSPI вы выполняете это пинг-понг взад и вперед, пока вам не скажут остановиться. Таким образом, они смогли подключить каждую схему аутентификации к высокому уровню абстракции пинг-понг, пока не будет сказано, чтобы остановить.

Как передать капли?

Вы передаете BLOB-объекты по любому каналу связи, который используете.

Если вы разговариваете с удаленным сервером по TCP/IP, то, вероятно, вы используете это:

// Open connection to server
sockConnect(162.210.196.166, 1433);

blob = null;

Boolean bContinue = InitializeSecurityContext(ref blob);

while (bContinue)
{
   sockWrite(blob); //send the blob to the server

   blob = sockRead(); //wait for the server to return a blob 

   bContinue = InitializeSecurityContext(ref blob);
}

Если вы делаете это через http:

blob = null;
Boolean bContinue = InitializeSecurityContext(ref blob);

while (bContinue)
{
    http = new HttpRequest("http://4chan.org/default.aspx");
    http.AddHeader("X-SSPI-Blob", blob.ToBase64());
    http.Send();

    blob = http.ReasponseHeader["X-SSPI-Blob"];
    if (blob.IsEmpty())
       break;

    bContinue = InitializeSecurityContext(ref blob);
}

Ответ 2

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

SSPI обычно используется для аутентификации пользователя по сети. Клиент вызывает AcquireCredentialsHandle, чтобы получить дескриптор учетных данных, а затем создать контекст безопасности, вызвав InitializeSecurityContext. Передайте буфер безопасности на сервер. Обратите внимание, что SSPI не определяет, как вы передаете буфер безопасности. Вы можете использовать http, tcp, named pipe, что угодно. Как только сервер получит буфер безопасности. Точно так же он сначала вызывает AcquireCredentialsHandle. Затем он передает полученный буфер безопасности в AcceptSecurityContext и генерирует новый буфер безопасности. В некоторых случаях вновь созданный буфер безопасности должен отправить обратно клиенту, а клиент передает его в InitializeSecurityContext и снова создает другой новый контекст безопасности. Этот процесс связывания SSPI продолжается до тех пор, пока InitializeSecurityContext и AcceptSecurityContext не вернут SEC_E_OK

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

Чтобы понять, почему targetName требуется в Kerberos, но не в NTLM, вам нужно понять еще одну базовую реализацию.

Существует два разных способа получения дескриптора учетных данных. Обычно люди указывают на использование текущего контекста безопасности. (т.е. учетной записи, которую вы использовали для входа на ваш компьютер). Вы также можете указать другой набор имени пользователя/пароля. Различные пакеты безопасности имеют разные значения для термина credentials. NTLM означает, что он сохранит хэш вашего пароля. Kerberos означает, что он собирается сохранить билет на выдачу билетов (TGT). Для программиста SSPI вам не нужно беспокоиться об этом.

Теперь, когда клиент переходит в обработчик приобретенных учетных данных в InitializeSecurityContext, аналогичным образом, другой пакет безопасности будет делать разные вещи. NTLM собирается создать пакет NEGOTIATE при первом вызове InitializeSecurityContext. Никакие другие машины не участвуют в процессе создания пакета NEGOTITATE. Пакет Kerberos очень отличается. Он собирается поговорить с KDC, чтобы запросить билет на услугу для запрашиваемой услуги. Служба идентифицируется именем участника-службы (SPN) в Kerberos. Здесь я не могу описать все подробности. Чистая сеть заключается в том, что запрос на обслуживание для NTLM нецелесообразен, в то время как запрос на обслуживание для Kerberos нацелен. Вы можете использовать один и тот же пакет NTLM NEGOTIATE для разных служб, используя метод проверки подлинности NTLM. Тем не менее, вам необходимо использовать разные билеты службы Kerberos для разных служб с использованием метода проверки подлинности Kerberos. Поэтому при вызове InitializeSecurityContext для Kerberos/Negotiate вам необходимо предоставить targetName.

Когда KDC получает запрос на билет обслуживания, он выполняет поиск в своей базе данных LDAP и выясняет, какая учетная запись связана с указанным servicePrincipalName. Учетная запись может быть учетной записью пользователя AD или учетной записью компьютера AD. KDC будет использовать главный ключ учетной записи целевой службы (сгенерированный паролем учетной записи) для шифрования ключа сеанса. Этот зашифрованный ключ сеанса будет передан от клиента к серверу позже.

Теперь, помните, я сказал, что сервер также должен делать AcquireCredentialsHandle, и я сказал, что есть два основных подхода, чтобы получить учетные данные. Я предполагаю, что вы используете первый подход для получения учетных данных. Это означает, что он будет использовать текущий контекст безопасности. В случае обычной сетевой проверки подлинности это можно проиллюстрировать в следующем примере. Если ваш сервер является HTTP-сервером, он будет учетной записью службы вашего сервера IIS. Сервер IIS будет использовать свой главный ключ учетной записи службы для дешифрования зашифрованного ключа сеанса. После получения ключа сеанса клиент и сервер продолжают связь с использованием ключа сеанса для шифрования и дешифрования.

Если это сценарий SSPI с обратной петлей, это сложнее. Если вы используете domain\jane и выполняете цикл на себя. Вам нужно указать SPN для домена \jane. Что такое SPN для домена \jane. Если вы проверяете объект пользователя AD, по умолчанию его нет. Вам нужно вручную его исправить.

Есть одна вещь, которая использовалась для меня, но она не документирована. Вы можете указать пользователя UPN (то есть [email protected]) как SPN. Это работает для меня. Вы можете попробовать.

Если это не сработает, другой способ исправить это - использовать второй подход для части сервера AcquireCredentialsHandle. Вместо использования дескриптора учетных данных domain\jane вы указываете другие учетные данные учетной записи службы. Вы можете убедиться, что учетная запись службы имеет правильный набор SPN. Затем вы можете использовать эту учетную запись SPN службы в своем InitializeSecurityContext. Конечно, это также означает, что вам нужно жестко закодировать свой пароль учетной записи службы в коде. Вам нужно быть осторожным и убедиться, что вы полностью заблокировали эту учетную запись службы, чтобы, несмотря на то, что пароль был украден, ваша среда AD не подвержена большому риску.

Ответ 3

Я пару лет опаздываю на эту вечеринку... Вчера я столкнулся с вашим вопросом, исследуя мою собственную проблему SSPI. Сегодня утром, когда я продолжил свое исследование, я наткнулся на статью, которая, кажется, предлагает решение вашего вопроса:

Keith Brown Апрель 2001 г. Статья в MSDN Magazine, озаглавленная "Краткие сведения о безопасности: интерфейс поставщика поддержки безопасности", содержит пример кода, который показывает имя targetName (для проверки пароля), должен быть строкой в ​​форме "Machine\User" или "Домен\Пользователь".

Статья находится здесь: http://msdn.microsoft.com/en-us/magazine/cc301890.aspx

"Цифры", указанные в статье (включая код примера), находятся здесь: http://msdn.microsoft.com/en-us/magazine/bb985825.aspx

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

Ответ 4

Это зависит от того, на какой SPN вы пытаетесь пройти аутентификацию. Мы выполняем аутентификацию NTLM/SPNEGO на HTTP-серверах (только) и руководство предлагает, что сервер HTTP/HTTPS должен зарегистрировать SPN как http/HOSTNAME. Поэтому, когда мы выполняем аутентификацию, мы просто добавляем http/ в верхнее имя узла. Например, мы передаем:

http/TFS.DOMAIN.COM

как цель для InitializeSecurityContext, где TFS.DOMAIN.COM - имя хоста с верхним расположением, которое пользователь набрал для доступа к своему серверу TFS.

Мы не пытаемся выполнять DNS-поиск или сопоставление FQDN. Если пользователь просто набирает http://foo/, тогда наш SPN http/FOO. Это означает, что администратор сервера должен настроить http/FOO как SPN.

Неверно, что администратор сервера настраивает машину, называет ее FOO и устанавливает SPN http/FOO, а затем предоставляет этот компьютер в Интернете как extranet.domain.com. В этом случае они также должны настроить http/EXTRANET.DOMAIN.COM как SPN. Это может стать сложным с балансировщиками нагрузки и т.д., Но это должно быть ответственностью администратора сервера.