Używanie poświadczeń opartych na certyfikacie z biblioteką MSAL Node

Poufne aplikacje klienckie można tworzyć za pomocą biblioteki MSAL Node (aplikacje internetowe, aplikacje demona itp.). Poświadczenia klienta są obowiązkowe dla poufnych klientów.

Wymagania wstępne

Poufne aplikacje klienckie można tworzyć za pomocą biblioteki MSAL Node (aplikacje internetowe, aplikacje demona itp.). Poświadczenia klienta są obowiązkowe dla poufnych klientów. Poświadczenia klienta mogą być następujące:

  • managed identity: jest to scenariusz bez certyfikatów, w którym zaufanie jest ustanawiane za pośrednictwem infrastruktury Azure. Nie jest wymagane zarządzanie sekretami ani certyfikatami. Biblioteka MSAL nie implementuje jeszcze tej funkcji, ale zamiast niej możesz użyć Azure Identity SDK. Zobacz dokumentację tożsamości zarządzanych dla zasobów platformy Azure
  • clientSecret: tajny ciąg znaków wygenerowany podczas rejestracji aplikacji lub zaktualizowany po rejestracji dla istniejącej aplikacji. Nie jest to zalecane w środowisku produkcyjnym.
  • clientCertificate: certyfikat ustawiony podczas rejestracji aplikacji. Certyfikat musi zawierać klucz prywatny, ponieważ jest on używany do podpisywania asercji, którą generuje MSAL. thumbprintSha256 to odcisk X.509 SHA-256 certyfikatu, a privateKey to klucz prywatny zakodowany w formacie PEM.
  • clientAssertion: zamiast zezwalać na tworzenie asercji przez bibliotekę MSAL, deweloper aplikacji przejmuje kontrolę. Przydatne w przypadku dodawania dodatkowych oświadczeń do asercji lub używania usługi KeyVault do podpisywania zamiast certyfikatu lokalnego. Certyfikat używany do podpisywania asercji nadal musi być ustawiony podczas rejestracji aplikacji.

Uwaga: od aplikacji 1P może być również wymagane wysyłanie x5c. Jest to łańcuch certyfikatów X.509 używany w scenariuszach uwierzytelniania nazwy podmiotu/wystawcy.

Bezpieczne używanie wpisów tajnych i certyfikatów

Wpisy tajne nigdy nie powinny być zakodowane na stałe. Pakiet npm dotenv może służyć do przechowywania wpisów tajnych lub certyfikatów w pliku env (znajdującym się w katalogu głównym projektu), który powinien zostać uwzględniony w pliku gitignore, aby zapobiec przypadkowym przekazaniu wpisów tajnych.

Certyfikaty można również odczytywać z plików za pośrednictwem modułu fs środowiska NodeJS. Jednak nigdy nie powinny być przechowywane w katalogu projektu. Aplikacje produkcyjne powinny pobierać certyfikaty z usługi Azure KeyVault lub innych bezpiecznych magazynów kluczy.

Aby uzyskać więcej informacji, zobacz certyfikaty i wpisy tajne .

Zobacz przykład MSAL: auth-code-with-certs

Rejestrowanie certyfikatów

Jeśli nie masz certyfikatu, możesz utworzyć certyfikat z podpisem własnym przy użyciu programu PowerShell lub Azure KeyVault.

Musisz przekazać certyfikat do Microsoft Entra ID.

  1. Przejdź do portalu Azure i wybierz rejestrację aplikacji Microsoft Entra.
  2. Wybierz blok Certyfikaty i wpisy tajne po lewej stronie.
  3. Kliknij pozycję Przekaż certyfikat i wybierz plik certyfikatu do przekazania (np. example.crt).
  4. Kliknij przycisk Dodaj. Po przesłaniu certyfikatu zostaną wyświetlone wartości odcisku (SHA-256), daty rozpoczęcia i wygaśnięcia.

Aby uzyskać więcej informacji, zobacz: Rejestrowanie certyfikatu przy użyciu Platforma tożsamości Microsoft

Inicjowanie biblioteki MSAL Node za pomocą certyfikatów

const msal = require('@azure/msal-node');
require('dotenv').config(); // process.env now has the values defined in a .env file

const config = {
    auth: {
        clientId: "YOUR_CLIENT_ID",
        authority: "https://login.microsoftonline.com/YOUR_TENANT_ID",
        clientCertificate: {
            thumbprintSha256: process.env.thumbprint,
            privateKey: process.env.privateKey,
        }
    }
};

// Create msal application object
const cca = new msal.ConfidentialClientApplication(config);

Zarówno thumbprintSha256, jak i privateKey powinny być ciągami znaków. privateKey powinien dodatkowo mieć następującą postać (PKCS#8):

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDkpKPrsfpIijS3
z2HCpDsa7dxOsKIrm7F1AtGBjyB0yVDjlh/FA7jT5sd2ypBh3FVsZGJudQsLRKfE
// ...
-----END ENCRYPTED PRIVATE KEY-----

Note

Możesz też zacząć od -----BEGIN PRIVATE KEY----- klucza prywatnego (niezaszyfrowanego PKCS#8) lub -----BEGIN RSA PRIVATE KEY----- (PKCS#1). Te formaty są również dopuszczalne. Następujące elementy mogą służyć do konwertowania dowolnego zgodnego klucza na typ klucza PKCS#8:

openssl pkcs8 -topk8 -inform PEM -outform PEM -in example.key -out example.key

Jeśli zaszyfrowano Twój klucz prywatny (lub jeśli Twój klucz prywatny jest już zaszyfrowany) za pomocą hasła, musisz go odszyfrować przed przekazaniem go do MSAL Node.

Ważne: nigdy nie koduj haseł na stałe w kodzie źródłowym. Zarówno klucz prywatny certyfikatu, jak i opcjonalne hasło descryption powinny być pobierane z bezpiecznej lokalizacji (np. Azure KeyVault) i wdrożone bezpiecznie za pomocą internetowego interfejsu API.

Można to zrobić przy użyciu modułu kryptograficznego node. createPrivateKey() Użyj metody , aby przeanalizować i wyeksportować klucz:

const fs = require('fs');
const crypto = require('crypto');

const privateKeySource = fs.readFileSync('<path_to_key>/example.key')

const privateKeyObject = crypto.createPrivateKey({
    key: privateKeySource,
    passphrase: process.env.YOUR_PASSPHRASE,
    format: 'pem'
});

const privateKey = privateKeyObject.export({
    format: 'pem',
    type: 'pkcs8'
});

(Opcjonalnie) Konwertowanie pliku pfx na pem

Protokół OpenSSL może służyć do konwertowania plików certyfikatów zakodowanych w formacie pfx na pem:

    openssl pkcs12 -in certificate.pfx -out certificate.pem

Jeśli konwersja musi nastąpić programowo, być może trzeba będzie polegać na pakiecie innej firmy, ponieważ Node.js nie oferuje dla tego natywnej metody. Na przykład przy użyciu popularnej implementacji protokołu TLS, takiej jak node-forge, można wykonać następujące czynności:

const forge = require('node-forge');

/**
 * @param {string} pfx: certificate + private key combination in pfx format
 * @param {string} passphrase: passphrase used to encrypt pfx file
 * @returns {Object}
 */
function convertPFX(pfx, passphrase = null) {

    const asn = forge.asn1.fromDer(forge.util.decode64(pfx));
    const p12 = forge.pkcs12.pkcs12FromAsn1(asn, true, passphrase);

    // Retrieve key data
    const keyData = p12.getBags({ bagType: forge.pki.oids.pkcs8ShroudedKeyBag })[forge.pki.oids.pkcs8ShroudedKeyBag]
        .concat(p12.getBags({ bagType: forge.pki.oids.keyBag })[forge.pki.oids.keyBag]);

    // Retrieve certificate data
    const certBags = p12.getBags({ bagType: forge.pki.oids.certBag })[forge.pki.oids.certBag];
    const certificate = forge.pki.certificateToPem(certBags[0].cert)

    // Convert a Forge private key to an ASN.1 RSAPrivateKey
    const rsaPrivateKey = forge.pki.privateKeyToAsn1(keyData[0].key);

    // Wrap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfo
    const privateKeyInfo = forge.pki.wrapRsaPrivateKey(rsaPrivateKey);

    // Convert a PKCS#8 ASN.1 PrivateKeyInfo to PEM
    const privateKey = forge.pki.privateKeyInfoToPem(privateKeyInfo);

    console.log("Converted certificate: \n", certificate);
    console.log("Converted key: \n", privateKey);

    return {
        certificate: certificate,
        key: privateKey
    };
}

(Opcjonalnie) Tworzenie serwera HTTPS

Protokół OAuth 2.0 zaleca korzystanie z połączenia HTTPS zawsze, gdy jest to możliwe. Większość usług w chmurze, takich jak Azure App Service, domyślnie zapewnia połączenie HTTPS za pośrednictwem serwera proxy. Jeśli na potrzeby testowania chcesz skonfigurować własny serwer HTTPS, zapoznaj się z dokumentacją Node.js, aby uzyskać wskazówki dotyczące tworzenia serwera HTTPS.

Należy również dodać certyfikaty z podpisem własnym dołańcucha kluczy / poświadczeń systemu operacyjnego, aby pominąć zasady zabezpieczeń przeglądarki. W przeglądarce może być nadal wyświetlane ostrzeżenie (np. Chrome).

  • Użytkownicy systemu Windows powinni skorzystać z tego przewodnika: Jak wyświetlać certyfikaty za pomocą przystawki MMC.

  • W przypadku użytkowników systemów Linux i MacOS zapoznaj się z dokumentacją systemu operacyjnego dotyczącą sposobu instalowania certyfikatów.

Warning

Do uruchamiania powyższych poleceń może być konieczne uprawnienia administratora .

Typowe problemy

W niektórych przypadkach podczas próby uwierzytelnienia przy użyciu certyfikatów może zostać zwrócony przez Microsoft Entra ID komunikat o błędzie, na przykład błąd AADSTS700027: Client assertion contains an invalid signature, który wskazuje, że certyfikaty i/lub klucze prywatne używane do inicjowania biblioteki MSAL Node są nieprawidłowo sformatowane. Częstą przyczyną jest to, że ciąg certyfikatu /klucza prywatnego, który dostarczasz do węzła BIBLIOTEKi MSAL, zawiera nieoczekiwane znaki, takie jak karetki powrotne (\r) lub nowe linie (\n):

-----BEGIN CERTIFICATE-----\nMIIDDzCCAfegAwIBAgIJAMkyzQVK88NHMA0GCSqGSIb3DQEBBQUAMIGCMQswCQYDVQQGEwJTRTESMBAGA1UECBMJU3RvY2tob2xtMQ4wDAYDVQQHEwVLaXN0YTEQMA4G0fbkqbKulrchGbNgkankZtEVg4PGjobZq7B+njvcVa7SsWF/WLq5AUbw==\r\n-----END CERTIFICATE-----

Alternatywnie plik certyfikatu/klucza może zawierać atrybuty torby:

Bag Attributes
    localKeyID: 28 B5 8E 16 11 88 E9 00 58 D5 76 30 12 B9 59 B8 E4 CE 7C AA
subject=/C=UK/ST=Suffolk/L=Ipswich/O=Example plc/CN=alice
issuer=/C=UK/ST=Suffolk/L=Ipswich/O=Example plc/CN=Certificate Authority/emailAddress=ca@example.com\n
-----BEGIN CERTIFICATE-----
MIIDDzCCAfegAwIBAgIJAMkyzQVK88NHMA0GCSqGSIb3DQEBBQUAMIGCMQswCQYD
VQQGEwJTRTESMBAGA1UECBMJU3RvY2tob2xtMQ4wDAYDVQQHEwVLaXN0YTEQMA4G
0fbkqbKulrchGbNgkankZtEVg4PGjo+Y8MdMjtfSZB29hwYvfMX09jzJ68ZqmpYQ
njvcVtLbEZN5OGCkaslb/f2OxLbsUNgIbws538WnaaufDvKmQe2kUdWmpl9Wn9Bf
bZq7B+njvcVa7SsWF/WLq5AUbw==
-----END CERTIFICATE-----

W takich przypadkach odpowiadasz za oczyszczenie ciągu znaków przed przekazaniem go do konfiguracji MSAL Node. Przykład:

const msal = require('@azure/msal-node');
const fs = require('fs');

const privateKeySource = fs.readFileSync('<path_to_key>/certs/example.key');
const privateKey = Buffer.from(privateKeySource, 'base64').toString().replace(/\r/g, "").replace(/\n/g, "");

const config = {
    auth: {
        clientId: "YOUR_CLIENT_ID",
        authority: "https://login.microsoftonline.com/YOUR_TENANT_ID",
        clientCertificate: {
            thumbprintSha256: process.env.thumbprint,
            privateKey: privateKey,
        }
    }
};

// Create msal application object
const cca = new msal.ConfidentialClientApplication(config);

Zobacz także