Поделиться через


Обработка проверки подлинности

Некоторые прокси-серверы и серверы требуют проверки подлинности перед предоставлением доступа к ресурсам в Интернете. Функции WinINet поддерживают проверку подлинности сервера и прокси-сервера для сеансов HTTP. Проверка подлинности FTP-серверов должна выполняться функцией InternetConnect . В настоящее время проверка подлинности FTP-шлюза не поддерживается.

Сведения о проверке подлинности HTTP

Если требуется проверка подлинности, клиентское приложение получает код состояния 401, если сервер требует проверки подлинности, или 407, если прокси-сервер требует проверки подлинности. С помощью кода состояния прокси-сервер или сервер отправляет один или несколько заголовков ответа проверки подлинности— Proxy-Authentication (для проверки подлинности прокси-сервера) или WWW-Authenticate (для проверки подлинности сервера).

Каждый заголовок ответа проверки подлинности содержит доступную схему проверки подлинности и область. Если поддерживается несколько схем проверки подлинности, сервер возвращает несколько заголовков ответа проверки подлинности. Значение области учитывает регистр и определяет пространство защиты на прокси-сервере или сервере. Например, заголовок "WWW-Authentication: Basic Realm="example" будет примером заголовка, возвращаемого при необходимости проверки подлинности сервера.

Клиентское приложение, отправив запрос, может пройти проверку подлинности, включив в запрос поле заголовка авторизации. Заголовок Authorization будет содержать схему проверки подлинности и соответствующий ответ, необходимый для этой схемы. Например, заголовок "Authorization: Basic <username:password>" будет добавлен в запрос и повторно отправлен на сервер, если клиент получил заголовок ответа проверки подлинности "WWW-Authenticate: Basic Realm="example"".

Существует два основных типа схем проверки подлинности:

  • Базовая схема проверки подлинности, в которой имя пользователя и пароль отправляются на сервер в виде открытого текста.
  • Схемы "запрос -ответ", которые позволяют использовать формат "запрос-ответ".

Базовая схема проверки подлинности основана на модели, которую клиент должен пройти проверку подлинности с помощью имени пользователя и пароля для каждой области. Сервер обслуживает запрос, если он повторно отправляется с заголовком авторизации, который содержит допустимое имя пользователя и пароль.

Схемы ответа на запросы обеспечивают более безопасную проверку подлинности. Если запрос требует проверки подлинности с помощью схемы "запрос—ответ", соответствующий код состояния и заголовки Authentication возвращаются клиенту. Затем клиент должен повторно отправить запрос с согласованием. Сервер вернет соответствующий код состояния с запросом, а затем клиенту потребуется повторно отправить запрос с соответствующим ответом, чтобы получить запрошенную службу.

В следующей таблице перечислены схемы проверки подлинности, тип проверки подлинности, библиотека DLL, которая их поддерживает, и описание схемы.

Схема Тип DLL Описание
Базовый (cleartext) basic Wininet.dll Использует строку в кодировке Base64, содержащую имя пользователя и пароль.
Digest (дайджест) запрос-ответ Digest.dll Схема "запрос-ответ", которая вызывает запрос с использованием значения nonce (указанной сервером строки данных). Допустимый ответ содержит контрольную сумму имени пользователя, пароля, заданного значения nonce, метода HTTP и запрошенного универсального идентификатора ресурса (URI). Поддержка дайджест-проверки подлинности появилась в Microsoft Internet Обозреватель 5.
NT LAN Manager (NTLM) запрос-ответ Winsspi.dll Схема ответа на запрос, которая основывается на имени пользователя.
Microsoft Network (MSN) запрос-ответ Msnsspc.dll Схема проверки подлинности Microsoft Network.
Распределенная проверка подлинности паролем (DPA) запрос-ответ Msapsspc.dll Аналогично проверке подлинности MSN и также используется Microsoft Network.
Удаленная проверка подлинности с использованием парольной фразы (RPA) Compuserve Rpawinet.dll, da.dll Схема проверки подлинности CompuServe. Дополнительные сведения см. в разделе Спецификации механизма RPA.

 

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

Если требуется проверка подлинности, в вызове HttpOpenRequest следует использовать флаг INTERNET_FLAG_KEEP_CONNECTION. Флаг INTERNET_FLAG_KEEP_CONNECTION требуется для проверки подлинности NTLM и других типов проверки подлинности, чтобы поддерживать подключение во время завершения процесса проверки подлинности. Если подключение не поддерживается, процесс проверки подлинности необходимо перезапустить с помощью прокси-сервера или сервера.

Функции InternetOpenUrl и HttpSendRequest успешно выполняются, даже если требуется проверка подлинности. Разница заключается в том, что данные, возвращаемые в файлах заголовков, и InternetReadFile получит HTML-страницу, информирующую пользователя о коде состояния.

Регистрация ключей проверки подлинности

INTERNET_OPEN_TYPE_PRECONFIG просматривает значения реестра ProxyEnable, ProxyServer и ProxyOverride. Эти значения находятся в разделе HKEY_CURRENT_USER\Программное обеспечение\Microsoft\Windows\CurrentVersion\Internet Settings.

Для схем проверки подлинности, отличных от базовых, необходимо добавить в реестр раздел HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Обозреватель\Security. Необходимо задать значение DWORDFlags с соответствующим значением. В следующем списке показаны возможные значения для значения Flags .

  • PLUGIN_AUTH_FLAGS_UNIQUE_CONTEXT_PER_TCPIP (value=0x01)

    Каждый сокет TCP/IP содержит свой контекст. В противном случае для каждой области или шаблона URL-адреса блока передается новый контекст.

  • PLUGIN_AUTH_FLAGS_CAN_HANDLE_UI (value=0x02)

    Эта библиотека DLL может обрабатывать собственные входные данные пользователя.

  • PLUGIN_AUTH_FLAGS_CAN_HANDLE_NO_PASSWD (value=0x04)

    Эта библиотека DLL может выполнять проверку подлинности без запроса пароля у пользователя.

  • PLUGIN_AUTH_FLAGS_NO_REALM (value=0x08)

    Эта библиотека DLL не использует стандартную строку области HTTP. Любые данные, которые кажутся областью, являются данными, зависящими от схемы.

  • PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED (value=0x10)

    Для этой библиотеки DLL не требуется постоянное подключение для последовательности запроса и ответа.

Например, чтобы добавить проверку подлинности NTLM, необходимо добавить ключ NTLM в HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Обозреватель\Security. В разделе HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Обозреватель\Security\NTLM необходимо добавить строковое значение DLLFile и значение DWORDFlags. Для параметра DLLFile должно быть задано значение Winsspi.dll, а для флагов — значение 0x08.

Проверка подлинности сервера

Когда сервер получает запрос, требующий проверки подлинности, сервер возвращает сообщение с кодом состояния 401. В этом сообщении сервер должен содержать один или несколько заголовков ответа WWW-Authenticate. Эти заголовки включают методы проверки подлинности, доступные на сервере. WinINet выбирает первый распознаваемый метод.

Обычная проверка подлинности обеспечивает слабую безопасность, если канал сначала не зашифрован с помощью SSL или PCT.

Функция InternetErrorDlg может использоваться для получения данных об имени пользователя и пароле от пользователя, или для получения данных можно создать настраиваемый пользовательский интерфейс.

Пользовательский интерфейс может использовать функцию InternetSetOption для задания значений INTERNET_OPTION_PASSWORD и INTERNET_OPTION_USERNAME , а затем повторно отправить запрос на сервер.

Проверка подлинности прокси

Когда клиент пытается использовать прокси-сервер, требующий проверки подлинности, он возвращает клиенту сообщение с кодом состояния 407. В этом сообщении прокси-сервер должен содержать один или несколько заголовков ответа Proxy-Authenticate. Эти заголовки включают методы проверки подлинности, доступные с прокси-сервера. WinINet выбирает первый распознаваемый метод.

Функция InternetErrorDlg может использоваться для получения от пользователя данных об имени пользователя и пароле, или можно создать настраиваемый пользовательский интерфейс.

Пользовательский интерфейс может использовать функцию InternetSetOption для задания значений INTERNET_OPTION_PROXY_PASSWORD и INTERNET_OPTION_PROXY_USERNAME , а затем повторно отправить запрос на прокси-сервер.

Если имя пользователя и пароль прокси-сервера не заданы, WinINet пытается использовать имя пользователя и пароль для сервера. Такое поведение позволяет клиентам реализовать тот же настраиваемый пользовательский интерфейс, который используется для обработки проверки подлинности сервера.

Обработка проверки подлинности HTTP

Проверка подлинности HTTP может обрабатываться с помощью InternetErrorDlg или настраиваемой функции, которая использует InternetSetOption или добавляет собственные заголовки проверки подлинности. InternetErrorDlg может проверять заголовки, связанные с дескриптором HINTERNET , для поиска скрытых ошибок, таких как коды состояния с прокси-сервера или сервера. InternetSetOption можно использовать для задания имени пользователя и пароля для прокси-сервера и сервера. Для проверки подлинности MSN и DPA необходимо использовать InternetErrorDlg , чтобы задать имя пользователя и пароль.

Для любой настраиваемой функции, которая добавляет собственные заголовки WWW-Authenticate или Proxy-Authenticate, необходимо установить флаг INTERNET_FLAG_NO_AUTH , чтобы отключить проверку подлинности.

В следующем примере показано, как можно использовать InternetErrorDlg для обработки проверки подлинности HTTP.

HINTERNET hOpenHandle,  hConnectHandle, hResourceHandle;
DWORD dwError, dwErrorCode;
HWND hwnd = GetConsoleWindow();

hOpenHandle = InternetOpen(TEXT("Example"),
                           INTERNET_OPEN_TYPE_PRECONFIG, 
                           NULL, NULL, 0);

hConnectHandle = InternetConnect(hOpenHandle,
                                 TEXT("www.server.com"), 
                                 INTERNET_INVALID_PORT_NUMBER,
                                 NULL,
                                 NULL, 
                                 INTERNET_SERVICE_HTTP,
                                 0,0);

hResourceHandle = HttpOpenRequest(hConnectHandle, TEXT("GET"),
                                  TEXT("/premium/default.htm"),
                                  NULL, NULL, NULL, 
                                  INTERNET_FLAG_KEEP_CONNECTION, 0);

resend:

HttpSendRequest(hResourceHandle, NULL, 0, NULL, 0);

// dwErrorCode stores the error code associated with the call to
// HttpSendRequest.  

dwErrorCode = hResourceHandle ? ERROR_SUCCESS : GetLastError();

dwError = InternetErrorDlg(hwnd, hResourceHandle, dwErrorCode, 
                           FLAGS_ERROR_UI_FILTER_FOR_ERRORS | 
                           FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS |
                           FLAGS_ERROR_UI_FLAGS_GENERATE_DATA,
                           NULL);

if (dwError == ERROR_INTERNET_FORCE_RETRY)
    goto resend;

// Insert code to read the data from the hResourceHandle
// at this point.

В этом примере dwErrorCode используется для хранения ошибок, связанных с вызовом HttpSendRequest. HttpSendRequest завершается успешно, даже если прокси-сервер требует проверки подлинности. Когда флаг FLAGS_ERROR_UI_FILTER_FOR_ERRORS передается в InternetErrorDlg, функция проверяет заголовки на наличие скрытых ошибок. Эти скрытые ошибки будут включать любые запросы на проверку подлинности. InternetErrorDlg отображает соответствующее диалоговое окно с запросом у пользователя необходимых данных. Флаги FLAGS_ERROR_UI_FLAGS_GENERATE_DATA и FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS также должны передаваться в InternetErrorDlg, чтобы функция сконструирует соответствующую структуру данных для ошибки и сохранит результаты диалогового окна в дескрипторе HINTERNET .

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

HINTERNET hOpenHandle,  hResourceHandle, hConnectHandle;
DWORD dwStatus;
DWORD dwStatusSize = sizeof(dwStatus);
char strUsername[64], strPassword[64];

// Normally, hOpenHandle, hResourceHandle,
// and hConnectHandle need to be properly assigned.

hOpenHandle = InternetOpen(TEXT("Example"),
                           INTERNET_OPEN_TYPE_PRECONFIG,
                           NULL, NULL, 0);
hConnectHandle = InternetConnect(hOpenHandle,
                                 TEXT("www.server.com"),
                                 INTERNET_INVALID_PORT_NUMBER,
                                 NULL,
                                 NULL,
                                 INTERNET_SERVICE_HTTP,
                                 0,0);

hResourceHandle = HttpOpenRequest(hConnectHandle, TEXT("GET"),
                                  TEXT("/premium/default.htm"),
                                  NULL, NULL, NULL,
                                  INTERNET_FLAG_KEEP_CONNECTION,
                                  0);

resend:

HttpSendRequest(hResourceHandle, NULL, 0, NULL, 0);

HttpQueryInfo(hResourceHandle, HTTP_QUERY_FLAG_NUMBER |
              HTTP_QUERY_STATUS_CODE, &dwStatus, &dwStatusSize, NULL);

switch (dwStatus)
{
    // cchUserLength is the length of strUsername and
    // cchPasswordLength is the length of strPassword.
    DWORD cchUserLength, cchPasswordLength;

    case HTTP_STATUS_PROXY_AUTH_REQ: // Proxy Authentication Required
        // Insert code to set strUsername and strPassword.

        // Insert code to safely determine cchUserLength and
        // cchPasswordLength. Insert appropriate error handling code.
        InternetSetOption(hResourceHandle,
                          INTERNET_OPTION_PROXY_USERNAME,
                          strUsername,
                          cchUserLength+1);

        InternetSetOption(hResourceHandle,
                          INTERNET_OPTION_PROXY_PASSWORD,
                          strPassword,
                          cchPasswordLength+1);
        goto resend;
        break;

    case HTTP_STATUS_DENIED:     // Server Authentication Required.
        // Insert code to set strUsername and strPassword.

        // Insert code to safely determine cchUserLength and
        // cchPasswordLength. Insert error handling code as
        // appropriate.
        InternetSetOption(hResourceHandle, INTERNET_OPTION_USERNAME,
                          strUsername, cchUserLength+1);
        InternetSetOption(hResourceHandle, INTERNET_OPTION_PASSWORD,
                          strPassword, cchPasswordLength+1);
        goto resend;
        break;
}

// Insert code to read the data from the hResourceHandle
// at this point.

Примечание

WinINet не поддерживает реализации сервера. Кроме того, его не следует использовать из службы. Для серверных реализаций или служб используйте службы Microsoft Windows HTTP (WinHTTP).