Partilhar via


Manipulando a autenticação

Alguns proxies e servidores exigem autenticação antes de conceder acesso a recursos na Internet. As funções WinINet suportam autenticação de servidor e proxy para sessões http. A autenticação de servidores ftp deve ser gerida pela função InternetConnect. Atualmente, a autenticação de gateway FTP não é suportada.

Sobre a autenticação HTTP

Se a autenticação for necessária, o aplicativo cliente receberá um código de status 401, se o servidor exigir autenticação, ou 407, se o proxy exigir autenticação. Com o código de status, o proxy ou servidor envia um, ou mais, cabeçalhos de resposta autenticados —Proxy-Authenticate (para autenticação de proxy) ou WWW-Authenticate (para autenticação de servidor).

Cada cabeçalho de resposta autenticado contém um esquema de autenticação disponível e um domínio. Se houver suporte para vários esquemas de autenticação, o servidor retornará vários cabeçalhos de resposta de autenticação. O valor de realm é sensível a maiúsculas e minúsculas e define um espaço de proteção no proxy ou servidor. Por exemplo, o cabeçalho "WWW-Authenticate: Basic Realm="example"" seria um exemplo de um cabeçalho retornado quando a autenticação do servidor é necessária.

O aplicativo cliente que enviou a solicitação pode autenticar-se incluindo um campo de cabeçalho Autorização com a solicitação. O cabeçalho Autorização conteria o esquema de autenticação e a resposta apropriada exigida por esse esquema. Por exemplo, o cabeçalho "Authorization: Basic <username:password>" seria adicionado à solicitação e reenviado ao servidor se o cliente recebesse o cabeçalho de resposta autenticado "WWW-Authenticate: Basic Realm="example"".

Existem dois tipos gerais de esquemas de autenticação:

  • Esquema de autenticação básica, onde o nome de usuário e a senha são enviados em texto não criptografado para o servidor.
  • Esquemas de desafio-resposta, que possibilitam esse formato.

O esquema de autenticação Básica é baseado no modelo de que um cliente deve autenticar-se com um nome de usuário e senha para cada realm. O servidor atende a solicitação se ela for reenviada com um cabeçalho de Autorização que inclua um nome de usuário e senha válidos.

Os esquemas de desafio-resposta permitem uma autenticação mais segura. Se uma solicitação exigir autenticação usando um esquema de desafio-resposta, o código de status apropriado e os cabeçalhos de autenticação serão retornados ao cliente. O cliente deve, então, reenviar o pedido para negociar. O servidor retornaria um código de status apropriado com um desafio, e o cliente precisaria reenviar a solicitação com a resposta adequada para obter o serviço solicitado.

A tabela a seguir lista os esquemas de autenticação, o tipo de autenticação, a DLL que os suporta e uma descrição do esquema.

Esquema Tipo DLL Descrição
Básico (texto não criptografado) básico Wininet.dll Usa uma cadeia de caracteres codificada em base64 que contém o nome de usuário e a senha.
Resumo desafio-resposta Digest.dll Um esquema de desafio-resposta que desafia o uso de um valor nonce (uma cadeia de dados especificada pelo servidor). Uma resposta válida contém uma soma de verificação do nome de usuário, da senha, do valor nonce fornecido, do método HTTP e do URI (Uniform Resource Identifier) solicitado. O suporte à autenticação Digest foi introduzido no Microsoft Internet Explorer 5.
Gerenciador de LAN NT (NTLM) desafio-resposta Winsspi.dll Um esquema de desafio-resposta que baseia o desafio no nome de usuário.
Rede Microsoft (MSN) desafio-resposta Msnsspc.dll O esquema de autenticação da Microsoft Network.
Autenticação de senha distribuída (DPA) desafio-resposta Msapsspc.dll Semelhante à autenticação MSN e também é usado pela Microsoft Network.
Autenticação remota por senha (RPA) CompuServe Rpawinet.dll, da.dll Esquema de autenticação CompuServe. Para obter mais informações, consulte as Especificações do Mecanismo RPA .

 

Para qualquer coisa diferente da autenticação básica, as chaves do Registro devem ser configuradas, além de instalar a DLL apropriada.

Se for necessária autenticação, deve ser usado o sinalizador INTERNET_FLAG_KEEP_CONNECTION na chamada a HttpOpenRequest. O sinalizador INTERNET_FLAG_KEEP_CONNECTION é necessário para NTLM e outros tipos de autenticação para manter a conexão durante a conclusão do processo de autenticação. Se a conexão não for mantida, o processo de autenticação deverá ser reiniciado com o proxy ou servidor.

As funções InternetOpenUrl e HttpSendRequest são concluídas com êxito, mesmo quando a autenticação é necessária. A diferença é que os dados retornados nos arquivos de cabeçalho e InternetReadFile receberiam uma página HTML informando o usuário sobre o código de status.

Registrando chaves de autenticação

INTERNET_OPEN_TYPE_PRECONFIG examina os valores do Registro ProxyEnable, ProxyServere ProxyOverride. Esses valores estão localizados em Software HKEY_CURRENT_USER\\Microsoft\Windows\CurrentVersion\Configurações da Internet.

Para esquemas de autenticação diferentes de Basic, uma chave deve ser adicionada ao registro em HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security. Um valor DWORD, Flags, deve ser definido com o valor apropriado. A lista seguinte mostra os valores possíveis para o valor Flags.

  • PLUGIN_AUTH_FLAGS_UNIQUE_CONTEXT_PER_TCPIP (valor=0x01)

    Cada soquete TCP/IP (Transmission Control Protocol/Internet Protocol) contém um contexto diferente. Caso contrário, um novo contexto será passado para cada modelo de URL de domínio ou bloco.

  • PLUGIN_AUTH_FLAGS_CAN_HANDLE_UI (valor=0x02)

    Esta DLL pode lidar com a sua própria entrada de utilizador.

  • PLUGIN_AUTH_FLAGS_CAN_HANDLE_NO_PASSWD (valor=0x04)

    Essa DLL pode ser capaz de fazer uma autenticação sem solicitar uma senha ao usuário.

  • PLUGIN_AUTH_FLAGS_NO_REALM (valor=0x08)

    Esta DLL não usa uma cadeia de caracteres de realm http padrão. Quaisquer dados que parecem ser um domínio são dados específicos do esquema.

  • PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED (valor=0x10)

    Esta DLL não requer uma conexão persistente para sua sequência de desafio-resposta.

Por exemplo, para adicionar autenticação NTLM, a chave NTLM deve ser adicionada ao HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security. Em HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security\NTLM, devem ser adicionados o valor string DLLFilee um valor DWORD , Flags. DLLFile deve ser definido como Winsspi.dlle Flags devem ser definidos como 0x08.

Autenticação do servidor

Quando um servidor recebe uma solicitação que requer autenticação, o servidor retorna uma mensagem de código de status 401. Nessa mensagem, o servidor deve incluir um ou mais cabeçalhos de resposta WWW-Authenticate. Esses cabeçalhos incluem os métodos de autenticação que o servidor tem disponíveis. WinINet escolhe o primeiro método que reconhece.

A autenticação básica fornece segurança fraca, a menos que o canal seja primeiro criptografado por link com SSL ou PCT.

A funçãoInternetErrorDlg pode ser usada para obter os dados de nome de usuário e senha do usuário, ou uma interface de usuário personalizada pode ser projetada para obter os dados.

Uma interface personalizada pode usar a função InternetSetOption para definir os valores INTERNET_OPTION_PASSWORD e INTERNET_OPTION_USERNAME e, em seguida, reenviar a solicitação para o servidor.

Autenticação de proxy

Quando um cliente tenta usar um proxy que requer autenticação, o proxy retorna uma mensagem de código de status 407 para o cliente. Nessa mensagem, o proxy deve incluir um ou mais cabeçalhos de resposta Proxy-Authenticate. Esses cabeçalhos incluem os métodos de autenticação disponíveis no proxy. WinINet escolhe o primeiro método que reconhece.

A função InternetErrorDlg pode ser usada para obter os dados de nome de usuário e senha do usuário, ou uma interface de usuário personalizada pode ser projetada.

Uma interface personalizada pode usar a funçãoInternetSetOption para definir os valores INTERNET_OPTION_PROXY_PASSWORD e INTERNET_OPTION_PROXY_USERNAME e, em seguida, reenviar a solicitação para o proxy.

Se nenhum nome de usuário e senha de proxy forem definidos, o WinINet tentará usar o nome de usuário e a senha para o servidor. Esse comportamento permite que os clientes implementem a mesma interface de usuário personalizada usada para manipular a autenticação do servidor.

Manipulando autenticação HTTP

A autenticação HTTP pode ser tratada com InternetErrorDlg ou uma função personalizada que utiliza InternetSetOption ou adiciona os seus próprios cabeçalhos de autenticação. InternetErrorDlg pode examinar os cabeçalhos associados a um identificador de HINTERNET para localizar erros ocultos, como códigos de status de um proxy ou servidor. InternetSetOption pode ser usado para definir o nome de usuário e senha para o proxy e servidor. Para autenticação MSN e DPA, InternetErrorDlg deve ser usado para definir o nome de usuário e a senha.

Para qualquer função personalizada que adicione seus próprios cabeçalhos WWW-Authenticate ou Proxy-Authenticate, o sinalizador INTERNET_FLAG_NO_AUTH deve ser definido para desabilitar a autenticação.

O exemplo a seguir mostra como InternetErrorDlg pode ser usado para manipular a autenticação 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.

No exemplo, dwErrorCode é usado para armazenar quaisquer erros associados à chamada para HttpSendRequest. HttpSendRequest é concluído com êxito, mesmo que o proxy ou servidor exija autenticação. Quando o sinalizador FLAGS_ERROR_UI_FILTER_FOR_ERRORS é passado para InternetErrorDlg , a função verifica os cabeçalhos em busca de erros ocultos. Esses erros ocultos incluiriam quaisquer solicitações de autenticação. InternetErrorDlg exibe a caixa de diálogo apropriada para solicitar ao usuário os dados necessários. Os sinalizadores FLAGS_ERROR_UI_FLAGS_GENERATE_DATA e FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS também devem ser passados para InternetErrorDlg, para que a função crie a estrutura de dados apropriada para o erro e armazene os resultados da caixa de diálogo no manipulador HINTERNET.

O código de exemplo a seguir mostra como a autenticação pode ser tratada usando 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.

Observação

WinINet não suporta implementações de servidor. Além disso, não deve ser usado num serviço. Para implementações ou serviços de servidor, use Microsoft Windows HTTP Services (WinHTTP).