Подтвердить что ты не робот

Аутентификация клиент-сервер - с использованием SSPI?

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

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

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

Я бы предпочел сделать это с чистой С#/. Net, но я открыт для использования небезопасных С# и pinvokes для win32 API, если это означает, что я сделаю это.

Я немного читал о SSPI в окнах, но я чувствую себя в темноте, потому что такая разработка приложений для меня нова.

Кто-нибудь знает, как это сделать? Является ли SSPI? Как использовать SSPI из С#? Есть ли собственный .Net-способ, чтобы мой код оставался переносимым?

4b9b3361

Ответ 1

Update:

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

В процессе исследования необходимых бит для решения этого вопроса я написал проект по предоставлению SSPI в .Net. Ниже я описываю основы взаимодействия с API SSPI Windows, чтобы кто-то мог реплицировать мои результаты. Если вы захотите использовать SSPI в .Net, я могу предложить вам использовать проект, который я создал для решения этой проблемы:

NSspi - Интерфейс .Net для API SSPI

SSPI предоставляет вам сырые массивы байт, содержащие токены аутентификации, которые затем вы решаете, как передавать - будь то через сокет с сообщениями в двоичном формате, пользовательский канал XML,.Net Remoting, некоторая форма WCF, черт, даже серийный порт. Вы решаете, как с ними бороться. С SSPI сервер может аутентифицировать клиентов, надежно идентифицировать клиента и даже выполнять основные процедуры обработки сообщений, такие как шифрование/подпись, используя контекст безопасности, установленный с клиентом.

API SSPI описан здесь: Обзор API SSPI

В частности, взгляните на следующие функции:

  • AcquireCredentialsHandle
    • Приобретает дескриптор некоторых форм учетных данных (например, текущий пользовательский вход в систему). Используется серверами и клиентами.
  • InitializeSecurityContext
    • Используется клиентами для создания контекста безопасности с сервером.
  • AcceptSecurityContext
    • Используется серверами для установления контекста безопасности с клиентом.

Типичным рабочим процессом является то, что каждая сторона будет инициализировать свои учетные данные с помощью AcquireCredentialsHandle. Затем цикл аутентификации начинается и прогрессирует следующим образом:

  • Клиент вызывает InitializeSecurityContext, не предоставляя токенов ввода, которые возвращают маркеры вывода в виде массива байтов. ISC возвращает "ContinueNeeded", чтобы указать, что цикл проверки подлинности не завершен.
  • Клиент отправляет маркеры на сервер тем, что ему нужно.
  • Сервер передает принятые токены в качестве входных данных в AcceptSecurityContext и создает свои собственные токены вывода. ASC также возвращает "ContinueNeeded", чтобы указать, что аутентификация цикл не завершен.
  • Затем сервер отправляет свои выходные токены клиенту.
  • Клиент предоставляет маркеры серверов в качестве входа в InitializeSecurityContext, который возвращает новые токены вывода.
  • Клиент отправляет свои новые маркеры вывода на сервер.
  • ...

Этот цикл продолжается до тех пор, пока клиент не увидит, что InitializeSecurityContext возвращает "ОК" , и сервер видит, что AcceptSecurityContext возвращает "OK". Каждая функция может возвращать "ОК" и по-прежнему предоставлять выходной токен (как указано ненулевым возвратом), чтобы указать, что он все равно должен отправлять данные на другую сторону. Так клиент знает, что его половина выполнена, но сервер все еще не завершен; и наоборот, если сервер завершает работу перед клиентом. Какая сторона завершается первой (возвращает "ОК" ) зависит от конкретного пакета безопасности, который используется под капотом SSPI, и любой пользователь SSPI должен знать об этом.

Информация выше должна быть достаточной для того, чтобы кто-либо мог взаимодействовать с системой SSPI, чтобы обеспечить "Интегрированную проверку подлинности Windows" в своем приложении и реплицировать мои результаты.

Ниже мой более ранний ответ, когда я узнал, как вызывать API SSPI.


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

Это возможно в .Net, и я в настоящее время разрабатываю оболочку .Net SSPI, которую я намереваюсь опубликовать.

Я основываю свою работу на некоторых образцах SSPI от Microsoft, которую я нашел.

В примере содержится сборка, управляемая С++/CLI, которая реализует необходимые части API SSPI (в папке Microsoft\Samples\Security\SSPI\SSPI, извлеченной из файла REMSSPI.exe). Затем у них есть два пользовательских интерфейса, клиентское приложение и серверное приложение, написанные на С#, которые используют этот API для выполнения аутентификации SSPI.

Пользовательские интерфейсы используют средство удаленного доступа .Net, чтобы связать все это вместе, но если я правильно понимаю API SSPI, единственная информация, которую клиент и сервер должна обменивать, состоит из байта [] s, содержащего данные токена контекста безопасности, которые могут быть легко интегрированы в любую коммуникационную инфраструктуру, которую вы хотите; в моем случае, двоичный протокол моего собственного дизайна.

Некоторые заметки о том, как заставить образец работать - у них есть источник библиотеки "SSPI", который лучше всего компилируется под VS 2005, хотя я получил его для работы в 2008 году; 2010 или выше потребует некоторой переделки, поскольку они используют языковые конструкции, которые были устаревшими. Вам также может потребоваться изменить заголовочные файлы, которые являются частью SDK вашей платформы, потому что они используют назначения указателей const для переменных unconst, и я не знаю, как лучше сделать компилятор счастливым (я никогда не использовал С++/CLI раньше).

Они включают скомпилированную dll sSPI в папку Microsoft\Samples\Security\SSPI\bin. Чтобы заставить исполняемые файлы клиента/сервера работать, вы должны скопировать эту DLL в свой каталог bin, иначе разрешение сбоя сбоя.

Итак, суммируем:

  • Go здесь, чтобы загрузить образец самораспаковывающегося образца REMSSPI.exe.
  • Извлеките файл REMSSPI.exe(дважды..)
  • Microsoft\Samples\Security\ССПИ \
    • bin\ - содержит скомпилированную dll Microsoft.Samples.Security.SSPI.dll
    • SSPI\ - содержит источник для dll
    • Sample\ - содержит исходный код пользовательского интерфейса
      • bin\ - Содержит образцы пользовательского интерфейса сборки. Скопируйте файл SSPI.dll и запустите ControlPanel.Client.exe и ControlPanel.Server.exe

Ответ 2

Никола правильна; не существует .NET-родного способа выполнить то, что вы делаете (по крайней мере, не используя поддержку низкоуровневых .NET-сокетов). Вы можете, конечно, погрузиться под обложки, чтобы сделать какую-то черную магию взаимодействия, но если и клиент, и сервер находятся под вашим контролем, вам может потребоваться немного поднять стек и использовать API более высокого уровня, такой как WCF, который есть имеют встроенную поддержку .NET для проверки подлинности Windows.

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

Ответ 3

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

Вы пробовали с NegotiateStream? Данный пример лучше подходит вашим потребностям: он использует Kerberos для аутентификации, прежде чем разрешить чтение/запись. Использование CredentialCache.DefaultNetworkCredentials должно избегать запроса пароля.

Ответ 4

Когда-либо пытались работать с WindowsIdentity?
Pure С#/. Net, serializable и GetCurrent() возвращает исполняемую учетную запись.


Значок безопасности
Пользователь предоставляет набор претензий к вашему приложению вместе с ее просьбой. В веб-службе эти претензии переносится в заголовок безопасности конверта SOAP. В браузерное веб-приложение, заявки поступают через HTTP POST из браузера пользователей, а позже может быть кэширован в cookie, если сеанс желательно. Независимо от того, как они поступают, они должны быть сериализованы так или иначе, и здесь появляются токены безопасности. представляет собой сериализованный набор формул, которые цифровой подписью выдают власть. Подпись важна - она ​​дает вам уверенность в том, что пользователь не просто составил кучу претензий и отправил их вам. В ситуациях с низкой степенью безопасности, когда криптография не нужна или желательно, вы можете использовать токены без знака, но это не сценарий Im основное внимание будет уделено в этой статье. Одной из основных особенностей WIF является возможность создавать и читать маркеры безопасности. WIF и основные сантехника в .NET Framework обрабатывает все криптографические тяжелые поднимая и представляя ваше приложение с набором требований, которые вы может читать.

цитируется Windows Identity Foudation WhitePaper

Ваш основной вопрос:

"Существует ли чистый С#/.NET способ аутентификации пользователей с использованием их учетных данных?"

WindowsIdentity - это токен аутентификации, выданный вашим контроллером домена, и мне кажется, что это лучший подход в настоящее время.


Я знал очень немного о WindowsIdentity, когда я впервые опубликовал, но я также чувствовал, что это поможет с вашей проблемой и ограничениями. Я много читал и, наконец, пришел к этой странице .
Внедрение WIF вполне объяснимо, WindowsIdentity - это новый набор платформы .NET, предназначенный для проблем безопасности на основе Windows/Роли.
SSPI, Kerberos являются частью всего процесса проверки подлинности Windows, токен входа в систему, полученный пользователем/машиной/процессом, предоставляется контроллером домена и не может быть получен "просто", инициирующим новый объект WindowsIdentity. Если бы существовал такой незаконный механизм, вся модель безопасности Windows (домены, UAC и т.д.) Была бы мертвой.

Вот небольшая консольная программа (очень!), которая генерирует исключение, если вы не являетесь частью "BUILTIN\Administrateurs" (измените название группы в соответствии с вашими собственными потребностями). Всякий раз, когда "Запуск от имени администратора", программа заканчивается без ошибок.
Существует очень большой набор разрешений, и каждое требование основано на требованиях (это идентификатор пользователя xxx?)

using System;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;

namespace WindowsIdentityTest
{
    class Program
    {
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        static string SomeServerAction()
        { return "Authenticated users can access"; }

        [PrincipalPermission(SecurityAction.Demand, Role = "BUILTIN\\Administrateurs")]
        static string SomeCriticalServerAction()
        { return "Only Admins can access"; }

        static void Main(string[] args)
        {
            //This allows to perform security checks against the current Identity.   
            AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

            try
            {
                Console.WriteLine(SomeServerAction());
                Console.WriteLine(SomeCriticalServerAction());

            }
            catch (SecurityException sec)
            {
                Console.WriteLine(string.Format("{0} : {1}\n------------\n{2}"
                    , sec.GetType()
                    , sec.Message
                    , sec.StackTrace));
            }
            catch (Exception ex)
            {
                Console.WriteLine("This shall not appen.");
            }
            Console.WriteLine("Press enter to quit.");
            Console.ReadLine();
        }
    }
}

Надеюсь, это поможет.