Utilização de credenciais de certificado com MSAL Node

Pode construir aplicações cliente confidenciais com MSAL Node (aplicações web, aplicações daemon, etc). Uma credencial de cliente é obrigatória para clientes confidenciais.

Pré-requisitos

Pode construir aplicações cliente confidenciais com MSAL Node (aplicações web, aplicações daemon, etc). Uma credencial de cliente é obrigatória para clientes confidenciais. A credencial do cliente pode ser:

  • managed identity: trata-se de um cenário sem certificado, onde a confiança é estabelecida através da infraestrutura do Azure. Não é necessário gerir segredos ou certificados. A MSAL ainda não implementa esta funcionalidade, mas pode usar o Azure Identity SDK em vez disso. Consulte a documentação sobre identidades geridas para recursos do Azure
  • clientSecret: uma cadeia secreta gerada durante o registo da aplicação, ou atualizada após o registo para uma aplicação existente. Isto não é recomendado para produção.
  • clientCertificate: um certificado definido durante o registo da aplicação. O certificado precisa de ter a chave privada, porque é usada para assinar uma asserção gerada pelo MSAL. O thumbprintSha256 é uma impressão digital X.509 SHA-256 do certificado, e o privateKey é a chave privada codificada no formato PEM.
  • clientAssertion: em vez de deixar a MSAL criar uma asserção, o programador da aplicação assume o controlo. Útil para adicionar reivindicações extra à asserção ou para usar o KeyVault para assinar, em vez de um certificado local. O certificado usado para assinar a afirmação ainda precisa de ser definido durante o registo da aplicação.

Nota: as apps 1p poderão também ter de enviar x5c. Esta é a cadeia de certificados X.509 usada em cenários de autenticação por nome do sujeito/emissor.

Utilização segura de segredos e certificados

Segredos nunca devem ser codificados fixamente. O pacote dotenv npm pode ser usado para armazenar segredos ou certificados num ficheiro .env (localizado na pasta raiz do projeto) que deve ser incluído no .gitignore para evitar uploads acidentais dos segredos.

Os certificados também podem ser lidos a partir de ficheiros através do módulo fs do NodeJS. No entanto, nunca devem ser armazenados no diretório do projeto. As aplicações de produção devem obter certificados do Azure KeyVault ou de outros cofres de chaves seguros.

Por favor, consulte certificados e segredos para mais informações.

Veja o exemplo de MSAL: auth-code-with-certs

Registo de certificados

Se não tiver um certificado, pode criar um certificado auto-assinado usando PowerShell ou usando o Azure KeyVault.

Precisa de carregar o seu certificado para o Microsoft Entra ID.

  1. Navegue até ao portal Azure e selecione o registo da sua aplicação Microsoft Entra.
  2. Selecione, à esquerda, o separador Certificados e segredos.
  3. Clique em Carregar certificado e selecione o ficheiro de certificado a carregar (por exemplo , example.crt).
  4. Clique em Adicionar. Uma vez carregado o certificado, a impressão digital (SHA-256),a data de início e os valores de validade são apresentados.

Para mais informações, veja: Registe o seu certificado na plataforma de identidades da Microsoft

Inicializar o MSAL Node com certificados

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);

É esperado que tanto thumbprintSha256 como privateKey sejam cadeias de caracteres. privateKey espera-se ainda que seja na seguinte forma (PKCS#8):

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

Note

Alternativamente, a sua chave privada pode começar com -----BEGIN PRIVATE KEY----- ( PKCS#8 não encriptado) ou -----BEGIN RSA PRIVATE KEY----- (PKCS#1). Estes formatos também são permitidos. O seguinte pode ser usado para converter qualquer chave compatível para o tipo de chave PKCS#8:

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

Se encriptou a sua chave privada (ou se a sua chave privada já estiver encriptada) com uma frase de acesso, terá de a desencriptar antes de a passar para o MSAL Node.

Importante: Nunca codifiquem palavras-passe no código-fonte. Tanto a chave privada do certificado como a palavra-passe opcional de desencriptação devem ser obtidas de um local seguro (por exemplo, Azure KeyVault) e implementadas de forma segura com a sua API web.

Isto pode ser feito usando o módulo cripto do Node. Use o createPrivateKey() método para analisar e exportar a sua chave:

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'
});

(Opcional) Converter pfx em pem

O OpenSSL pode ser usado para converter ficheiros de certificado codificados em pfx para pem:

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

Se a conversão tiver de ser feita programaticamente, então poderá ter de recorrer a um pacote de terceiros, pois Node.js não oferece método nativo para isso. Por exemplo, usando uma implementação popular de TLS como o node-forge, pode fazer:

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
    };
}

(Opcional) Criação de um servidor HTTPS

O protocolo OAuth 2.0 recomenda a utilização de uma ligação HTTPS sempre que possível. A maioria dos serviços na cloud, como o Serviço de Aplicações do Azure, disponibiliza uma ligação HTTPS por defeito através de um proxy. Se, para fins de teste, quiser configurar o seu próprio servidor HTTPS, consulte a documentação Node.js para orientações sobre como criar um servidor HTTPS.

Também terá de adicionar os seus certificados auto-assinados àcadeia de chaves / de credenciais do seu sistema operativo para contornar a política de segurança do navegador. Pode ainda assim ver um aviso no seu navegador depois (por exemplo, Chrome).

Warning

Pode precisar de privilégios de administrador para executar os comandos acima.

Problemas comuns

Em alguns casos, pode receber um erro do Microsoft Entra ID ao tentar autenticar usando certificados, como o AADSTS700027: Client assertion contains an invalid signature erro, indicando que os certificados e/ou chaves privadas que utiliza para inicializar o MSAL Node estão malformados. Uma razão comum para isto é que a cadeia de certificados / chaves privadas que está a fornecer ao Nó MSAL contém caracteres inesperados, como carros de retorno (\r) ou novas linhas (\n):

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

Em alternativa, o seu ficheiro de certificado/chave pode conter bag attributes:

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-----

Nesses casos, és responsável por limpar a string antes de a passar para a configuração do MSAL Node. Por exemplo:

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);

Consulte também