Բոլոր դասերը
Վեբի հիմունքներՄիջին10 րոպե ընթերցումԻմ ստեկում

HTTPS և TLS

Handshake, սերտիֆիկատներ, Let's Encrypt և HSTS՝ գործնական քայլերով։

  • TLS 1.3
  • Certificates
  • Let's Encrypt
  • HSTS
  • Origin certificates
Քայլ 1/5
Բրաուզերը ուզում է խոսել example.com-ի հետ։ Սրճարանի Wi-Fi-ում լրտես է ականջ դնում։ Դասական։

30 վայրկյանում

HTTPS-ը HTTP է, որն ուղարկվում է TLS-ի ներսում՝ գաղտնագրված և նույնականացված թունելով։ TLS-ը երաշխավորում է, որ ոչ ոք չի կարող կարդալ կամ փոխել թրաֆիկը, իսկ սերտիֆիկատն ապացուցում է, որ դուք իսկապես խոսում եք example.com-ի հետ։ Let's Encrypt-ի շնորհիվ սերտիֆիկատներն անվճար են և ավտոմատ թարմացվում են, ուստի յուրաքանչյուր կայք պետք է լինի միայն HTTPS։

Ինչու եմ օգտագործում

  • Ամենուր աշխատեցնում եմ HTTPS՝ ավտոմատ թարմացվող Let's Encrypt սերտիֆիկատներով․ դա յուրաքանչյուր սերվերի իմ անվտանգության բազային մակարդակի մասն է։
  • Իմ պրոդուկտներում login-ները, վճարումները և անձնական տվյալները երբեք չպետք է փոխանցվեն պարզ տեքստով։
  • Բրաուզերները HTTP էջերը նշում են որպես not secure, և շատ ժամանակակից հնարավորություններ (service worker-ներ, geolocation, HTTP/2 բրաուզերներում) պահանջում են HTTPS։
  • Սերտիֆիկատների խնդիրները կայքերն ակնթարթորեն անջատում են, ուստի դրանք հասկանալը խնայում է սթրեսային ժամեր։

Ինչպես է աշխատում

01Ինչ է տալիս TLS-ը

TLS-ը (Transport Layer Security, SSL-ի իրավահաջորդը) տալիս է երեք բան։ Գաղտնիություն՝ թրաֆիկը գաղտնագրված է, ուստի նույն Wi-Fi-ում գտնվողը տեսնում է միայն անիմաստ նշաններ։ Ամբողջականություն՝ ճանապարհին ցանկացած փոփոխություն հայտնաբերվում է։ Նույնականացում՝ սերվերն ապացուցում է իր ինքնությունը վստահելի կենտրոնի կողմից ստորագրված սերտիֆիկատով։ Անալոգիա՝ կնքված, բացումը ցույց տվող ծրար, որը հասցնում է սուրհանդակը, ով ստուգել է ստացողի անձնագիրը։ TLS 1.3-ը (RFC 8446) ընթացիկ տարբերակն է, իսկ TLS 1.2-ը դեռ ընդունելի է․ SSL 3.0-ն, TLS 1.0-ն և TLS 1.1-ը deprecated են և պետք է անջատվեն։ Նկատեք, որ HTTPS-ը թաքցնում է path-երը, header-ները և body-ները, բայց դոմենի անունը դեռ տեսանելի է DNS-ի և SNI դաշտի միջոցով, եթե չի օգտագործվում Encrypted Client Hello։

02TLS 1.3 handshake-ը

Handshake-ը տևում է մեկ round trip։ Բրաուզերն ուղարկում է ClientHello՝ աջակցվող cipher suite-ներ, պատահական արժեք, hostname (SNI), աջակցվող պրոտոկոլներ (ALPN, օրինակ՝ h2) և key share՝ իր կեսը ephemeral Diffie-Hellman փոխանակման մեջ (սովորաբար X25519, իսկ ընթացիկ բրաուզերներում հաճախ հիբրիդ post-quantum ML-KEM-ի հետ)։ Սերվերը պատասխանում է ServerHello-ով և իր key share-ով․ այժմ երկու կողմերն էլ հաշվում են նույն գաղտնիքը՝ առանց այն երբևէ ուղարկելու։ Դրանից հետո ամեն ինչ գաղտնագրված է․ սերվերն ուղարկում է իր սերտիֆիկատների շղթան, CertificateVerify ստորագրություն, որն ապացուցում է, որ նա տիրապետում է private key-ին, և Finished։ Բրաուզերը ստուգում է սերտիֆիկատը և ուղարկում իր Finished-ը՝ առաջին HTTP հարցման հետ միասին։ Քանի որ բանալիները ephemeral են, գողացված սերվերային բանալին չի կարող վերծանել անցյալի թրաֆիկը (forward secrecy)։ Վերսկսված session-ները կարող են նույնիսկ տվյալներ ուղարկել անմիջապես (0-RTT)՝ replay-ի ռիսկերով։

bash
# See the negotiated version, cipher and certificate chain
openssl s_client -connect example.com:443 -servername example.com -brief </dev/null
# Only accept TLS 1.3 to test support
openssl s_client -connect example.com:443 -servername example.com -tls1_3 </dev/null

03Սերտիֆիկատներ և վստահության շղթան

Սերտիֆիկատը public key-ը կապում է մեկ կամ մի քանի hostname-ի (Subject Alternative Name դաշտում) սահմանափակ ժամանակով և ստորագրված է Certificate Authority-ի (CA) կողմից։ Բրաուզերները և օպերացիոն համակարգերը գալիս են վստահելի root CA-ների ցանկով։ Root-երը հազվադեպ են ուղղակիորեն ստորագրում կայքերի սերտիֆիկատները․ նրանք ստորագրում են intermediate CA-ներ, որոնք էլ ստորագրում են ձեր leaf սերտիֆիկատը։ Այնպես որ ձեր սերվերը պետք է ուղարկի leaf-ը գումարած intermediate-ները (full chain), իսկ բրաուզերը կառուցում է ճանապարհը մինչև իր վստահած root-ը։ Վալիդացիայի տեսակներ՝ DV (domain validated, ավտոմատ, այն, ինչ օգտագործում են գրեթե բոլորը), OV և EV (կազմակերպության ստուգումներ, այսօր բրաուզերներում տեսանելի առավելություն չունեն)։ Wildcard-ները (*.example.com) ծածկում են subdomain-ների մեկ մակարդակ։ Բոլոր հանրային սերտիֆիկատները գրանցվում են Certificate Transparency լոգերում, ուստի կարող եք տեսնել ձեր դոմենի համար թողարկված յուրաքանչյուր սերտիֆիկատ։ Կյանքի տևողությունները կրճատվում են․ ոլորտի առավելագույնը 2026-ին իջնում է 200 օրի և 2029-ին հասնում 47 օրի, ուստի ավտոմատացումը պարտադիր է։

04Let's Encrypt certbot-ով

Let's Encrypt-ն անվճար, ավտոմատացված CA է, որն օգտագործում է ACME պրոտոկոլը։ certbot-ն ապացուցում է, որ դուք վերահսկում եք դոմենը, սովորաբար HTTP-01 challenge-ով (այն token է մատուցում /.well-known/acme-challenge/-ում 80 պորտով) կամ DNS-01-ով (TXT գրառում, պարտադիր է wildcard-ների համար)։ Տեղադրեք այն, nginx plugin-ով սերտիֆիկատ պահանջեք, և այն ձեր փոխարեն կխմբագրի nginx կոնֆիգը։ Փաթեթները տեղադրում են systemd timer, որն օրական երկու անգամ փորձում է թարմացնել և թարմացնում է, երբ սերտիֆիկատի ժամկետը մոտենում է ավարտին։ Միշտ ստուգեք թարմացումը --dry-run-ով և ավելացրեք deploy hook, որպեսզի nginx-ը reload լինի նոր սերտիֆիկատով։ Let's Encrypt-ի սերտիֆիկատներն այսօր լռելյայն 90 օրյա են, ավելի կարճ 45 օրյա տարբերակներն արդեն հասանելի են, իսկ լռելյայնը 2027-ին անցնում է 64 օրի և 2028-ին՝ 45 օրի, ուստի երբեք մի հենվեք ձեռքով թարմացման վրա։

bash
sudo apt update && sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
# Renewal is automatic; verify the timer and do a test run
systemctl list-timers | grep certbot
sudo certbot renew --dry-run
# Reload nginx after each successful renewal
sudo certbot renew --deploy-hook "systemctl reload nginx" --dry-run
sudo certbot certificates

05Լավ nginx TLS կոնֆիգ և HSTS

Ամբողջ HTTP-ն redirect արեք HTTPS-ի, թույլատրեք միայն TLS 1.2 և 1.3, և թողեք, որ ժամանակակից լռելյայն արժեքներն ընտրեն cipher-ները։ Mozilla-ի SSL Configuration Generator-ը յուրաքանչյուր սերվերի համար տալիս է արդիական կարգավորումներ։ HSTS-ը (Strict-Transport-Security) բրաուզերներին ասում է ձեր դոմենի համար max-age վայրկյանի ընթացքում օգտագործել միայն HTTPS, նույնիսկ եթե ինչ-որ մեկը մուտքագրում է http:// կամ սեղմում հին հղման վրա․ դա արգելափակում է SSL-stripping հարձակումները։ Ներդրեք այն զգուշորեն՝ սկսեք կարճ max-age-ից, includeSubDomains ավելացրեք միայն այն ժամանակ, երբ յուրաքանչյուր subdomain ունի HTTPS, և բրաուզերների preload ցանկին (preload flag-ով) դիմեք միայն երբ վստահ եք, որովհետև հեռացումը ամիսներ է տևում։ Եթե Cloudflare-ի հետևում եք Full (strict)-ով, origin-ի նույն սերտիֆիկատը ծածկում է երկրորդ hop-ը։

nginx
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}
server {
    listen 443 ssl;
    http2 on;
    server_name example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_cache shared:SSL:10m;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

06SSL-ի տարածված սխալները և ինչպես դրանք շտկել

NET::ERR_CERT_DATE_INVALID կամ «certificate has expired»՝ թարմացումը ձախողվել է․ ստուգեք certbot-ի լոգերը, timer-ը և որ 80 պորտը հասանելի է HTTP-01-ի համար։ ERR_CERT_COMMON_NAME_INVALID՝ սերտիֆիկատը չի ծածկում այս hostname-ը, հաճախ www-ն բացակայում է․ վերաթողարկեք բոլոր անուններով։ «unable to get local issuer certificate» curl-ում, Android-ում կամ Node client-ներում, մինչդեռ բրաուզերներն աշխատում են՝ սերվերն ուղարկում է միայն leaf-ը, ոչ թե շղթան․ օգտագործեք fullchain.pem։ ERR_SSL_VERSION_OR_CIPHER_MISMATCH՝ միայն հին պրոտոկոլներ, կամ այս SNI անվան համար սերտիֆիկատ չկա։ Mixed content՝ HTTPS էջը բեռնում է http:// սկրիպտներ կամ պատկերներ․ շտկեք URL-ները կամ CSP-ում ավելացրեք upgrade-insecure-requests։ HSTS սխալներ, որոնք հնարավոր չէ շրջանցել՝ HSTS-ով դոմենի վրա սերտիֆիկատն անվավեր է․ շտկեք սերտիֆիկատը։ Cloudflare-ի հետևում 525-ն ու 526-ը այս խնդիրների origin-ի կողմի տարբերակներն են։

bash
# Expiry dates and names covered
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -dates -subject -ext subjectAltName
sudo journalctl -u certbot --since "7 days ago"
sudo nginx -t && sudo systemctl reload nginx

Օգտագործեք, երբ

  • Յուրաքանչյուր հանրային կայք, API և ադմին պանել՝ առանց բացառության։
  • Ներքին ծառայություններ, որոնք փոխանցում են credentials կամ անձնական տվյալներ, նույնիսկ մասնավոր ցանցերում։
  • CDN-ի և ձեր origin-ի միջև (Full (strict) ռեժիմ)։

Մի՛ օգտագործեք, երբ

  • Մի ավարտեք TLS-ը հավելվածի կոդում, երբ nginx-ը կամ load balancer-ը կարող է դա անել ավելի պարզ։
  • Հանրային կայքերի համար մի օգտագործեք self-signed սերտիֆիկատներ․ օգտագործեք Let's Encrypt կամ origin սերտիֆիկատ CDN-ի հետևում։

Այլընտրանքներ

  • Cloudflare Origin CA

    Անվճար, երկարաժամկետ սերտիֆիկատներ, որոնց վստահում է միայն Cloudflare-ը, edge-ից origin hop-ի համար։

  • Caddy

    Վեբ սերվեր, որը սերտիֆիկատներն ավտոմատ ստանում և թարմացնում է՝ առանց լրացուցիչ գործիքների։

  • acme.sh / lego

    Թեթև ACME client-ներ, հարմար են DNS-01-ի և ոչ սովորական կարգավորումների համար։

  • Managed սերտիֆիկատներ

    AWS ACM-ը, load balancer-ները և PaaS պլատֆորմները ձեր փոխարեն կառավարում են թողարկումն ու թարմացումը։

Լավագույն պրակտիկաներ

  1. Ավտոմատացրեք թողարկումն ու թարմացումը, ստուգեք --dry-run-ով և հետևեք ժամկետներին։
  2. Մատուցեք ամբողջական շղթան (fullchain.pem), ոչ միայն leaf սերտիֆիկատը։
  3. Միացրեք միայն TLS 1.2 և 1.3, հետևեք Mozilla-ի intermediate պրոֆիլին։
  4. HTTP-ն redirect արեք HTTPS-ի 301-ով և HSTS ավելացրեք բոլոր subdomain-ները ստուգելուց հետո։
  5. Պաշտպանեք private key-երը ֆայլերի խիստ իրավունքներով և երբեք commit մի արեք դրանք։
  6. Ավելացրեք CAA գրառում՝ նշելով այն CA-ները, որոնք իրականում օգտագործում եք։

Տարածված սխալներ

  • Թարմացնել ձեռքով և մոռանալ, այնպես որ կայքն անջատվում է ժամկետի ավարտի օրը։
  • Ամբողջությամբ արգելափակել 80 պորտը, ինչը կոտրում է HTTP-01 թարմացումը։
  • Բացակայող intermediate սերտիֆիկատներ, այնպես որ որոշ client-ներ ձախողվում են, մինչդեռ desktop բրաուզերներն աշխատում են։
  • Միացնել HSTS preload-ը, նախքան յուրաքանչյուր subdomain կաջակցի HTTPS-ը։
  • Թողնել mixed-content http:// URL-ներ template-ներում և տվյալների բազայում։

Խորը վերլուծություն

07Revocation, և ինչու են կյանքի ժամկետները կրճատվում

Եթե private key-ը արտահոսում է, սերտիֆիկատին պետք է դադարեն վստահել դեռ ժամկետի ավարտից առաջ։ Երկու դասական գործիքներն էլ խնդիրներ ունեն։ CRL-ները revoke արված serial համարների ցուցակներ են, որոնք կարող են մեծանալ։ OCSP-ն թույլ է տալիս client-ին CA-ին հարցնել մեկ սերտիֆիկատի մասին, բայց այն CA-ին բացահայտում է, թե որ կայքերն է այցելում օգտատերը, ավելացնում է latency, իսկ բրաուզերները soft-fail են անում, երբ responder-ն անհասանելի է, ուստի այն արգելափակող հարձակվողը հաղթում է։ OCSP stapling-ը, որտեղ սերվերը կցում է ստորագրված status, ուղղեց դրա մի մասը։ Let's Encrypt-ը 2025-ին փակեց իր OCSP ծառայությունը և այժմ հրապարակում է միայն CRL-ներ, իսկ բրաուզերները client-ներին ուղարկում են CRL-ներից կառուցված կոմպակտ revocation հավաքածուներ։ Արդյունաբերության հիմնական պատասխանը, սակայն, կարճ ժամկետներն են. 47-օրյա սերտիֆիկատի գողացված key-ը օգտակար է շաբաթներ, ոչ թե մեկ տարի։ Ահա առավելագույն վավերականության կրճատման իրական պատճառը։

08Key-երի տեսակներ, cipher suite-եր և post-quantum key exchange

Ձեր սերտիֆիկատի key-ը կամ RSA է (2048 բիթը սովորական նվազագույնն է), կամ ECDSA (P-256)։ ECDSA key-երը ավելի փոքր են, իսկ ստորագրություններն ավելի արագ, ինչը կրճատում է handshake-ները. RSA-ն ամենալայն աջակցությունն ունի շատ հին client-ների մեջ։ nginx-ը կարող է մատուցել երկուսն էլ միաժամանակ և ընտրել ըստ client-ի։ TLS 1.3-ում ընդամենը մի քանի cipher suite կա, բոլորը AEAD (AES-GCM, ChaCha20-Poly1305), և լռելյայն դրանք լավն են։ TLS 1.2-ի համար հետևեք Mozilla-ի intermediate պրոֆիլին, որը պահում է միայն ECDHE key exchange-ը AEAD cipher-ներով։ Key exchange-ը անցնում է post-quantum hybrid-ների. X25519MLKEM768-ը համատեղում է դասական X25519-ը ML-KEM-ի հետ, ուստի գրանցված տրաֆիկը մնում է անվտանգ նույնիսկ ապագա քվանտային համակարգիչների դեմ։ Ընթացիկ բրաուզերներն այն առաջարկում են. nginx-ում այն պահանջում է OpenSSL 3.5 կամ ավելի նոր, իսկ հին OpenSSL-ի վրա խումբը նշելը nginx-ին թույլ չի տալիս գործարկվել։

nginx
# Dual certificates: modern clients get ECDSA, older ones RSA
ssl_certificate     /etc/letsencrypt/live/example.com-ecdsa/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com-ecdsa/privkey.pem;
ssl_certificate     /etc/letsencrypt/live/example.com-rsa/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com-rsa/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
# Only with OpenSSL 3.5+:
# ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1;

09ACME մանրամասն. challenge-ներ, ARI և rate limit-ներ

ACME client-ը ստեղծում է account key, պատվեր է տալիս անունների հավաքածուի համար, յուրաքանչյուր անվան համար անցնում է մեկ challenge, ուղարկում է certificate signing request և ներբեռնում սերտիֆիկատը։ HTTP-01-ը պահանջում է, որ port 80-ը հասանելի լինի յուրաքանչյուր սերվերում, որը պատասխանում է այդ անվան համար, ուստի load balancer-ի հետևում token-ը պետք է մատուցեն բոլոր node-երը, այլապես validation-ը պատահականորեն ձախողվում է։ DNS-01-ը աշխատում է wildcard-ների և private սերվերների համար, բայց DNS-ը խմբագրող API token-ը հզոր է, ուստի սահմանափակեք այն մեկ zone-ով կամ _acme-challenge-ը delegate արեք առանձին zone-ի։ TLS-ALPN-01-ը validation է անում port 443-ում։ ACME Renewal Information-ը (ARI, RFC 9773) թույլ է տալիս CA-ին client-ներին ասել, թե երբ թարմացնել, օրինակ՝ ավելի շուտ զանգվածային revocation-ի ժամանակ. certbot-ը այն աջակցում է 4.1 տարբերակից։ Let's Encrypt-ը նաև կիրառում է rate limit-ներ, օրինակ՝ շաբաթական սահմանաչափ մեկ registered domain-ի սերտիֆիկատների և կրկնօրինակների համար, ուստի թեստավորեք staging միջավայրում։

bash
# Practise against staging first (no rate-limit pain)
sudo certbot certonly --nginx --staging -d example.com -d www.example.com
# Wildcard via DNS-01 with a DNS plugin and a zone-scoped token
sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
  -d example.com -d "*.example.com"
# ECDSA key (the default for new certbot certificates)
sudo certbot certonly --nginx --key-type ecdsa -d example.com

10Հրապարակային վեբից այն կողմ. mTLS, ներքին PKI և ECH

TLS-ը կարող է նույնականացնել երկու կողմերին էլ։ Mutual TLS-ում (mTLS) client-ը նույնպես ներկայացնում է սերտիֆիկատ, որը սերվերը ստուգում է իր վստահած CA-ի դեմ։ Սա տարածված է ծառայությունների միջև, գործընկերների API-ների և CDN-ից origin կապերի համար։ Service mesh-երը ավտոմատ թողարկում և rotate են անում այս սերտիֆիկատները։ Ներքին ծառայությունների համար կարող եք աշխատեցնել private CA (օրինակ՝ step-ca-ով կամ cloud private CA-ով), բայց այդ դեպքում յուրաքանչյուր client պետք է վստահի այդ root-ին, և rotation-ը ու revocation-ը ձեր պատասխանատվությունն են. հրապարակային անունների համար հրապարակային CA-ն ACME-ով ավելի պարզ է։ Encrypted Client Hello-ն (ECH) թաքցնում է SNI hostname-ը ցանցային դիտորդներից՝ ClientHello-ն գաղտնագրելով HTTPS DNS record-ում հրապարակված key-ով։ Խոշոր բրաուզերներն ու CDN-ները աջակցում են այն, ուստի proxied կայքերի համար այն հաճախ աշխատում է առանց ձեր սերվերում որևէ փոփոխության։

nginx
# nginx: require a client certificate from your internal CA
ssl_client_certificate /etc/ssl/internal/ca.pem;
ssl_verify_client on;
ssl_verify_depth 2;
# Test with a client certificate
# curl --cert client.pem --key client.key https://api.internal.example.com/health

Իրական իրավիճակներ

01

Սերտիֆիկատների ժամկետն անցավ հանգստյան օրերին

Խնդիր

Երկուշաբթի օրը կայքը ցույց է տալիս NET::ERR_CERT_DATE_INVALID։ certbot-ը տեղադրվել էր ամիսներ առաջ, և թարմացումները նախկինում աշխատում էին։

Ինչպես լուծել

Աշխատեցրեք sudo certbot renew --dry-run և կարդացեք սխալը։ Տարածված պատճառներ. firewall-ի փոփոխության ժամանակ port 80-ը փակվել է, HTTP-ից HTTPS redirect-ը կամ auth կանոնը արգելափակում է /.well-known/acme-challenge/-ը, DNS-ը հիմա մատնացույց է անում CDN կամ նոր սերվեր, կամ timer-ն անջատված է։ Ստուգեք systemctl list-timers-ը և journalctl -u certbot-ը։ Ուղղեք պատճառը, աշխատեցրեք certbot renew, reload արեք nginx-ը և հաստատեք նոր ամսաթվերը openssl x509 -noout -dates-ով։ Հետո ավելացրեք արտաքին expiry մոնիթորինգ, որը զգուշացնում է 14 օր առաջ, և deploy hook, որը յուրաքանչյուր թարմացումից հետո reload է անում nginx-ը։

02

Private key-ը commit է արվել repository

Խնդիր

Developer-ը սխալմամբ privkey.pem-ը push է արել ընդհանուր Git repository։ Repository-ն private է, բայց մի քանի կապալառու մուտք ունի։

Ինչպես լուծել

Key-ը համարեք compromised։ Անմիջապես թողարկեք սերտիֆիկատ նոր key-ով, օրինակ՝ sudo certbot renew --cert-name example.com --force-renewal --new-key, և reload արեք nginx-ը։ Revoke արեք հին սերտիֆիկատը certbot revoke --cert-path-ով՝ մատնացույց անելով դրան, որպես պատճառ նշելով keyCompromise։ Ֆայլը հեռացրեք repository-ի պատմությունից history-rewriting գործիքով և rotate արեք նույն commit-ի մյուս բոլոր secret-ները։ Սերտիֆիկատների directory-ն ավելացրեք .gitignore-ում և secret-scanning hook դրեք, որպեսզի դա այլևս չկրկնվի։

03

Android հավելվածը չի կարողանում միանալ, բրաուզերները կարողանում են

Խնդիր

Նոր սերվեր տեղափոխվելուց հետո կայքն աշխատում է բոլոր բրաուզերներում, բայց մոբայլ հավելվածը և գործընկերոջ Java client-ը ձախողվում են certificate path սխալներով։

Ինչպես լուծել

Ամենայն հավանականությամբ, նոր nginx կոնֆիգում ssl_certificate-ը մատնացույց է անում cert.pem, ոչ թե fullchain.pem, ուստի intermediate-ը բացակայում է։ Բրաուզերները սա շտկում են քեշավորված intermediate-ներով կամ AIA fetching-ով. շատ հավելվածներ և Java client-ներ՝ ոչ։ Աշխատեցրեք openssl s_client -showcerts և հաստատեք, որ երևում են երկու սերտիֆիկատ։ Փոխեք fullchain.pem-ի, թեստավորեք nginx -t-ով, reload արեք և աշխատեցրեք SSL checker։ Եթե հավելվածը օգտագործում է certificate pinning, ստուգեք՝ արդյոք այն pin է անում փոխված key, և rotation-ից առաջ պլանավորեք pin-երի թարմացումը backup pin-երով։

Արագ ուղեցույց

Համաձայնեցված պրոտոկոլ և cipher
openssl s_client -connect example.com:443 -servername example.com -brief </dev/null
Ժամկետի ավարտը և անունները
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates -ext subjectAltName
Ցույց տալ ուղարկված ամբողջական chain-ը
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null
Ուսումնասիրել լոկալ սերտիֆիկատը
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -text | less
certbot-ի սերտիֆիկատների ցանկը
sudo certbot certificates
Թեստավորել թարմացումը
sudo certbot renew --dry-run
Անուն ավելացնել գոյություն ունեցող սերտիֆիկատին
sudo certbot --nginx --expand -d example.com -d www.example.com -d shop.example.com
HSTS header (թեստավորելուց հետո)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Ստուգել, որ key-ը համապատասխանում է սերտիֆիկատին
openssl x509 -noout -pubkey -in cert.pem | sha256sum; openssl pkey -pubout -in privkey.pem | sha256sum
Որոնել Certificate Transparency log-երում
https://crt.sh/?q=example.com

Իմ իրական նախագծերում

  • Իմ կառավարած սերվերներում օգտագործում եմ certbot-ով թողարկված Let's Encrypt սերտիֆիկատներ, իսկ HTTPS-ն ամենուր և ավտոմատ թարմացումն իմ բազային մակարդակի մասն են։
  • Իմ firewall-ի բազային մակարդակը բաց է պահում 80 և 443 պորտերը, այնպես որ HTTP-01 challenge-ները և HTTP-ից HTTPS redirect-ներն աշխատում են։
  • POS SaaS սերվերն օգտագործում է Docker Compose TLS override՝ nginx-ով որպես reverse proxy ծառայությունների առջև։

Հարցեր և պատասխաններ

Q1Ինչպե՞ս է աշխատում TLS 1.3 handshake-ը։

Client-ն ուղարկում է ClientHello՝ աջակցվող cipher-ներով, SNI-ում hostname-ով, ALPN պրոտոկոլներով և key share-ով ephemeral Diffie-Hellman փոխանակման համար։ Սերվերը պատասխանում է ServerHello-ով և իր key share-ով, և երկուսն էլ ստանում են նույն session key-երը։ Դրանից հետո ամեն ինչ գաղտնագրված է․ սերվերն ուղարկում է իր սերտիֆիկատների շղթան, ստորագրություն, որն ապացուցում է, որ նա ունի private key-ը, և Finished։ Client-ը վալիդացնում է շղթան և hostname-ը, ուղարկում է Finished և կարող է անմիջապես ուղարկել HTTP հարցումը։ Դա մեկ round trip է՝ TLS 1.2-ի երկուսի համեմատ։ Ephemeral բանալիները տալիս են forward secrecy, այնպես որ հետագա բանալու արտահոսքը չի կարող վերծանել ձայնագրված թրաֆիկը։

Q2Ի՞նչ է վստահության շղթան (chain of trust)։

Բրաուզերները և օպերացիոն համակարգերը վստահում են root CA սերտիֆիկատների փոքր հավաքածուի։ Root-երը ստորագրում են intermediate CA-ներ, իսկ intermediate-ները ստորագրում են կայքերի սերտիֆիկատները։ Երբ սերվերը ներկայացնում է իր leaf սերտիֆիկատը գումարած intermediate-ները, client-ը ստուգում է յուրաքանչյուր ստորագրություն շղթայով վերև, մինչև հասնի վստահելի root-ի, և ստուգում է վավերականության ժամկետները, hostname-ը Subject Alternative Name-ում և key usage-ը։ Եթե intermediate-ը բացակայում է, որոշ client-ներ կարող են այն ներբեռնել, իսկ մյուսները ձախողվում են, ահա թե ինչու curl-ը կամ մոբայլ հավելվածները կարող են կոտրվել, մինչդեռ desktop բրաուզերներն աշխատում են։ Root-երը մնում են offline և պաշտպանված, իսկ intermediate-ները կարելի է պտտել (rotate)՝ առանց փոխելու այն, ինչին վստահում են սարքերը։

Q3Ինչպե՞ս ես ապահովում, որ սերտիֆիկատները production-ում երբեք ժամկետանց չդառնան։

Ավտոմատացում գումարած մոնիտորինգ։ Օգտագործում եմ certbot կամ այլ ACME client՝ systemd timer-ով կամ cron-ով, deploy hook, որը reload է անում nginx-ը, և կարգավորումից հետո ու սերվերի ցանկացած փոփոխությունից հետո աշխատեցնում եմ certbot renew --dry-run։ 80 պորտը մնում է բաց HTTP-01-ի համար, կամ օգտագործում եմ DNS-01 սահմանափակ իրավունքներով API token-ով։ Հետո մոնիտորինգ եմ անում դրսից՝ uptime գործիք, որը ծանուցում է, երբ սերտիֆիկատին մնացել է մոտ երկու շաբաթից պակաս։ Կյանքի տևողությունները կրճատվում են ամբողջ ոլորտում՝ ձգտելով 47 օրի մինչև 2029, ուստի ձեռքով արվող ցանկացած բան վաղ թե ուշ կձախողվի։ CDN-ի հետևում edge սերտիֆիկատը managed է, բայց origin-ը դեռ պահանջում է նույն խնամքը։

Q4Ի՞նչ է HSTS-ը, և որո՞նք են ռիսկերը։

HSTS-ը պատասխանի header է՝ Strict-Transport-Security, որը բրաուզերին ասում է այս դոմենի համար որոշակի ժամանակահատվածում, օրինակ՝ մեկ տարի, օգտագործել միայն HTTPS։ Առաջին այցից հետո բրաուզերն ինքն է http:// հղումները բարձրացնում HTTPS-ի և թույլ չի տալիս օգտատերերին շրջանցել սերտիֆիկատի սխալները, ինչը արգելափակում է SSL-stripping հարձակումները։ Preload ցանկի դեպքում բրաուզերները այն կիրառում են նույնիսկ ամենաառաջին այցի ժամանակ։ Ռիսկը կախվածությունն է (lock-in)․ եթե includeSubDomains-ով ծածկված որևէ subdomain չի աջակցում HTTPS, կամ սերտիֆիկատը կոտրվում է, օգտատերերը չեն կարող հասնել դրան։ Այդ պատճառով սկսում եմ կարճ max-age-ից, ստուգում բոլոր subdomain-ները, հետո մեծացնում այն, և preload եմ անում միայն վստահ լինելու դեպքում։

Q5Կայքն աշխատում է Chrome-ում, բայց curl-ն ասում է «unable to get local issuer certificate»։ Ինչո՞ւ։

Ամենայն հավանականությամբ սերվերն ուղարկում է միայն իր leaf սերտիֆիկատը՝ առանց intermediate-ի։ Desktop բրաուզերները հաճախ թաքցնում են դա, որովհետև քեշավորում են intermediate-ները կամ ներբեռնում դրանք AIA ընդլայնման միջոցով, բայց curl-ը, շատ մոբայլ client-ներ, Node-ը և Java-ն դա չեն անում։ Լուծումը ամբողջական շղթայի կարգավորումն է․ nginx-ում ssl_certificate-ը պետք է ցույց տա certbot-ի fullchain.pem-ը, ոչ թե cert.pem-ը։ Ստուգում եմ openssl s_client -showcerts-ով և համոզվում, որ intermediate-ը երևում է, կամ օգտագործում եմ առցանց SSL checker։ Ավելի հազվադեպ client մեքենան ինքն ունի հնացած CA bundle, որը թարմացում է պահանջում։

Սենիոր մակարդակի հարցեր

S1Որտե՞ղ պետք է TLS-ը terminate լինի CDN-ով, load balancer-ով և container-ներով համակարգում։

Յուրաքանչյուր hop պետք է գաղտնագրված լինի, երբ անցնում է ցանցով, որը դուք ամբողջությամբ չեք վերահսկում։ CDN-ը terminate է անում այցելուի TLS-ը։ CDN-ից origin օգտագործում եմ Full (strict)՝ վավեր սերտիֆիկատով, իդեալում նաև authenticated origin pulls։ Load balancer-ը կարող է terminate և նորից գաղտնագրել, կամ TLS-ը փոխանցել nginx-ին. այնտեղ termination-ը պարզեցնում է սերտիֆիկատների կառավարումը, վերագաղտնագրումը պահում է տվյալները պաշտպանված ցանցի ներսում։ Նույն host-ում nginx-ի և container-ների միջև private Docker ցանցով պարզ HTTP-ն տարածված, ընդունելի փոխզիջում է։ Host-երի միջև կամ ընդհանուր cluster-ներում օգտագործեք TLS կամ mTLS, հաճախ service mesh-ի միջոցով։ Քիչ termination կետերը նշանակում են պաշտպանելու քիչ key-եր, բայց տրաֆիկը ստուգող յուրաքանչյուր hop պետք է ունենա իր սերտիֆիկատը և rotation-ը։

S2Ինչպե՞ս կպատրաստվեք 47-օրյա սերտիֆիկատների ժամկետներին բազմաթիվ սերվերներում։

Ենթադրեք, որ ոչ մի ձեռքով արվող բան չի դիմանա։ Գույքագրեք յուրաքանչյուր սերտիֆիկատ. web սերվերներ, load balancer-ներ, mail, VPN, սարքեր և ամեն ինչ, որն օգտագործում է ձեռքով պատճենված սերտիֆիկատի ֆայլ։ Յուրաքանչյուրը տեղափոխեք ACME ավտոմատացման կամ managed ծառայության, ինչպես CDN-ը կամ cloud load balancer-ը, որն ինքն է թարմանում։ Օգտագործեք ARI աջակցող client-ներ, որպեսզի CA-ն կարողանա ազդանշել վաղ թարմացման մասին։ Reload-ները դարձրեք ավտոմատ deploy hook-երով և համոզվեք, որ configuration management-ը չի վերագրում թարմացված ֆայլերը։ Արտաքինից մոնիթորինգ արեք ժամկետները և chain-ի սխալները՝ զգուշացնելով շատ ավելի շուտ, քան կմնա կյանքի ժամկետի մեկ երրորդը։ ACME աշխատեցնել չկարողացող սարքերը պետք է լինեն proxy-ի հետևում, որը կարող է։ Ներդրումն արդարանում է compliance-ից այն կողմ. rotation-ները դառնում են առօրյա, ուստի արտակարգ revocation-ն այլևս սթրես չէ։

S3Արժե՞ արդյոք certificate pinning-ը մոբայլ հավելվածներում։

Pinning-ը հավելվածին ստիպում է ընդունել միայն կոնկրետ key-եր, ինչը արգելափակում է interception-ը նույնիսկ եթե օգտատերը տեղադրում է կեղծ CA, կամ CA-ն compromised է։ Գինը փխրունությունն է. եթե key-երը rotate եք անում առանց հավելվածի իմացության, յուրաքանչյուր տեղադրված տարբերակ դադարում է աշխատել, իսկ կարճ ժամկետներով սերտիֆիկատների դեպքում rotation-ը հաճախակի է։ Եթե pinning-ը պարտադիր է, pin արեք intermediate-ի կամ ձեր սեփական երկարակյաց key-ի public key-ը, ոչ թե leaf-ը, միշտ ուղարկեք backup pin-եր, տրամադրեք pinning-ը հեռակա թարմացնելու կամ անջատելու եղանակ և թարմացումների միջև պահեք նույն key-ը, որտեղ ձեր CA-ի գործընթացը դա թույլ է տալիս։ Հավելվածների մեծ մասի համար ստանդարտ TLS validation-ը գումարած պլատֆորմի Certificate Transparency ստուգումները բավարար են։ Pinning-ը սովորաբար արդարանում է բանկային և բարձր ռիսկի հավելվածներում։

Բառարան

CA
Certificate Authority. կազմակերպություն, որին վստահում են սերտիֆիկատներ ստորագրել՝ ստուգելուց հետո, որ հայցողը կառավարում է դոմենը։
Leaf certificate
Ձեր սեփական hostname-ի սերտիֆիկատը՝ chain-ի ամենաներքևում։
Intermediate CA
CA սերտիֆիկատ root-ի և ձեր leaf-ի միջև. սերվերները պետք է այն ուղարկեն leaf-ի հետ միասին։
SAN
Subject Alternative Name. hostname-ների ցանկը, որոնց համար սերտիֆիկատը վավեր է։
SNI
Server Name Indication. hostname-ը, որը client-ն ուղարկում է handshake-ում, որպեսզի սերվերը ընտրի ճիշտ սերտիֆիկատը։
Forward secrecy
Ժամանակավոր session key-երի օգտագործում, որպեսզի գողացված սերվերի key-ը չկարողանա վերծանել անցյալում գրանցված տրաֆիկը։
ACME
Պրոտոկոլը, որով Let's Encrypt-ի նման CA-ները ավտոմատ թողարկում և թարմացնում են սերտիֆիկատները։
HSTS
Header, որը բրաուզերներին ասում է որոշակի ժամանակահատվածում դոմենի համար օգտագործել միայն HTTPS։
Certificate Transparency
Յուրաքանչյուր թողարկված սերտիֆիկատի հրապարակային log-եր, որպեսզի դոմենի սեփականատերերը նկատեն անսպասելիները։
mTLS
Mutual TLS. և՛ client-ը, և՛ սերվերը ներկայացնում են սերտիֆիկատներ և ստուգում միմյանց։

Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։

Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։