Megosztás a következőn keresztül:


Hitelesítés a WinHTTP-ban

Egyes HTTP-kiszolgálók és proxyk hitelesítést igényelnek, mielőtt engedélyezik az erőforrásokhoz való hozzáférést az interneten. A Microsoft Windows HTTP Services (WinHTTP) függvényei támogatják a HTTP-munkamenetek kiszolgáló- és proxyhitelesítését.

Tudnivalók a HTTP-hitelesítésről

Ha hitelesítésre van szükség, a HTTP-alkalmazás 401-et (a kiszolgáló hitelesítést igényel) vagy 407-et kap (a proxy hitelesítést igényel). Az állapotkóddal együtt a proxy vagy a kiszolgáló egy vagy több hitelesítési fejlécet küld: WWW-Authenticate (kiszolgálóhitelesítéshez) vagy Proxy-Authenticate (proxyhitelesítéshez).

Minden hitelesítési fejléc tartalmaz egy támogatott hitelesítési sémát, és az Alapszintű és a Kivonatoló sémák esetében egy tartományt. Ha több hitelesítési séma is támogatott, a kiszolgáló több hitelesítési fejlécet ad vissza. A tartomány értéke megkülönbözteti a kis- és nagybetűket, és olyan kiszolgálókat vagy proxykat határoz meg, amelyekhez ugyanazokat a hitelesítő adatokat fogadják el. A "WWW-Authentication: Basic Realm="example" fejléc például akkor adható vissza, ha kiszolgálóhitelesítésre van szükség. Ez a fejléc azt határozza meg, hogy a felhasználói hitelesítő adatokat meg kell adni a "példa" tartományhoz.

A HTTP-alkalmazások tartalmazhatnak engedélyezési fejlécmezőt a kiszolgálónak küldött kéréssel. Az engedélyezési fejléc tartalmazza a hitelesítési sémát és a séma által megkövetelt megfelelő választ. Az "Engedélyezés: Egyszerű <felhasználónév:jelszó>" fejléc például hozzáadódik a kéréshez, és elküldi a kiszolgálónak, ha az ügyfél megkapta a "WWW-Authentication: Basic Realm="example" válaszfejlécet.

Jegyzet

Bár itt egyszerű szövegként jelennek meg, a felhasználónév és a jelszó valójában base64 kódolású.

 

A hitelesítési sémáknak két általános típusa van:

  • Alapszintű hitelesítési séma, amelyben a felhasználónevet és a jelszót a rendszer világos szövegben küldi el a kiszolgálónak.

    Az alapszintű hitelesítési séma azon a modellen alapul, amelyet az ügyfélnek minden egyes tartományhoz meg kell adnia egy felhasználónévvel és jelszóval. A kiszolgáló csak akkor nyújtja a kérést, ha a kérést egy érvényes felhasználónevet és jelszót tartalmazó engedélyezési fejléctel küldi el.

  • A kihívásokra való reagálási sémák, például a Kerberos, amelyekben a kiszolgáló hitelesítési adatokkal. Az ügyfél átalakítja az adatokat a felhasználói hitelesítő adatokkal, és elküldi az átalakított adatokat a kiszolgálónak hitelesítés céljából.

    A kihívás-válasz sémák biztonságosabb hitelesítést tesznek lehetővé. A kihívás-válasz sémában a rendszer soha nem továbbítja a felhasználónevet és a jelszót a hálózaton keresztül. Miután az ügyfél kiválasztott egy kihívás-válasz sémát, a kiszolgáló egy megfelelő állapotkódot ad vissza egy kihívással, amely tartalmazza az adott sémahitelesítési adatokat. Az ügyfél ezután a megfelelő válaszsal újraküldi a kérést a kért szolgáltatás beszerzéséhez. A kihívásokra való reagálási sémák több cserét is végrehajthatnak.

Az alábbi táblázat a WinHTTP által támogatott hitelesítési sémákat, a hitelesítési típust és a séma leírását tartalmazza.

Cselszövés Típus Leírás
Egyszerű (egyszerű szöveg) Alapvető Egy base64 kódolású sztringet használ, amely tartalmazza a felhasználónevet és a jelszót.
Emészt Kihívás-válasz Nemce (kiszolgáló által megadott adatsztring) érték használatával kapcsolatos kihívások. Az érvényes válasz tartalmazza a felhasználónév, a jelszó, a megadott nemce érték, a HTTP-és a kért egységes erőforrás-azonosító (URI) ellenőrzőösszegét.
NTLM Kihívás-válasz Az identitás igazolásához a hitelesítési adatokat kell átalakítani a felhasználói hitelesítő adatokkal. Ahhoz, hogy az NTLM-hitelesítés megfelelően működjön, több cserének kell végbemenie ugyanazon a kapcsolaton. Ezért az NTLM-hitelesítés nem használható, ha egy beavatkozó proxy nem támogatja az életben tartási kapcsolatokat. Az NTLM-hitelesítés akkor is meghiúsul, ha WinHttpSetOption használ a WINHTTP_DISABLE_KEEP_ALIVE jelzővel, amely letiltja az életben tartás szemantikáját.
Útlevél Kihívás-válasz A Microsoft Passport 1.4 használ.
Tárgyal Kihívás-válasz Ha a kiszolgáló és az ügyfél is Windows 2000 vagy újabb verziót használ, a Rendszer Kerberos-hitelesítést használ. Ellenkező esetben A rendszer NTLM-hitelesítést használ. A Kerberos Windows 2000 és újabb operációs rendszerekben érhető el, és biztonságosabbnak tekinthető, mint az NTLM-hitelesítés. Ahhoz, hogy a hitelesítés egyeztetése megfelelően működjön, több cserének kell végbemenie ugyanazon a kapcsolaton. Ezért az egyeztetési hitelesítés nem használható, ha egy beavatkozó proxy nem támogatja az életben tartási kapcsolatokat. Az egyeztetési hitelesítés akkor is meghiúsul, ha WinHttpSetOption használ a WINHTTP_DISABLE_KEEP_ALIVE jelzővel, amely letiltja az életben tartás szemantikáját. Az egyeztetési hitelesítési sémát néha integrált Windows-hitelesítésnek is nevezik.

 

Hitelesítés WinHTTP-alkalmazásokban

A WinHTTP alkalmazásprogramozási felülete (API) két funkciót biztosít az internetes erőforrások eléréséhez olyan helyzetekben, amikor hitelesítésre van szükség: WinHttpSetCredentials és WinHttpQueryAuthSchemes.

Ha 401-es vagy 407-es állapotkóddal érkezik válasz, WinHttpQueryAuthSchemes használható a hitelesítési fejlécek elemzésére a támogatott hitelesítési sémák és a hitelesítési cél meghatározásához. A hitelesítési cél az a kiszolgáló vagy proxy, amely hitelesítést kér. WinHttpQueryAuthSchemes az elérhető sémák közül az első hitelesítési sémát is meghatározza a kiszolgáló által javasolt hitelesítési sémák alapján. A hitelesítési séma kiválasztásának módszere az RFC 2616 által javasolt viselkedés.

WinHttpSetCredentials lehetővé teszi, hogy az alkalmazás megadja a használt hitelesítési sémát, valamint egy érvényes felhasználónevet és jelszót a célkiszolgálón vagy proxyn való használatra. A hitelesítő adatok megadása és a kérés újraküldése után a rendszer automatikusan létrehozza és hozzáadja a szükséges fejléceket a kérelemhez. Mivel egyes hitelesítési sémák több tranzakciót igényelnek, WinHttpSendRequest a hibát visszaadhatja, ERROR_WINHTTP_RESEND_REQUEST. A hiba észlelésekor az alkalmazásnak mindaddig újra kell küldenie a kérést, amíg olyan válasz nem érkezik, amely nem tartalmaz 401 vagy 407 állapotkódot. A 200 állapotkód azt jelzi, hogy az erőforrás elérhető, és a kérés sikeres. További visszaadható állapotkódokért lásd HTTP-állapotkódokat.

Ha egy elfogadható hitelesítési séma és hitelesítő adatok ismertek a kérés kiszolgálóra történő elküldése előtt, az alkalmazás meghívhatja WinHttpSetCredentials, mielőtt meghívja WinHttpSendRequest. Ebben az esetben a WinHTTP megkísérli az előhitelesítést a kiszolgálóval úgy, hogy hitelesítő adatokat vagy hitelesítési adatokat a kiszolgálónak küldött kezdeti kérésben. Az előhitelesítés csökkentheti a hitelesítési folyamat csereszámát, és ezáltal javíthatja az alkalmazás teljesítményét.

Az előhitelesítés a következő hitelesítési sémákkal használható:

  • Alapszintű – mindig lehetséges.
  • Tárgyaljon a Kerberosban történő feloldásról – nagyon valószínű, hogy lehetséges; Az egyetlen kivétel az, ha az időeltérés ki van kapcsolva az ügyfél és a tartományvezérlő között.
  • (Egyeztetés az NTLM-be történő feloldásról) – soha nem lehetséges.
  • NTLM – csak Windows Server 2008 R2 rendszerben lehetséges.
  • Megemésztés - soha nem lehetséges.
  • Passport - soha nem lehetséges; a kezdeti kihívás-válasz után a WinHTTP cookie-kat használ a Passport előzetes hitelesítéséhez.

Egy tipikus WinHTTP-alkalmazás a következő lépéseket hajtja végre a hitelesítés kezeléséhez.

Az WinHttpSetCredentials által beállított hitelesítő adatokat csak egy kéréshez használja a rendszer. A WinHTTP nem gyorsítótárazza a más kérésekben használandó hitelesítő adatokat, ami azt jelenti, hogy olyan alkalmazásokat kell írni, amelyek több kérésre is válaszolhatnak. Hitelesített kapcsolat újbóli használata esetén előfordulhat, hogy más kérések nem lesznek megtámadva, de a kódnak bármikor válaszolnia kell egy kérésre.

Példa: Dokumentum beolvasása

Az alábbi mintakód megpróbál lekérni egy megadott dokumentumot egy HTTP-kiszolgálóról. A rendszer lekéri az állapotkódot a válaszból annak megállapításához, hogy szükség van-e hitelesítésre. Ha 200 állapotkódot talál, a dokumentum elérhető. Ha 401 vagy 407 állapotkódot talál, a dokumentum lekérése előtt hitelesítésre van szükség. Bármely más állapotkód esetén hibaüzenet jelenik meg. A lehetséges állapotkódok listáját HTTP-állapotkódok.

#include <windows.h>
#include <winhttp.h>
#include <stdio.h>

#pragma comment(lib, "winhttp.lib")

DWORD ChooseAuthScheme( DWORD dwSupportedSchemes )
{
  //  It is the server's responsibility only to accept 
  //  authentication schemes that provide a sufficient
  //  level of security to protect the servers resources.
  //
  //  The client is also obligated only to use an authentication
  //  scheme that adequately protects its username and password.
  //
  //  Thus, this sample code does not use Basic authentication  
  //  becaus Basic authentication exposes the client's username
  //  and password to anyone monitoring the connection.
  
  if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NEGOTIATE )
    return WINHTTP_AUTH_SCHEME_NEGOTIATE;
  else if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NTLM )
    return WINHTTP_AUTH_SCHEME_NTLM;
  else if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_PASSPORT )
    return WINHTTP_AUTH_SCHEME_PASSPORT;
  else if( dwSupportedSchemes & WINHTTP_AUTH_SCHEME_DIGEST )
    return WINHTTP_AUTH_SCHEME_DIGEST;
  else
    return 0;
}

struct SWinHttpSampleGet
{
  LPCWSTR szServer;
  LPCWSTR szPath;
  BOOL fUseSSL;
  LPCWSTR szServerUsername;
  LPCWSTR szServerPassword;
  LPCWSTR szProxyUsername;
  LPCWSTR szProxyPassword;
};

void WinHttpAuthSample( IN SWinHttpSampleGet *pGetRequest )
{
  DWORD dwStatusCode = 0;
  DWORD dwSupportedSchemes;
  DWORD dwFirstScheme;
  DWORD dwSelectedScheme;
  DWORD dwTarget;
  DWORD dwLastStatus = 0;
  DWORD dwSize = sizeof(DWORD);
  BOOL  bResults = FALSE;
  BOOL  bDone = FALSE;

  DWORD dwProxyAuthScheme = 0;
  HINTERNET  hSession = NULL, 
             hConnect = NULL,
             hRequest = NULL;

  // Use WinHttpOpen to obtain a session handle.
  hSession = WinHttpOpen( L"WinHTTP Example/1.0",  
                          WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                          WINHTTP_NO_PROXY_NAME, 
                          WINHTTP_NO_PROXY_BYPASS, 0 );

  INTERNET_PORT nPort = ( pGetRequest->fUseSSL ) ? 
                        INTERNET_DEFAULT_HTTPS_PORT  :
                        INTERNET_DEFAULT_HTTP_PORT;

  // Specify an HTTP server.
  if( hSession )
    hConnect = WinHttpConnect( hSession, 
                               pGetRequest->szServer, 
                               nPort, 0 );

  // Create an HTTP request handle.
  if( hConnect )
    hRequest = WinHttpOpenRequest( hConnect, 
                                   L"GET", 
                                   pGetRequest->szPath,
                                   NULL, 
                                   WINHTTP_NO_REFERER, 
                                   WINHTTP_DEFAULT_ACCEPT_TYPES,
                                   ( pGetRequest->fUseSSL ) ? 
                                       WINHTTP_FLAG_SECURE : 0 );

  // Continue to send a request until status code 
  // is not 401 or 407.
  if( hRequest == NULL )
    bDone = TRUE;

  while( !bDone )
  {
    //  If a proxy authentication challenge was responded to, reset
    //  those credentials before each SendRequest, because the proxy  
    //  may require re-authentication after responding to a 401 or  
    //  to a redirect. If you don't, you can get into a 
    //  407-401-407-401- loop.
    if( dwProxyAuthScheme != 0 )
      bResults = WinHttpSetCredentials( hRequest, 
                                        WINHTTP_AUTH_TARGET_PROXY, 
                                        dwProxyAuthScheme, 
                                        pGetRequest->szProxyUsername,
                                        pGetRequest->szProxyPassword,
                                        NULL );
    // Send a request.
    bResults = WinHttpSendRequest( hRequest,
                                   WINHTTP_NO_ADDITIONAL_HEADERS,
                                   0,
                                   WINHTTP_NO_REQUEST_DATA,
                                   0, 
                                   0, 
                                   0 );

    // End the request.
    if( bResults )
      bResults = WinHttpReceiveResponse( hRequest, NULL );

    // Resend the request in case of 
    // ERROR_WINHTTP_RESEND_REQUEST error.
    if( !bResults && GetLastError( ) == ERROR_WINHTTP_RESEND_REQUEST)
        continue;

    // Check the status code.
    if( bResults ) 
      bResults = WinHttpQueryHeaders( hRequest, 
                                      WINHTTP_QUERY_STATUS_CODE |
                                      WINHTTP_QUERY_FLAG_NUMBER,
                                      NULL, 
                                      &dwStatusCode, 
                                      &dwSize, 
                                      NULL );

    if( bResults )
    {
      switch( dwStatusCode )
      {
        case 200: 
          // The resource was successfully retrieved.
          // You can use WinHttpReadData to read the 
          // contents of the server's response.
          printf( "The resource was successfully retrieved.\n" );
          bDone = TRUE;
          break;

        case 401:
          // The server requires authentication.
          printf(" The server requires authentication. Sending credentials...\n" );

          // Obtain the supported and preferred schemes.
          bResults = WinHttpQueryAuthSchemes( hRequest, 
                                              &dwSupportedSchemes, 
                                              &dwFirstScheme, 
                                              &dwTarget );

          // Set the credentials before resending the request.
          if( bResults )
          {
            dwSelectedScheme = ChooseAuthScheme( dwSupportedSchemes);

            if( dwSelectedScheme == 0 )
              bDone = TRUE;
            else
              bResults = WinHttpSetCredentials( hRequest, 
                                        dwTarget, 
                                        dwSelectedScheme,
                                        pGetRequest->szServerUsername,
                                        pGetRequest->szServerPassword,
                                        NULL );
          }

          // If the same credentials are requested twice, abort the
          // request.  For simplicity, this sample does not check
          // for a repeated sequence of status codes.
          if( dwLastStatus == 401 )
            bDone = TRUE;

          break;

        case 407:
          // The proxy requires authentication.
          printf( "The proxy requires authentication.  Sending credentials...\n" );

          // Obtain the supported and preferred schemes.
          bResults = WinHttpQueryAuthSchemes( hRequest, 
                                              &dwSupportedSchemes, 
                                              &dwFirstScheme, 
                                              &dwTarget );

          // Set the credentials before resending the request.
          if( bResults )
            dwProxyAuthScheme = ChooseAuthScheme(dwSupportedSchemes);

          // If the same credentials are requested twice, abort the
          // request.  For simplicity, this sample does not check 
          // for a repeated sequence of status codes.
          if( dwLastStatus == 407 )
            bDone = TRUE;
          break;

        default:
          // The status code does not indicate success.
          printf("Error. Status code %d returned.\n", dwStatusCode);
          bDone = TRUE;
      }
    }

    // Keep track of the last status code.
    dwLastStatus = dwStatusCode;

    // If there are any errors, break out of the loop.
    if( !bResults ) 
        bDone = TRUE;
  }

  // Report any errors.
  if( !bResults )
  {
    DWORD dwLastError = GetLastError( );
    printf( "Error %d has occurred.\n", dwLastError );
  }

  // Close any open handles.
  if( hRequest ) WinHttpCloseHandle( hRequest );
  if( hConnect ) WinHttpCloseHandle( hConnect );
  if( hSession ) WinHttpCloseHandle( hSession );
}

Automatikus bejelentkezési szabályzat

Az automatikus bejelentkezési (automatikus bejelentkezési) szabályzat határozza meg, hogy a WinHTTP mikor foglalja bele az alapértelmezett hitelesítő adatokat egy kérésbe. Az alapértelmezett hitelesítő adatok az aktuális szál jogkivonata vagy a munkamenet-jogkivonat attól függően, hogy a WinHTTP szinkron vagy aszinkron módban van-e használva. A szál jogkivonata szinkron módban, a munkamenet-jogkivonat pedig aszinkron módban használatos. Ezek az alapértelmezett hitelesítő adatok gyakran a Microsoft Windowsba való bejelentkezéshez használt felhasználónév és jelszó.

Az automatikus bejelentkezési szabályzat azért lett implementálva, hogy megakadályozza ezeket a hitelesítő adatokat a nem megbízható kiszolgálóval való hitelesítéshez. Alapértelmezés szerint a biztonsági szint WINHTTP_AUTOLOGON_SECURITY_LEVEL_MEDIUM értékre van állítva, így az alapértelmezett hitelesítő adatok csak intranetes kérelmekhez használhatók. Az automatikus bejelentkezési szabályzat csak az NTLM és az Egyeztetés hitelesítési sémákra vonatkozik. A hitelesítő adatok soha nem lesznek automatikusan továbbítva más sémákkal.

Az automatikus bejelentkezési szabályzat a WinHttpSetOption függvénnyel állítható be a WINHTTP_OPTION_AUTOLOGON_POLICY jelzővel. Ez a jelző csak a kérelemleíróra vonatkozik. Ha a házirend WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW van beállítva, az alapértelmezett hitelesítő adatok az összes kiszolgálóra elküldhetők. Ha a házirend WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH van beállítva, az alapértelmezett hitelesítő adatok nem használhatók hitelesítéshez. Erősen ajánlott közepes szinten használni az automatikus bejelentkezést.

Tárolt felhasználónevek és jelszavak

A Windows XP bevezette a tárolt felhasználónevek és jelszavak fogalmát. Ha egy felhasználó Passport-hitelesítő adatait a rendszer a Passport-regisztráció varázsló vagy a hitelesítő adatok szokásos párbeszédpanelenmenti, a rendszer a tárolt felhasználónevekbe és jelszavakba menti. Ha a WinHTTP-t Windows XP vagy újabb rendszeren használja, a WinHTTP automatikusan használja a tárolt felhasználónevek és jelszavak hitelesítő adatait, ha a hitelesítő adatok nincsenek explicit módon beállítva. Ez hasonló az NTLM/Kerberos alapértelmezett bejelentkezési hitelesítő adatainak támogatásához. Az alapértelmezett Passport-hitelesítő adatok használatára azonban nem vonatkoznak az automatikus bejelentkezési szabályzat beállításai.