15-bo‘lim

TLS va HTTPS

TLS nimani va'da qiladi, qo'l berish bosqichlari, sertifikatlar va ishonch zanjiri, nima shifrlanadi va nima ochiq qoladi.

🕑 8 daqiqa o‘qish 📄 744 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. TLS uchta narsani va'da qiladi
  2. Qo'l berish bosqichlari
  3. TLS serveri va mijozi
  4. Ishonch zanjiri
  5. Nima shifrlanadi, nima yo'q?
  6. Xulosa

12-bo'limda HTTP so'rovini ochiq matnda yubordik. Bu shuni anglatadiki, yo'ldagi har bir qurilma uni o'qiy oladi - Wi-Fi nuqtasi, provayder, oradagi marshrutizatorlar.

HTTPS - bu HTTP ning ustiga TLS qatlami qo'shilgani.

TLS uchta narsani va'da qiladi #

Va'daMa'nosiUsiz nima bo'ladi
MaxfiylikYo'ldagi hech kim o'qiy olmaydiParolingiz ochiq ketadi
ButunlikYo'lda o'zgartirib bo'lmaydiSahifaga reklama qo'shiladi
HaqiqiylikServer aynan o'zi ekani tasdiqlanadiSoxta saytga tushasiz

Uchinchisi eng ko'p e'tibordan chetda qoladi, lekin u eng muhimi. Shifrlash kim bilan gaplashayotganingizni bilmasangiz, foydasiz: hujumchi bilan xotirjam shifrlangan aloqa qurgan bo'lasiz.

Qo'l berish bosqichlari #

TLS 1.3 qo'l berish Mijoz Server ClientHello + kalit ulushi + SNI "qaysi shifrlarni bilaman, qaysi saytga kelyapman" ServerHello + sertifikat + imzo "mana men shuman - buni tekshirib ko'r" mijoz sertifikatni tekshiradi bu yerdan boshlab hammasi shifrlangan TLS 1.3 da bu bir marta borib-kelishga sig'adi (TLS 1.2 da ikki marta kerak edi) Kalit hech qachon yo'ldan o'tmaydi - u ikkala tomonda alohida hisoblanadi
Sertifikat maxfiy emas - u ochiq yuboriladi va hamma ko'radi

Eng muhim nuqta: shifrlash kaliti tarmoqdan o'tmaydi. Ikkala tomon ochiq ma'lumot almashadi, lekin undan kelib chiqadigan umumiy sirni faqat o'zlari hisoblay oladi. Bu kalit almashuvi "Amaliy kriptografiya" darsligida batafsil ko'rilgan.

TLS serveri va mijozi #

Quyidagi misolda sinov sertifikati yasaladi va u bilan haqiqiy TLS ulanish quriladi:

Python
import os
import ssl
import socket
import subprocess
import tempfile
import threading

ish = tempfile.mkdtemp()
kalit = os.path.join(ish, "kalit.pem")
sert = os.path.join(ish, "sert.pem")

# O'zi imzolagan sertifikat yasaymiz (faqat sinov uchun!)
subprocess.run([
    "openssl", "req", "-x509", "-newkey", "rsa:2048",
    "-keyout", kalit, "-out", sert, "-days", "1", "-nodes",
    "-subj", "/CN=localhost",
], check=True, capture_output=True)

print("sertifikat yasaldi:", os.path.exists(sert))
print("kalit yasaldi     :", os.path.exists(kalit))

PORT = 9900

tinglovchi = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tinglovchi.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tinglovchi.bind(("127.0.0.1", PORT))
tinglovchi.listen(1)

server_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
server_ctx.load_cert_chain(sert, kalit)


def server():
    xom, _ = tinglovchi.accept()
    with server_ctx.wrap_socket(xom, server_side=True) as himoyalangan:
        himoyalangan.recv(1024)
        himoyalangan.sendall(b"shifrlangan javob")


oqim = threading.Thread(target=server, daemon=True)
oqim.start()

# Mijoz: o'zi imzolagan sertifikatga ishonishi uchun uni beramiz
mijoz_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
mijoz_ctx.load_verify_locations(sert)

xom = socket.create_connection(("127.0.0.1", PORT))
s = mijoz_ctx.wrap_socket(xom, server_hostname="localhost")
s.sendall(b"shifrlangan so'rov")
javob = s.recv(1024)

print()
print("TLS 1.3 ishlatildimi:", s.version() == "TLSv1.3")
print("shifr tanlandimi    :", s.cipher() is not None)

sertifikat = s.getpeercert()
nom = dict(x[0] for x in sertifikat["subject"])
print("sertifikat egasi    :", nom["commonName"])

print("javob               :", javob.decode())

s.close()
oqim.join()
tinglovchi.close()
Natija
sertifikat yasaldi: True
kalit yasaldi     : True

TLS 1.3 ishlatildimi: True
shifr tanlandimi    : True
sertifikat egasi    : localhost
javob               : shifrlangan javob

E'tibor bering: soket bilan ishlash o'zgarmadi. sendall va recv xuddi oldingidek. Farqi shundaki, soket wrap_socket bilan o'ralgan - bu 9-bo'limdagi Dekorator naqshining aynan o'zi.

-nodes va o'zi imzolagan sertifikat - faqat sinov uchun

Yuqoridagi buyruqda ikkita narsa bor, ular ishlab chiqarishga mos emas:

NimaNima uchun sinov uchun
-nodesMaxfiy kalit parolsiz saqlanadi
-x509 o'zi imzolaganHech kim unga ishonmaydi

Haqiqiy sayt uchun sertifikatni sertifikat markazi (CA) beradi. Bugun bu bepul va avtomatik: Let's Encrypt kabi xizmatlar buni bir buyruq bilan bajaradi.

Ishonch zanjiri #

Mijoz sertifikatni qanday tekshiradi? U uchta savolga javob izlaydi:

  1. Sertifikatni ishonchli markaz imzolaganmi?
  2. Undagi nom men so'ragan nom bilan mos keladimi?
  3. Muddati tugamaganmi?

Uchalasini ham sinab ko'ramiz:

Python
import os
import ssl
import socket
import subprocess
import tempfile
import threading

ish = tempfile.mkdtemp()
kalit = os.path.join(ish, "k.pem")
sert = os.path.join(ish, "s.pem")
subprocess.run([
    "openssl", "req", "-x509", "-newkey", "rsa:2048",
    "-keyout", kalit, "-out", sert, "-days", "1", "-nodes",
    "-subj", "/CN=localhost",
], check=True, capture_output=True)

PORT = 9901
tinglovchi = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tinglovchi.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tinglovchi.bind(("127.0.0.1", PORT))
tinglovchi.listen(4)

server_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
server_ctx.load_cert_chain(sert, kalit)


def server(nechta):
    for _ in range(nechta):
        xom, _ = tinglovchi.accept()
        try:
            with server_ctx.wrap_socket(xom, server_side=True) as h:
                h.recv(64)
                h.sendall(b"ok")
        except ssl.SSLError:
            pass          # mijoz qo'l berishni rad etdi
        except OSError:
            pass


oqim = threading.Thread(target=server, args=(3,), daemon=True)
oqim.start()


def sinab_kor(nom, ctx, xost="localhost"):
    try:
        xom = socket.create_connection(("127.0.0.1", PORT), timeout=5)
        s = ctx.wrap_socket(xom, server_hostname=xost)
        s.sendall(b"salom")
        s.recv(64)
        s.close()
        print(f"  {nom:<34} ULANDI")
    except ssl.SSLCertVerificationError as x:
        sabab = x.verify_message.split(",")[0]
        print(f"  {nom:<34} RAD ETILDI")
        print(f"  {'':<34} sabab: {sabab}")
    except ssl.SSLError:
        print(f"  {nom:<34} RAD ETILDI: TLS xatosi")


print("uchta mijoz, uchta sozlama:")

# 1 - tizimning ishonchli markazlari (bizning sertifikat yo'q)
sinab_kor("tizim ishonchi bilan", ssl.create_default_context())

# 2 - sertifikatimizni ishonchli deb ko'rsatamiz
ctx2 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx2.load_verify_locations(sert)
sinab_kor("sertifikat ishonchli deb berildi", ctx2)

# 3 - to'g'ri sertifikat, lekin NOM mos kelmaydi
ctx3 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx3.load_verify_locations(sert)
sinab_kor("nom mos kelmaydi", ctx3, "boshqa-sayt.uz")

oqim.join()
tinglovchi.close()
Natija
uchta mijoz, uchta sozlama:
  tizim ishonchi bilan               RAD ETILDI
                                     sabab: self-signed certificate
  sertifikat ishonchli deb berildi   ULANDI
  nom mos kelmaydi                   RAD ETILDI
                                     sabab: Hostname mismatch

Uchinchi holat ayniqsa muhim: sertifikat haqiqiy va ishonchli, lekin u localhost uchun berilgan. Boshqa nom so'ralganda ulanish rad etildi.

Aynan shu tekshiruv soxta saytlardan himoya qiladi.

Sertifikat tekshiruvini hech qachon o'chirmang

Internetda "TLS xatosini qanday tuzatish" degan savolga eng ko'p beriladigan "yechim" - tekshiruvni o'chirish:

TilO'chirish usuli
Pythonctx.verify_mode = ssl.CERT_NONE
curl-k yoki --insecure
Node.jsrejectUnauthorized: false

Buni qilsangiz, TLS ning uchinchi va'dasi butunlay yo'qoladi: shifrlash qoladi, lekin kim bilan shifrlayotganingiz noma'lum.

To'g'ri yechimlar:

MuammoTo'g'ri yechim
Ichki sertifikatUni ishonchlilar ro'yxatiga qo'shing
Muddati tugaganYangilang
Nom mos emasTo'g'ri nom bilan qayta bering
Zanjir to'liq emasServerga oraliq sertifikatni qo'shing

Oxirgisi juda ko'p uchraydi: brauzerda ishlaydi, lekin curl yoki mobil ilova xato beradi. Sabab - brauzerda oraliq sertifikat keshda qolgan bo'ladi.

Nima shifrlanadi, nima yo'q? #

Bu savolga aniq javob berish muhim - ko'pchilik HTTPS ni "hech kim hech narsani ko'rmaydi" deb tushunadi.

Python
MALUMOTLAR = [
    ("Qaysi IP manzilga ulandingiz", False),
    ("Qaysi portga ulandingiz", False),
    ("Ulanish vaqti va davomiyligi", False),
    ("Uzatilgan ma'lumot HAJMI", False),
    ("Sayt nomi (SNI, qo'l berishda)", False),
    ("DNS so'rovi (oddiy DNS da)", False),
    ("So'ralgan yo'l (/hisobim)", True),
    ("Sarlavhalar va cookie lar", True),
    ("Forma va parol", True),
    ("Javob tanasi", True),
    ("Holat kodi", True),
]

print(f"{'Ma\'lumot':<34} {'Yo\'lda ko\'rinadimi'}")
print("-" * 56)
for nom, shifrlangan in MALUMOTLAR:
    holat = "yo'q - shifrlangan" if shifrlangan else "HA - ochiq"
    print(f"{nom:<34} {holat}")

ochiq = sum(1 for _, s in MALUMOTLAR if not s)
print()
print("ochiq qoladigan bandlar:", ochiq)
print("shifrlanadiganlari     :", len(MALUMOTLAR) - ochiq)
print()
print("TLS mazmunni yashiradi, ALOQA FAKTINI emas")
Natija
Ma'lumot                           Yo'lda ko'rinadimi
--------------------------------------------------------
Qaysi IP manzilga ulandingiz       HA - ochiq
Qaysi portga ulandingiz            HA - ochiq
Ulanish vaqti va davomiyligi       HA - ochiq
Uzatilgan ma'lumot HAJMI           HA - ochiq
Sayt nomi (SNI, qo'l berishda)     HA - ochiq
DNS so'rovi (oddiy DNS da)         HA - ochiq
So'ralgan yo'l (/hisobim)          yo'q - shifrlangan
Sarlavhalar va cookie lar          yo'q - shifrlangan
Forma va parol                     yo'q - shifrlangan
Javob tanasi                       yo'q - shifrlangan
Holat kodi                         yo'q - shifrlangan

ochiq qoladigan bandlar: 6
shifrlanadiganlari     : 5

TLS mazmunni yashiradi, ALOQA FAKTINI emas
SNI nima uchun ochiq qoladi?

2-bo'limda ko'rgandik: bitta IP da yuzlab sayt turishi mumkin.

Server qaysi sertifikatni yuborishni bilishi kerak. Lekin bu qaror qo'l berishning eng boshida, shifrlash hali yoqilmasdan qabul qilinadi.

Shuning uchun sayt nomi (Server Name Indication) ochiq ketadi.

Buni yopish uchun Encrypted Client Hello ishlab chiqilgan, lekin u hali hamma joyda ishlatilmaydi.

Amaliy xulosa: HTTPS qaysi saytga kirganingizni yashirmaydi - faqat o'sha saytda nima qilganingizni yashiradi.

Amaliy topshiriq
  1. TLS server misolini ishga tushiring.
  2. s.cipher() natijasini to'liq chop eting va o'qing.
  3. Sertifikat muddatini (notAfter) chop eting.
  4. Tekshiruv misolini ishga tushiring.
  5. To'rtinchi holat qo'shing: muddati o'tgan sertifikat (-days 0).
  6. openssl s_client -connect edu.softromeda.com:443 ni ishga tushiring.
  7. Chiqishdan sertifikat zanjirini toping.
  8. Brauzerda qulf belgisini bosib, sertifikatni ko'ring.
  9. TLS yashiradigan va yashirmaydigan uchtadan narsani sanang.
  10. Sertifikat tekshiruvini o'chirish nima uchun xavfli ekanini yozing.

Xulosa #

  • TLS uchta narsani beradi: maxfiylik, butunlik va haqiqiylik.
  • Haqiqiylik eng muhimi: kim bilan gaplashayotganingizni bilmasangiz, shifrlash foydasiz.
  • Shifrlash kaliti tarmoqdan o'tmaydi - u ikkala tomonda alohida hisoblanadi.
  • TLS 1.3 qo'l berish bir marta borib-kelishga sig'adi.
  • Soket API si o'zgarmaydi - soket shunchaki wrap_socket bilan o'raladi.
  • Sertifikat tekshiruvi uch savoldan iborat: kim imzolagan, nom mos keladimi, muddati.
  • Nom mos kelmasa ulanish rad etiladi - bu soxta saytlardan asosiy himoya.
  • Tekshiruvni hech qachon o'chirmang - bu TLS ning uchinchi va'dasini yo'q qiladi.
  • TLS mazmunni yashiradi, aloqa faktini emas: IP, vaqt, hajm va SNI ochiq qoladi.
  • HTTPS qaysi saytga kirganingizni emas, o'sha saytda nima qilganingizni yashiradi.

Keyingi bo'limda tarmoq tezligi haqida gaplashamiz: kechikish, o'tkazuvchanlik va tiqilinch nazorati.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.