Control de la autenticación

Algunos servidores proxy y servidores requieren autenticación antes de conceder acceso a los recursos en Internet. Las funciones winINet admiten la autenticación de servidor y proxy para sesiones http. La función InternetConnect debe controlar la autenticación de servidores ftp. Actualmente, no se admite la autenticación de puerta de enlace ftp.

Acerca de la autenticación HTTP

Si se requiere autenticación, la aplicación cliente recibe un código de estado 401, si el servidor requiere autenticación o 407, si el proxy requiere autenticación. Con el código de estado, el proxy o el servidor envía uno o varios encabezados de respuesta de autenticación: Proxy-Authenticate (para la autenticación de proxy) o WWW-Authenticate (para la autenticación del servidor).

Cada encabezado de respuesta de autenticación contiene un esquema de autenticación disponible y un dominio kerberos. Si se admiten varios esquemas de autenticación, el servidor devuelve varios encabezados de respuesta de autenticación. El valor del dominio kerberos distingue mayúsculas de minúsculas y define un espacio de protección en el proxy o el servidor. Por ejemplo, el encabezado "WWW-Authenticate: Basic Realm="example"" sería un ejemplo de un encabezado devuelto cuando se requiere la autenticación del servidor.

La aplicación cliente que envió la solicitud se puede autenticar por sí misma mediante la inclusión de un campo de encabezado de autorización con la solicitud. El encabezado Authorization contendrá el esquema de autenticación y la respuesta adecuada requerida por ese esquema. Por ejemplo, el encabezado "Authorization: Basic <username:password>" se agregaría a la solicitud y se volvería a enviar al servidor si el cliente recibió el encabezado de respuesta de autenticación "WWW-Authenticate: Basic Realm="example"".

Hay dos tipos generales de esquemas de autenticación:

  • Esquema de autenticación básico, donde el nombre de usuario y la contraseña se envían en texto no cifrado al servidor.
  • Esquemas de respuesta a desafíos, que permiten un formato de respuesta a desafíos.

El esquema de autenticación básico se basa en el modelo que un cliente debe autenticarse con un nombre de usuario y una contraseña para cada dominio kerberos. El servidor atiende la solicitud si se resentrada con un encabezado authorization que incluye un nombre de usuario y una contraseña válidos.

Los esquemas de desafío y respuesta permiten una autenticación más segura. Si una solicitud requiere autenticación mediante un esquema challenge-response, el código de estado adecuado y los encabezados Authenticate se devuelven al cliente. Después, el cliente debe volver a enviar la solicitud con una negociación. El servidor devolvería un código de estado adecuado con un desafío y, a continuación, el cliente necesitaría reenviar la solicitud con la respuesta adecuada para obtener el servicio solicitado.

En la tabla siguiente se enumeran los esquemas de autenticación, el tipo de autenticación, el archivo DLL que los admite y una descripción del esquema.

Scheme Tipo Archivo DLL Descripción
Básico (texto no cifrado) basic Wininet.dll Usa una cadena codificada en base64 que contiene el nombre de usuario y la contraseña.
Digest challenge-response Digest.dll Un esquema de desafío-respuesta que desafía el uso de un valor nonce (una cadena de datos especificada por el servidor). Una respuesta válida contiene una suma de comprobación del nombre de usuario, la contraseña, el valor nonce dado, el método HTTP y el identificador uniforme de recursos (URI) solicitado. La compatibilidad con la autenticación implícita se introdujo en Microsoft Internet Explorer 5.
NT LAN Manager (NTLM) challenge-response Winsspi.dll Un esquema de desafío-respuesta que basa el desafío en el nombre de usuario.
Microsoft Network (MSN) challenge-response Msnsspc.dll El esquema de autenticación de Microsoft Network.
Autenticación de contraseña distribuida (DPA) challenge-response Msapsspc.dll De forma similar a la autenticación de MSN y también la usa Microsoft Network.
Autenticación de frase de contraseña remota (RPA) Compuserve Rpawinet.dll, da.dll Esquema de autenticación de CompuServe. Para obtener más información, consulte las especificaciones del mecanismo RPA.

 

Para cualquier cosa que no sea la autenticación básica, las claves del Registro deben configurarse además de instalar el archivo DLL adecuado.

Si se requiere autenticación, se debe usar la marca INTERNET_FLAG_KEEP_CONNECTION en la llamada a HttpOpenRequest. La marca INTERNET_FLAG_KEEP_CONNECTION es necesaria para NTLM y otros tipos de autenticación con el fin de mantener la conexión mientras se completa el proceso de autenticación. Si no se mantiene la conexión, el proceso de autenticación debe reiniciarse con el proxy o el servidor.

Las funciones InternetOpenUrl y HttpSendRequest se completan correctamente incluso cuando se requiere autenticación. La diferencia es que los datos devueltos en los archivos de encabezado e InternetReadFile recibirían una página HTML que informa al usuario del código de estado.

Registro de claves de autenticación

INTERNET_OPEN_TYPE_PRECONFIG examina los valores del Registro ProxyEnable, ProxyServer y ProxyOverride. Estos valores se encuentran en HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings.

Para los esquemas de autenticación distintos de Basic, se debe agregar una clave al registro en HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security. Un valor DWORD , Flags, debe establecerse con el valor adecuado. En la lista siguiente se muestran los valores posibles para el valor Flags .

  • PLUGIN_AUTH_FLAGS_UNIQUE_CONTEXT_PER_TCPIP (value=0x01)

    Cada socket protocolo de control de transmisión/Protocolo de Internet (TCP/IP) contiene un contexto diferente. De lo contrario, se pasa un nuevo contexto para cada plantilla de dirección URL de bloque o dominio.

  • PLUGIN_AUTH_FLAGS_CAN_HANDLE_UI (value=0x02)

    Este archivo DLL puede controlar su propia entrada de usuario.

  • PLUGIN_AUTH_FLAGS_CAN_HANDLE_NO_PASSWD (value=0x04)

    Este archivo DLL puede ser capaz de realizar una autenticación sin pedir al usuario una contraseña.

  • PLUGIN_AUTH_FLAGS_NO_REALM (value=0x08)

    Este archivo DLL no usa una cadena de dominio kerberos HTTP estándar. Los datos que parecen ser un dominio kerberos son datos específicos del esquema.

  • PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED (value=0x10)

    Este archivo DLL no requiere una conexión persistente para su secuencia de desafío-respuesta.

Por ejemplo, para agregar la autenticación NTLM, se debe agregar la clave NTLM a HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security. En HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security\NTLM, se debe agregar el valor de cadena, DLLFile y un valor DWORD , Flags. DLLFile debe establecerse en Winsspi.dll y las marcas deben establecerse en 0x08.

Autenticación de servidor

Cuando un servidor recibe una solicitud que requiere autenticación, el servidor devuelve un mensaje de código de estado 401. En ese mensaje, el servidor debe incluir uno o varios encabezados de respuesta WWW-Authenticate. Estos encabezados incluyen los métodos de autenticación que el servidor tiene disponible. WinINet elige el primer método que reconoce.

La autenticación básica proporciona una seguridad débil a menos que el canal esté primero cifrado con SSL o PCT.

La función InternetErrorDlg se puede usar para obtener los datos de nombre de usuario y contraseña del usuario, o bien se puede diseñar una interfaz de usuario personalizada para obtener los datos.

Una interfaz personalizada puede usar la función InternetSetOption para establecer los valores de INTERNET_OPTION_PASSWORD y INTERNET_OPTION_USERNAME y, a continuación, volver a enviar la solicitud al servidor.

Autenticación de proxy

Cuando un cliente intenta usar un proxy que requiere autenticación, el proxy devuelve un mensaje de código de estado 407 al cliente. En ese mensaje, el proxy debe incluir uno o varios encabezados de respuesta Proxy-Authenticate. Estos encabezados incluyen los métodos de autenticación disponibles en el proxy. WinINet elige el primer método que reconoce.

La función InternetErrorDlg se puede usar para obtener los datos de nombre de usuario y contraseña del usuario, o se puede diseñar una interfaz de usuario personalizada.

Una interfaz personalizada puede usar la función InternetSetOption para establecer los valores de INTERNET_OPTION_PROXY_PASSWORD y INTERNET_OPTION_PROXY_USERNAME y, a continuación, volver a enviar la solicitud al proxy.

Si no se establece ningún nombre de usuario proxy y contraseña, WinINet intenta usar el nombre de usuario y la contraseña del servidor. Este comportamiento permite a los clientes implementar la misma interfaz de usuario personalizada que se usa para controlar la autenticación del servidor.

Control de la autenticación HTTP

La autenticación HTTP se puede controlar con InternetErrorDlg o con una función personalizada que usa InternetSetOption o agrega sus propios encabezados de autenticación. InternetErrorDlg puede examinar los encabezados asociados a un identificador HINTERNET para buscar errores ocultos, como códigos de estado de un proxy o servidor. InternetSetOption se puede usar para establecer el nombre de usuario y la contraseña para el proxy y el servidor. Para la autenticación de MSN y DPA, Se debe usar InternetErrorDlg para establecer el nombre de usuario y la contraseña.

Para cualquier función personalizada que agregue sus propios encabezados WWW-Authenticate o Proxy-Authenticate, la marca INTERNET_FLAG_NO_AUTH debe establecerse para deshabilitar la autenticación.

En el ejemplo siguiente se muestra cómo se puede usar InternetErrorDlg para controlar la autenticación 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.

En el ejemplo, dwErrorCode se usa para almacenar los errores asociados a la llamada a HttpSendRequest. HttpSendRequest se completa correctamente, incluso si el proxy o el servidor requieren autenticación. Cuando la marca FLAGS_ERROR_UI_FILTER_FOR_ERRORS se pasa a InternetErrorDlg, la función comprueba si hay errores ocultos en los encabezados. Estos errores ocultos incluirían las solicitudes de autenticación. InternetErrorDlg muestra el cuadro de diálogo adecuado para solicitar al usuario los datos necesarios. Las marcas FLAGS_ERROR_UI_FLAGS_GENERATE_DATA y FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS también deben pasarse a InternetErrorDlg, de modo que la función construya la estructura de datos adecuada para el error y almacene los resultados del cuadro de diálogo en el identificador HINTERNET .

En el código de ejemplo siguiente se muestra cómo se puede controlar la autenticación mediante 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.

Nota

WinINet no admite implementaciones de servidor. Además, no se debe usar desde un servicio. En el caso de las implementaciones de servidor o los servicios, use Servicios HTTP de Microsoft Windows (WinHTTP).