Обработка проверки подлинности
Некоторые прокси-серверы и серверы требуют проверки подлинности перед предоставлением доступа к ресурсам в Интернете. Функции 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).