Axios s využitím certifikátů (SSL)

Mutual TLS (SSL klientský certifikát)

Od verze TAS 5.17 lze pro HTTPS požadavky nastavit klientský SSL certifikát (mutual TLS) metodou applySslConfig(). Metoda vrací stejnou instanci klienta, takže ji lze řetězit s dalším nastavením (např. setVaultHeader).

Způsob, jakým se získá hodnota certifikátu, se mezi verzemi 5.17 a 5.19 liší — viz sekce níže.

Parametry

Metoda přijímá jeden konfigurační objekt opts:

Parametr

Typ

Popis

ca

string | Buffer | VaultSecretRef

CA bundle (certifikační autorita). Nepovinné.

cert

string | Buffer | VaultSecretRef

Klientský certifikát. Nepovinné.

key

string | Buffer | VaultSecretRef

Privátní klíč ke klientskému certifikátu. Nepovinné.

passphrase

string

Heslo k privátnímu klíči (pokud je klíč zašifrovaný). Nepovinné.

rejectUnauthorized

boolean

Ověřovat SSL certifikát serveru. Výchozí hodnota true.

ciphers

string

Seznam povolených TLS šifer (OpenSSL formát). Nepovinné. Používá se pro kompatibilitu se staršími službami — viz upozornění u praktického příkladu.

TAS 5.17 — hodnota certifikátu přes lib.getCertificate()

Ve verzi 5.17 ještě Trezor certifikáty nesdružuje. Hodnotu certifikátu je nutné načíst „postaru" funkcí lib.getCertificate(certName, encoding?) (výchozí kódování binary) a předat ji do applySslConfig() jako string nebo Buffer.

const client = axios.getAxios({ baseURL: 'https://api.mutual-tls.example.com' });
client.applySslConfig({
ca: lib.getCertificate('mtls-ca'),
cert: lib.getCertificate('mtls-client-cert'),
key: lib.getCertificate('mtls-client-key'),
});

const response = client.get('/secure-endpoint');
return response.data;
Absolutní cestu k souboru certifikátu vrací lib.getCertificatePath(certName).

TAS 5.18 — certifikáty i externí zdroje z Trezoru přes vault.get()

Od verze 5.18 Trezor sdružuje jak citlivé hodnoty (API klíče, hesla, tokeny), tak certifikáty a externí zdroje (Administrace → Trezor, záložka Externí zdroje). Ve výpočtu se vše načítá jednotně přes vault.get(name), který vrací VaultSecretRef — ten nelze serializovat ani zalogovat a předává se přímo do applySslConfig().

const client = axios.getAxios({ baseURL: 'https://api.mutual-tls.example.com' });
client.applySslConfig({
ca: vault.get('MTLS_CA'),
cert: vault.get('MTLS_CLIENT_CERT'),
key: vault.get('MTLS_CLIENT_KEY'),
});

const response = client.get('/secure-endpoint');
return response.data;
Stejným způsobem (vault.get(...)) se v 5.18 načítají i hodnoty z externích zdrojů definované na úrovni serverové konfigurace, např. v souboru .env.

Nastavení rejectUnauthorized: false vypne ověření serverového certifikátu a vystavuje spojení riziku MITM útoku. Používej pouze pro testování proti self-signed certifikátům, nikdy v produkci.

Praktický příklad — SOAP volání s klientským certifikátem

Nejčastějším reálným použitím mutual TLS je volání staršího SOAP endpointu (typicky služby státní správy nebo bankovní rozhraní), který se zároveň prokazuje klientským certifikátem. Oproti jednoduchému client.get() výše přibývají tři věci: XML tělo přes Buffer.from, hlavička SOAPAction a použití requestRaw. Ukázku si projdeme po částech.

1. Tělo požadavku přes Buffer.from

Axios ve výchozím stavu serializuje tělo jako JSON. SOAP obálka je ale XML — aby ji axios odeslal beze změny, obalí se do binárního Buffer:

const payload = Buffer.from(xml, 'utf-8');

Proměnná xml obsahuje hotovou SOAP obálku jako text; Buffer.from(..., 'utf-8') ji převede na binární data.

2. Klient s explicitním timeoutem

SOAP služby bývají pomalejší, proto nastav dostatečný timeout (v milisekundách). Výchozí hodnota 0 se totiž řídí globálním timeoutem výpočtu (120 s), což u pomalé služby nemusí stačit:

const client = axios.getAxios({
    timeout: 300000
});

3. Nastavení certifikátu

Konfigurace je stejná jako v příkladech výše — zde s hodnotami z Trezoru přes lib.getCertificate() (TAS 5.17). Navíc se objevují dva parametry snižující zabezpečení, které legacy SOAP služby často vyžadují:

client.applySslConfig({
    cert: lib.getCertificate('client.pem'),
    key: lib.getCertificate('client.key'),
    rejectUnauthorized: false,
    ciphers: "DEFAULT@SECLEVEL=0"
});

Parametr ciphers určuje povolené šifry TLS. Hodnota DEFAULT@SECLEVEL=0 snižuje bezpečnostní úroveň OpenSSL a povoluje starší, jinak zakázané šifry a slabší klíče — bez ní se se staršími službami nemusí podařit navázat spojení.

Kombinace rejectUnauthorized: false a ciphers: "DEFAULT@SECLEVEL=0" záměrně snižuje bezpečnost spojení — vypíná ověření serverového certifikátu (riziko MITM) a povoluje zastaralé šifry. Používej ji pouze tam, kde to protistrana skutečně vyžaduje. Pokud služba běží na moderním certifikátu, obě volby vynech.

4. Odeslání přes requestRaw

SOAP se posílá metodou POST. Hlavička SOAPAction je u SOAP 1.1 povinná — hodnota '""' (prázdné uvozovky) se používá, když služba nevyžaduje konkrétní akci. Použije se requestRaw, protože ze SOAP odpovědi je obvykle potřeba i stavový kód a hlavičky:

const result = client.requestRaw({
    method: 'POST',
    url,
    data: payload,
    headers: {
        'SOAPAction': '""'
    }
});
requestRaw (od verze 5.7.37) vrací plnou odpověď { data, status, statusText, headers } a na chybový status nevyhazuje výjimku — stavový kód proto zkontroluj ručně (např. if (result.status !== 200)). Klasické metody (get, post, …) vracejí přímo data a na chybu výjimku vyhodí; ty použij u běžných JSON API, kde status ani hlavičky nepotřebuješ.

Kompletní kód
const payload = Buffer.from(xml, 'utf-8');

const client = axios.getAxios({
    timeout: 300000
});
client.applySslConfig({
    cert: lib.getCertificate('client.pem'),
    key: lib.getCertificate('client.key'),
    rejectUnauthorized: false,
    ciphers: "DEFAULT@SECLEVEL=0"
});

const result = client.requestRaw({
    method: 'POST',
    url,
    data: payload,
    headers: {
        'SOAPAction': '""'
    }
});
Volání je synchronníresult obsahuje odpověď rovnou. Nikdy nepoužívej async, await, .then() ani Promise; TAS transpilace by způsobila tiché selhání výpočtu.

Frantisek Brych Updated by Frantisek Brych

AXIOS s využitím Trezoru

Contact

Team assistant (opens in a new tab)

Powered by HelpDocs (opens in a new tab)