IlmHamroh
JavaScript Full-stack/25-qism. HTTP, Express va REST API6/51-dars17 daqiqa
Mundarija (28)

HTTPS Node.js'da: TLS sertifikati, https.createServer, HTTP/2 va ALPN

Qisqacha: HTTPS — HTTP'ning TLS bilan shifrlangan ko'rinishi. Node'da u https.createServer({ key, cert }, ishlovchi) bilan yoqiladi: kalit va sertifikat kerak. Lokal ishlash uchun sertifikatni mkcert yoki openssl yasaydi, internetdagi domen uchun — Let's Encrypt. Lekin prodakshnda TLS'ni ko'pincha Node emas, oldidagi proxy (nginx, Caddy) bajaradi — bu TLS termination. HTTP/2 brauzerda faqat TLS ustida ishlaydi va protokolni ALPN kelishadi. Biz o'lchadik: 10 ta parallel so'rov (har biri 100 ms) HTTP/2 da bitta TCP ulanish orqali 133 ms da tugadi.

Bu darsda

  • TLS sertifikati ichida nima borligini Node'ning X509Certificate bilan o'qiysiz.
  • https.createServer bilan lokal HTTPS server ochasiz va "ishonchsiz sertifikat" xatolarini tushuntirasiz.
  • mkcert, Let's Encrypt va TLS termination qachon kerakligini ajrata olasiz.
  • node:http2 serverini, ALPN kelishuvini va multiplexing'ni o'lchov bilan ko'rasiz.
  • HTTP'dan HTTPS'ga xavfsiz yo'naltirish yozasiz.

Oldin bilishingiz kerak: HTTPS va TLS, HTTP versiyalari va real-time aloqa, net, dns va tls, Static fayl server.

1. Nega bu kerak?

HTTPS darsida brauzer tomonini ko'rgansiz: qulf belgisi, sertifikat, shifrlangan kanal. net, dns va tls darsida esa tls.connect bilan mijoz sifatida sertifikat zanjirini o'qigansiz. Endi navbat server tomonida: vazifalar-api HTTPS bilan qanday ishlaydi?

Sabablar aniq. HTTP'da parol, token va vazifalar matni ochiq ketadi — kafedagi Wi-Fi'da o'tirgan har kim o'qiy oladi. Brauzerlar HTTP sahifalarni "Xavfsiz emas" deb belgilaydi. HTTP/2 brauzerda faqat HTTPS bilan ishlaydi. Secure cookie va Service Worker ham faqat HTTPS'da (28-qismda cookie'ni chuqur ko'rasiz).

Lekin bu darsning asosiy xulosasi kutilmagan bo'lishi mumkin: ko'pincha TLS'ni Node'da o'zingiz qilmaysiz. Buni tushunish uchun avval Node'da qanday qilinishini ko'ramiz.

O'xshatish: bank binosi. Kirish eshigida qo'riqchi pasportni tekshiradi va metall detektordan o'tkazadi (TLS). Ichkarida xodimlar bir-biriga hujjatni oddiy uzatadi — ular allaqachon himoyalangan binoda. Har xodimning stolida alohida qo'riqchi qo'yish (har Node jarayonida TLS) — mumkin, lekin qimmat va noqulay.

2. Sertifikat va kalit

2.1 Ikki fayl

HTTPS server uchun ikki narsa kerak:

  • Shaxsiy kalit (private key) — faqat serverda turadigan sir. U bilan server "men haqiqatan shu domenman" deb imzo qo'yadi.
  • Sertifikat (certificate) — ochiq hujjat: domen nomi, ochiq kalit, amal qilish muddati va uni tasdiqlagan tashkilot (CA — certificate authority, "sertifikat beruvchi markaz") imzosi.

Brauzer sertifikatni oladi va uch narsani tekshiradi: imzo ishonchli CA'dan zanjir bo'ylab keladimi, muddati o'tmaganmi, ichidagi domen manzil satridagi domenga mosmi. crypto darsida imzoning o'zini ko'rgansiz — bu o'sha mexanizm.

2.2 Sertifikatni Node bilan o'qish

Kanon tajribasida sertifikat Git bilan keladigan OpenSSL 3.5.6 bilan yasaldi: P256 egri chiziqli (prime256v1) kalit, 2 kun muddat, domen localhost va IP 127.0.0.1. Kalit va sertifikat faqat vaqtinchalik papkada turdi — Git'ga tushmadi. Buyruq:

bash
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
  -nodes -days 2 -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \
  -keyout kalit.pem -out sert.pem

-x509 — so'rov emas, darhol tayyor sertifikat. -nodes — kalitni parolsiz saqlash (lokal sinov uchun). subjectAltName (SAN) — sertifikat qaysi nomlar uchun amal qilishi. Zamonaviy brauzerlar va Node faqat SAN'ga qaraydi, eski CN maydoniga emas.

Quyidagi blokda biz shunday yasagan ochiq sertifikat bor (kalitsiz — sertifikat sir emas). Node'ning X509Certificate klassi uni o'qiydi:

js
import { X509Certificate } from "node:crypto";

const pem = `-----BEGIN CERTIFICATE-----
MIIBmDCCAT6gAwIBAgITCU1qCZdn5AHpVRXMd4LOyjlGCTAKBggqhkjOPQQDAjAU
MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjYxMDI0MDY0MTI5WhcNMjYxMDI2MDY0
MTI5WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB
BwNCAAQJmRf8e3dnbERWm7W4AucwahvQc+zJVvvEap2xX2J1A8duXO4i6H1vgieq
tl/5LJM8/Jp1j0/0A+J69mAb+OvEo28wbTAdBgNVHQ4EFgQUNcct0DYDdKrC/5jW
b7wtq4ZrYrkwHwYDVR0jBBgwFoAUNcct0DYDdKrC/5jWb7wtq4ZrYrkwDwYDVR0T
AQH/BAUwAwEB/zAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwCgYIKoZIzj0E
AwIDSAAwRQIhAMFmuEl02uaFA4MJgtbZ9ETpVsIlwIbQ66SjDn9ENE3GAiBC3GTY
nDxp7Tlw59PK0ng6spfPaTpTliY79KPvqizEOw==
-----END CERTIFICATE-----`;

const sert = new X509Certificate(pem);
console.log("subject:", sert.subject);
console.log("issuer:", sert.issuer);
console.log("SAN:", sert.subjectAltName);
console.log("gacha:", sert.validToDate.toISOString());
console.log("localhost:", sert.checkHost("localhost"));
console.log("example.com:", sert.checkHost("example.com"));
console.log("o'zi imzolagan:", sert.verify(sert.publicKey));

Konsolda:

text
subject: CN=localhost
issuer: CN=localhost
SAN: DNS:localhost, IP Address:127.0.0.1
gacha: 2026-10-26T06:41:29.000Z
localhost: localhost
example.com: undefined
o'zi imzolagan: true

subject va issuer bir xil — sertifikatni o'zi imzolagan. Buni self-signed (o'z-o'zidan imzolangan) sertifikat deymiz. Oxirgi qator ham shuni tasdiqlaydi: sertifikat o'zining ochiq kaliti bilan tekshirilganda imzo to'g'ri chiqdi. Hech qanday CA kafolat bermagan, shuning uchun brauzer ham, Node ham unga sukut bo'yicha ishonmaydi. checkHost("example.com") — undefined: bu sertifikat boshqa domen uchun yaroqsiz.

Tekshirib ko'ring: Sertifikat — ochiq hujjat, uni darsga qo'yish mumkin. Shaxsiy kalitni-chi?

Javob

Yo'q. Kalit kimda bo'lsa, o'sha "men localhost'man" (yoki haqiqiy domenda — "men sizning saytingizman") deb imzo qo'ya oladi. Kalit Git'ga, darsga, chatga tushmaydi. Kanonda ham kalit faqat vaqtinchalik papkada yaratildi va o'chirildi.

3. https.createServer

3.1 Server — http bilan deyarli bir xil

node:https moduli node:http ning nusxasi, faqat birinchi argument — TLS sozlamalari:

js
import https from "node:https";
import { readFileSync } from "node:fs";

const server = https.createServer(
  { key: readFileSync("kalit.pem"), cert: readFileSync("sert.pem") },
  (req, res) => res.end(`salom, ${req.socket.getProtocol()}\n`),
);
server.listen(0, "127.0.0.1");

Ishlovchi o'zgarmaydi: o'sha req va res. Farq ulanish darajasida — req.socket endi TLSSocket, getProtocol() esa kelishilgan TLS versiyasini qaytaradi. Bu blok kalit faylini o'qiydi, shuning uchun nocheck — o'z kompyuteringizda openssl buyrug'idan keyin ishga tushiring.

3.2 Ishonchsiz sertifikat: uch mijoz, uch xil javob

Kanon shu serverga turli mijozlar bilan murojaat qildi (Node 24.21.0, Windows 11, curl 8.19.0 Schannel bilan):

text
curl $A → exit 60: curl: (60) schannel: SEC_E_UNTRUSTED_ROOT (0x80090325) - The certificate chain was issued by an authority that is not trusted.
curl -k $A → salom, TLSv1.3
curl --cacert tls/sert.pem $A → salom, TLSv1.3
fetch (sertifikat ishonchsiz) → fetch failed; cause: DEPTH_ZERO_SELF_SIGNED_CERT

O'qib chiqamiz:

  1. curl exit 60 — "sertifikat zanjirini ishonchsiz markaz bergan". Windows'dagi curl Schannel (Windows'ning o'z TLS kutubxonasi) bilan qurilgan, xabar shundan.
  2. curl -k — "tekshirma" (--insecure). Shifrlash bor, lekin kim bilan gaplashayotganingiz noma'lum. Faqat lokal sinovda.
  3. curl --cacert sert.pem — "shu sertifikatga ishon". To'g'ri yo'l: tekshiruv o'chmaydi, faqat ishonch ro'yxatiga bitta yozuv qo'shiladi.
  4. fetch — fetch failed, sababi error.cause da (fetch darsi): DEPTH_ZERO_SELF_SIGNED_CERT — "zanjir chuqurligi nol, sertifikat o'zi imzolangan".

Node'da --cacert ning o'xshashi — NODE_EXTRA_CA_CERTS muhit o'zgaruvchisi. Biz ishga tushirdik: o'sha server, https://localhost:<port>/ ga fetch, avval o'zgaruvchisiz, keyin NODE_EXTRA_CA_CERTS=sert.pem bilan:

text
fetch failed ← DEPTH_ZERO_SELF_SIGNED_CERT
salom, TLSv1.3

Ikkinchi ishga tushirishda kod o'zgarmadi — faqat muhit o'zgaruvchisi qo'shildi.

Diqqat: Internetda NODE_TLS_REJECT_UNAUTHORIZED=0 maslahatini ko'p uchratasiz. U curl -k kabi butun jarayon uchun tekshiruvni o'chiradi — tashqi API'larga (to'lov tizimi, Telegram) ketadigan so'rovlar ham himoyasiz qoladi. Node buni ishga tushganda ogohlantirish bilan bildiradi. Hech qachon prodakshnda ishlatmang; lokalda ham NODE_EXTRA_CA_CERTS yaxshiroq.

3.3 mkcert: lokal ishonchli sertifikat

Har safar -k yoki --cacert yozish noqulay. mkcert — lokal ishlab chiqish uchun kichik dastur: o'z kompyuteringizda shaxsiy CA yaratadi va uni tizimning ishonch omboriga qo'shadi. Keyin u bergan sertifikatlarga brauzer ham ishonadi. Hujjatdagi oqim:

bash
mkcert -install                    # lokal CA, tizim omboriga
mkcert localhost 127.0.0.1         # localhost+1.pem va kalit

Node tizim omborini sukut bo'yicha o'qimaydi. Ikki yo'l bor: NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem" yoki Node 24 dagi --use-system-ca bayrog'i (node --help da: "use system's CA store"). Biz mkcert'ni o'rnatmadik — bu oqim rasmiy README bo'yicha. Dev server proxy va HTTPS darsida Vite uchun xuddi shu muammoni ko'rgansiz.

Diqqat: mkcert -install yaratgan rootCA-key.pem — sizning kompyuteringizdagi har qanday sayt uchun "ishonchli" sertifikat chiqara oladigan kalit. Uni hech kimga bermang va serverga ko'chirmang. mkcert — faqat lokal uchun.

4. Haqiqiy domen: Let's Encrypt va TLS termination

4.1 Let's Encrypt

Internetdagi domen uchun sertifikatni ishonchli CA berishi kerak. Let's Encrypt — bepul, avtomatik CA. U ACME protokoli bilan ishlaydi: dastur (masalan certbot yoki Caddy) "bu domen meniki" ekanini isbotlaydi. Odatda domendagi maxsus manzilga fayl qo'yib yoki DNS yozuvi qo'shib. Sertifikat qisqa muddatli va avtomatik yangilanadi. Let's Encrypt e'loniga ko'ra (2025-12-02), 2026-10 holatida sukut muddat hali 90 kun. 45 kunlik sertifikat esa ixtiyoriy profil bilan beriladi. Reja bo'yicha sukut 2027-02 da 64 kunga, 2028-02 da 45 kunga qisqaradi. Qisqa muddat ataylab: kalit o'g'irlansa, zarar uzoq davom etmaydi. Shuning uchun yangilash albatta avtomatik bo'lishi kerak — qo'lda yangilash unutiladi.

Bularning hammasini Node ichida qilish mumkin (ACME kutubxonalari bor), lekin kamdan-kam qilinadi. Sabab — keyingi bo'lim.

4.2 TLS termination

flowchart LR
  B["Brauzer"] -- "HTTPS :443" --> P["nginx / Caddy<br/>sertifikat, kalit"]
  P -- "HTTP :3000<br/>127.0.0.1" --> N1["Node 1"]
  P -- "HTTP :3001" --> N2["Node 2"]

TLS termination (TLS'ni tugatish) — shifrlangan ulanish proxy'da tugaydi. Proxy sertifikatni ko'rsatadi, so'rovni ochadi va ichki tarmoqda oddiy HTTP bilan Node'ga uzatadi. Node faqat 127.0.0.1 da tinglaydi — tashqaridan unga to'g'ridan yetib bo'lmaydi.

Nega shunday:

Masala TLS Node'da TLS proxy'da
Sertifikat yangilash har ilova o'zi, qayta ishga tushirish bitta joyda, avtomatik (Caddy, certbot)
Bir nechta Node jarayoni har biriga kalit kalit faqat proxy'da
Shifrlash narxi Node CPU'si proxy (C'da yozilgan, tez)
HTTP/2, HTTP/3, siqish o'zingiz proxy sozlamasi

Kanonda ham shu qaror: vazifalar-api da TLS yo'q, u 127.0.0.1 da HTTP tinglaydi. HTTPS — deploy qismida VPS'dagi reverse proxy'ning ishi (33-qism). Let's Encrypt va haqiqiy domen kanonda sinalmagan — mashinada domen yo'q.

Node'da TLS qachon kerak? Proxy'siz kichik ichki xizmat, ikki server orasida o'zaro sertifikat bilan tanishish (mTLS — mutual TLS, ikki tomon ham sertifikat ko'rsatadi) yoki proxy bilan Node orasida ham shifrlash talab qilinganda.

Tekshirib ko'ring: vazifalar-api nginx ortida, TLS nginx'da tugaydi. Node'dagi req.socket.encrypted nima bo'ladi va foydalanuvchi HTTPS ishlatganini Node qanday biladi?

Javob

req.socket.encrypted — undefined: nginx bilan Node orasidagi ulanish oddiy HTTP. Foydalanuvchi protokolini Node faqat proxy qo'shgan sarlavhadan biladi: X-Forwarded-Proto: https. Bu sarlavhaga qachon ishonish mumkinligi — keyingi darsdan keyingi dars mavzusi.

5. HTTP/2 va ALPN

5.1 HTTP/1.1 ning muammosi

HTTP versiyalari darsida ko'rgansiz: HTTP/1.1 da bitta ulanishda so'rovlar navbat bilan ketadi — birinchi javob tugamaguncha ikkinchisi kutadi. Brauzer bunga qarshi bitta saytga bir nechta (odatda 6 tagacha) ulanish ochadi. HTTP/2 esa bitta ulanishda ko'p so'rovni parallel yuboradi — bu multiplexing (ko'p oqimni bitta kanalda aralashtirish). Har so'rov — alohida stream (oqim, raqamli), javob bo'laklari aralashib keladi va qabul qiluvchida qayta yig'iladi.

Quyidagi toza funksiya vaqtni taxminan hisoblaydi (tarmoq kechikishisiz, faqat navbat):

js
// n ta so'rov, har biri ms; k ta ulanish; har ulanishda bittadan
function navbatVaqti(n, ms, k) {
  return Math.ceil(n / k) * ms;
}

console.log("HTTP/1.1, 1 ulanish:", navbatVaqti(10, 100, 1), "ms");
console.log("HTTP/1.1, 6 ulanish:", navbatVaqti(10, 100, 6), "ms");
console.log("HTTP/2, 10 oqim:", navbatVaqti(10, 100, 10), "ms");

Konsolda:

text
HTTP/1.1, 1 ulanish: 1000 ms
HTTP/1.1, 6 ulanish: 200 ms
HTTP/2, 10 oqim: 100 ms

Bu nazariya. Endi o'lchov.

5.2 ALPN: qaysi protokolda gaplashamiz

Mijoz HTTP/2 ni bilishini server qayerdan biladi? TLS kelishuvi paytida mijoz o'zi biladigan protokollar ro'yxatini yuboradi: ["h2", "http/1.1"]. Server bittasini tanlaydi. Bu kengaytma — ALPN (Application-Layer Protocol Negotiation, "ilova protokolini kelishish"), RFC 7301. Qo'shimcha so'rov yo'q — tanlov TLS kelishuvining ichida.

Shuning uchun brauzerlar HTTP/2 ni faqat TLS ustida ishlatadi: ALPN TLS'ning bir qismi. Standart shifrlanmagan HTTP/2 (h2c) ni ham ta'riflaydi, lekin brauzerlar uni qo'llamaydi.

5.3 node:http2 — kanon o'lchovi

Kanon http2.createSecureServer({ key, cert, allowHTTP1: true }) serverini ochdi. Ishlovchi har so'rovga 100 ms dan keyin javob beradi. allowHTTP1 — HTTP/2 ni bilmaydigan mijozlar uchun 1.1 ga qaytish. Natija (Node 24.21.0). Ikkinchi qatordagi ikki raqamga qarang — vaqt (133 ms) va ulanishlar soni (1):

text
ALPN kelishuvi: h2, TLS TLSv1.3, shifr TLS_AES_256_GCM_SHA384
HTTP/2: 10 parallel so'rov (har biri 100 ms) — 133 ms, TCP ulanishlar 1; birinchi javob {"versiya":"2.0","yol":"/v/0"}
curl (HTTP/2'siz qurilgan, Schannel) → {"versiya":"1.1","yol":"/eski"}

Uchta fakt:

  1. tls.connect mijoz ALPNProtocols: ["h2", "http/1.1"] yubordi — server h2 ni tanladi.
  2. 10 so'rov bitta TCP ulanishda, jami 133 ms — nazariyadagi 100 ms ga yaqin. Qolgan 33 ms — ulanish ochish va TLS kelishuvi.
  3. Mashinadagi curl HTTP/2 ni qo'llamaydi (curl --version dagi Features ro'yxatida yo'q). U http/1.1 ni taklif qildi va server allowHTTP1 tufayli 1.1 da javob berdi. req.httpVersion — "1.1".

Mijoz kodi Node'ning http2.connect i bilan yozildi (kanon, qisqartirilgan):

js
const sessiya = http2.connect(manzil, { ca: cert });
const oqim = sessiya.request({ ":path": "/v/0" });
oqim.on("data", (bolak) => (tana += bolak));
oqim.on("end", () => console.log(tana));

:path — HTTP/2 dagi soxta sarlavha (pseudo-header). HTTP/1.1 ning so'rov qatori (GET /v/0 HTTP/1.1) HTTP/2 da :method, :path, :scheme, :authority sarlavhalariga aylangan. Sarlavhalar ham ikkilik formatda va siqilgan (HPACK) ketadi.

5.4 HTTP/2 Node'da kerakmi?

Odatda yo'q. Brauzer bilan proxy orasida HTTP/2 (yoki HTTP/3) bo'ladi, proxy bilan Node orasida esa oddiy HTTP/1.1 keep-alive yetadi. Express ham node:http2 bilan to'g'ridan ishlamaydi. HTTP/3 — UDP ustidagi QUIC protokolida ishlaydigan versiya (RFC 9114) — uni ham proxy yoki CDN beradi (Caddy uni sukut bo'yicha yoqadi). Kanonda HTTP/3 sinalmagan: curl ham, mashina ham buni qo'llamadi.

Tekshirib ko'ring: Ikki saytda 30 ta kichik rasm bor. Biri HTTP/1.1, ikkinchisi HTTP/2. Server javob vaqti bir xil. Qaysi sahifa tezroq yuklanadi va nega?

Javob

HTTP/2. HTTP/1.1 da brauzer ~6 ulanish ochadi va 30 rasm 5 "to'lqin"da keladi. HTTP/2 da hammasi bitta ulanishda parallel ketadi. Qo'shimcha foyda: bitta TLS kelishuvi va siqilgan sarlavhalar.

6. HTTP'dan HTTPS'ga yo'naltirish

HTTPS yoqilgach ham kimdir http:// bilan keladi. Odatiy yechim — 80-portda kichik server: har so'rovni https:// ga 308 (doimiy, metod va tana saqlanadi) bilan yo'naltiradi. 301 ham ishlatiladi, lekin u POST ni GET ga aylantirib yuborishi mumkin.

Tuzoq: yangi manzilni Host sarlavhasidan yasaysiz, Host esa mijozdan keladi. Tekshiruvsiz yozilgan yo'naltirish hujumchiga "sizning domeningizdan" istalgan saytga havola yasashga imkon beradi (open redirect). Biz ishga tushirdik:

js
import { createServer, request } from "node:http";

const RUXSAT = new Set(["api.example.com", "example.com"]);
const server = createServer((req, res) => {
  const host = (req.headers.host ?? "").split(":")[0].toLowerCase();
  if (!RUXSAT.has(host)) return res.writeHead(400).end();
  res.writeHead(308, { Location: `https://${host}${req.url}` });
  res.end();
});
await new Promise((ok) => server.listen(0, "127.0.0.1", ok));
const port = server.address().port;

function sor(host, path) {
  return new Promise((ok, rad) => {
    const opts = { port, host: "127.0.0.1", path, headers: { host } };
    request(opts, (res) => {
      res.resume();
      ok(`${res.statusCode} ${res.headers.location ?? "-"}`);
    }).on("error", rad).end();
  });
}
console.log(await sor("api.example.com", "/vazifalar?bajarildi=1"));
console.log(await sor("Example.com:80", "/"));
console.log(await sor("yomon.example.net", "/kirish"));
server.closeAllConnections();
server.close();

Konsolda:

text
308 https://api.example.com/vazifalar?bajarildi=1
308 https://example.com/
400 -

fetch emas, node:http ning request i ishlatildi: fetch Host sarlavhasini o'zgartirishga ruxsat bermaydi (u taqiqlangan sarlavha). Port qismini (:80) tashlab, harfni kichraytirdik. Ro'yxatda yo'q host — 400.

Brauzerga "bu saytga faqat HTTPS bilan kel" deb eslab qolishni aytadigan sarlavha ham bor — HSTS (Strict-Transport-Security: max-age=…). U faqat HTTPS javobida ma'noga ega. Mashhur middleware'lar darsida helmet uni o'zi qo'yadi.

7. Hujumchi nigohi

Hujum Qanday Himoya
Wi-Fi'da tinglash HTTP trafikini o'qish HTTPS hamma joyda; HSTS
MITM o'z sertifikati bilan mijoz tekshiruvni o'chirgan (-k, NODE_TLS_REJECT_UNAUTHORIZED=0) tekshiruvni o'chirmang; NODE_EXTRA_CA_CERTS
Kalit o'g'irlash Git'dagi kalit.pem, serverdagi ochiq ruxsatlar kalit Git'da yo'q, faqat proxy'da, chmod 600
SSL stripping birinchi HTTP so'rovni ushlab, HTTPS'ga o'tkazmaslik 308 yo'naltirish + HSTS
Open redirect Host: yomon.example.net Host oq ro'yxati

MITM (man-in-the-middle, "o'rtadagi odam") — net va tls darsida ko'rgansiz: mijoz bilan server orasiga kirib, ikkalasiga ham o'zini boshqasi deb tanishtirish. Sertifikat tekshiruvi aynan shunga qarshi. Uni o'chirgan kod — eshikni ochiq qoldirgan qulf.

8. API qadami: o'zgarish yo'q (tajriba)

Bu dars uchun vazifalar-api da yangi holat yo'q. Kanon tajribasi va qarori:

  • TLS, HTTP/2 va ALPN alohida tajribada o'lchandi (yuqoridagi barcha chiqishlar). Kalit Git'ga tushmadi.
  • Qaror: vazifalar-api HTTPS'ni o'zi qilmaydi. U HOST=127.0.0.1 da HTTP tinglaydi; TLS — proxy'da (33-qism, VPS). Sabab — «TLS termination» bo'limidagi jadval: bitta joyda sertifikat, avtomatik yangilanish, Node CPU'si tejaladi.
  • Let's Encrypt, haqiqiy domen va HTTP/3 — sinalmagan.

Bugun loyihaga commit yo'q. Holat 05 dan keyingi o'zgarish server timeout'lari darsida bo'ladi.

9. Ko'p uchraydigan xatolar

Xato Sabab Davosi
DEPTH_ZERO_SELF_SIGNED_CERT o'z-o'zidan imzolangan sertifikat NODE_EXTRA_CA_CERTS yoki mkcert
UNABLE_TO_VERIFY_LEAF_SIGNATURE serverda oraliq sertifikat yo'q to'liq zanjir (fullchain.pem)
ERR_TLS_CERT_ALTNAME_INVALID domen SAN'da yo'q to'g'ri domen bilan sertifikat
CERT_HAS_EXPIRED muddat o'tgan avtomatik yangilash
curl: (60) curl CA'ni tanimaydi --cacert, -k faqat lokal
EACCES 443-portda Linux'da 1024 dan past port root talab qiladi proxy 443 da, Node 3000 da

UNABLE_TO_VERIFY_LEAF_SIGNATURE — "oxirgi (barg) sertifikat imzosini tekshirib bo'lmadi". Ko'pincha serverga faqat o'z sertifikati qo'yilgan, uni CA bilan bog'laydigan oraliq sertifikat unutilgan. Brauzer ba'zan oraliqni o'zi topadi, Node esa topmaydi — "brauzerda ishlaydi, Node'da yo'q" muammosining klassik sababi.

10. Mashqlar

Yechimlar kurs/mashqlar/25/06-tls/ da.

1-mashq (oson): to'ldiring

  • Sertifikat qaysi domenlar uchun ekanini aytadigan maydon —
  • TLS ichida HTTP/2 ni kelishadigan kengaytma —
  • O'z-o'zidan imzolangan sertifikatga Node ishonishi uchun muhit o'zgaruvchisi — NODE_EXTRA_
  • Shifrlangan ulanish proxy'da tugashi — TLS
  • HTTP/2 ning bitta ulanishda ko'p so'rov yuborishi —
Yechim
  • SAN (subjectAltName) — DNS:localhost, IP Address:127.0.0.1.
  • ALPN — mijoz ["h2", "http/1.1"] taklif qiladi, server tanlaydi.
  • CA_CERTS — NODE_EXTRA_CA_CERTS=sert.pem.
  • termination — nginx/Caddy sertifikatni ko'rsatadi, Node'ga HTTP.
  • multiplexing — kanonda 10 so'rov, 1 TCP ulanish, 133 ms.

2-mashq (o'rta): sertifikat hisoboti

«Sertifikatni Node bilan o'qish» bo'limidagi PEM bilan sertHisoboti(pem) funksiyasini yozing. U { nomlar, kunlar, oziImzolagan } qaytarsin: nomlar — SAN'dagi qiymatlar massivi ("DNS:" va "IP Address:" prefikslarisiz), kunlar — validFromDate dan validToDate gacha butun kunlar soni, oziImzolagan — issuer === subject va imzo o'z kaliti bilan to'g'ri. Eslatma: split(", ") va replace(/^[^:]+:/, "") — satr metodlari.

Yechim
js
import { X509Certificate } from "node:crypto";

const pem = `-----BEGIN CERTIFICATE-----
MIIBmDCCAT6gAwIBAgITCU1qCZdn5AHpVRXMd4LOyjlGCTAKBggqhkjOPQQDAjAU
MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjYxMDI0MDY0MTI5WhcNMjYxMDI2MDY0
MTI5WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB
BwNCAAQJmRf8e3dnbERWm7W4AucwahvQc+zJVvvEap2xX2J1A8duXO4i6H1vgieq
tl/5LJM8/Jp1j0/0A+J69mAb+OvEo28wbTAdBgNVHQ4EFgQUNcct0DYDdKrC/5jW
b7wtq4ZrYrkwHwYDVR0jBBgwFoAUNcct0DYDdKrC/5jWb7wtq4ZrYrkwDwYDVR0T
AQH/BAUwAwEB/zAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwCgYIKoZIzj0E
AwIDSAAwRQIhAMFmuEl02uaFA4MJgtbZ9ETpVsIlwIbQ66SjDn9ENE3GAiBC3GTY
nDxp7Tlw59PK0ng6spfPaTpTliY79KPvqizEOw==
-----END CERTIFICATE-----`;

function sertHisoboti(matn) {
  const s = new X509Certificate(matn);
  const nomlar = (s.subjectAltName ?? "")
    .split(", ")
    .map((q) => q.replace(/^[^:]+:/, ""));
  const ms = s.validToDate - s.validFromDate;
  const kunlar = Math.floor(ms / 86_400_000);
  const oziImzolagan =
    s.issuer === s.subject && s.verify(s.publicKey);
  return { nomlar, kunlar, oziImzolagan };
}

console.log(sertHisoboti(pem));

Konsolda:

text
{ nomlar: [ 'localhost', '127.0.0.1' ], kunlar: 2, oziImzolagan: true }

Ikki Date ni ayirsangiz — millisekundlar farqi. Bir kunda 86 400 000 ms.

3-mashq (qiyin): ALPN tanlovi

ALPN qoidasi (RFC 7301): server o'z afzallik tartibida yuradi va mijoz ro'yxatida bor birinchi protokolni tanlaydi; umumiy protokol bo'lmasa — kelishuv xato bilan tugaydi. alpnTanla(server, mijoz) funksiyasini yozing: tanlangan nomni yoki null qaytarsin. To'rt holatni sinang: brauzer (h2, http/1.1), eski curl (http/1.1), HTTP/2'siz server, umumiy protokolsiz mijoz. Toza JS — saytda ham ishlaydi.

Yechim
js
function alpnTanla(server, mijoz) {
  return server.find((p) => mijoz.includes(p)) ?? null;
}

const yangi = ["h2", "http/1.1"];
const eski = ["http/1.1"];
console.log(alpnTanla(yangi, ["h2", "http/1.1"])); // h2
console.log(alpnTanla(yangi, ["http/1.1"])); // http/1.1
console.log(alpnTanla(eski, ["h2", "http/1.1"])); // http/1.1
console.log(alpnTanla(yangi, ["spdy/3"])); // null

Ikkinchi qator — kanondagi HTTP/2'siz curl holati: allowHTTP1 server 1.1 ga tushdi. Uchinchisi — server faqat 1.1 biladi, brauzer ham 1.1 da gaplashadi. Node'da allowHTTP1: false bo'lsa, server ro'yxati faqat ["h2"] va to'rtinchi holat kabi kelishuv uziladi.

11. Real ishda

  • Deploy'da — Caddy (avtomatik Let's Encrypt, HTTP/2 va HTTP/3) yoki nginx + certbot, Node esa 127.0.0.1 da. Bulut balansirlari (AWS ALB, Cloudflare) ham TLS'ni o'zi tugatadi.
  • Mikroservislar orasida — mTLS (servis mesh: Istio, Linkerd) — bu holda Node'ga sertifikat beriladi yoki uni yonidagi proxy qiladi.
  • Lokal — mkcert; Node uchun NODE_EXTRA_CA_CERTS yoki --use-system-ca.
  • Intervyu: "TLS termination nima?", "HTTP/2 multiplexing nima beradi?", "ALPN nima uchun kerak?", "NODE_TLS_REJECT_UNAUTHORIZED=0 nega xavfli?".

Xulosa

  • https.createServer({ key, cert }, ishlovchi) — http bilan bir xil, faqat TLS sozlamalari bilan; kalit — sir, sertifikat — ochiq.
  • O'z-o'zidan imzolangan sertifikatga ishonch: curl --cacert, NODE_EXTRA_CA_CERTS, mkcert. Tekshiruvni o'chirish (-k, REJECT_UNAUTHORIZED=0) — faqat lokal sinovda.
  • Prodakshnda TLS odatda proxy'da tugaydi (TLS termination); vazifalar-api 127.0.0.1 da HTTP.
  • HTTP/2 — multiplexing, ALPN orqali TLS ichida kelishiladi; kanonda 10 so'rov, 1 ulanish, 133 ms.
  • HTTP→HTTPS yo'naltirishda Host ni oq ro'yxat bilan tekshiring.

Keyingi dars: Server timeout'lari va keep-alive — keepAliveTimeout, headersTimeout, Slowloris hujumi va serverni to'g'ri to'xtatish.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
HTTPS Node.js'da: TLS sertifikati, https.createServer, HTTP/2 va ALPN — IlmHamroh