14-bo‘lim
Cookie, sessiya va holat
HTTP nima uchun holatsiz, cookie qanday ishlaydi, sessiya ombori, cookie atributlari va imzolangan cookie.
Ushbu bo‘lim mundarijasi
HTTP holatsiz (stateless) protokol: har so'rov mustaqil va server oldingisini eslamaydi.
Lekin saytga kirasiz, savatga mahsulot qo'shasiz, sahifani yangilaysiz - va hammasi joyida turadi. Bu qanday ishlaydi?
Cookie - eng sodda yechim #
G'oya juda oddiy: server javobda kichik matn beradi, brauzer uni saqlaydi va har keyingi so'rovda qaytaradi.
import socket
import threading
PORT = 9800
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 tomonidagi sessiya ombori
SESSIYALAR = {"s-abc123": {"ism": "Husanboy", "korishlar": 0}}
def sarlavha_top(sorov, nom):
for q in sorov.split("\r\n")[1:]:
if q.lower().startswith(nom.lower() + ":"):
return q.split(":", 1)[1].strip()
return None
def server(nechta):
for _ in range(nechta):
ulanish, _ = tinglovchi.accept()
sorov = ulanish.recv(4096).decode()
cookie = sarlavha_top(sorov, "Cookie")
qoshimcha = ""
if cookie and "sessiya=" in cookie:
sid = cookie.split("sessiya=")[1].split(";")[0]
sessiya = SESSIYALAR.get(sid)
if sessiya:
sessiya["korishlar"] += 1
tana = (f"Xush kelibsiz, {sessiya['ism']}! "
f"Ko'rishlar: {sessiya['korishlar']}")
else:
tana = "Sessiya topilmadi"
else:
tana = "Salom, mehmon! Sizga sessiya berildi."
qoshimcha = ("Set-Cookie: sessiya=s-abc123; Path=/; "
"HttpOnly; SameSite=Lax\r\n")
yuk = tana.encode()
javob = (f"HTTP/1.1 200 OK\r\n{qoshimcha}"
f"Content-Length: {len(yuk)}\r\n"
f"Connection: close\r\n\r\n").encode() + yuk
ulanish.sendall(javob)
ulanish.close()
oqim = threading.Thread(target=server, args=(3,), daemon=True)
oqim.start()
def sorov_yubor(cookie=None):
m = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
m.settimeout(5)
m.connect(("127.0.0.1", PORT))
satr = "GET / HTTP/1.1\r\nHost: x\r\n"
if cookie:
satr += f"Cookie: {cookie}\r\n"
m.sendall((satr + "\r\n").encode())
javob = b""
while True:
b = m.recv(1024)
if not b:
break
javob += b
m.close()
sarlavhalar, tana = javob.decode().split("\r\n\r\n", 1)
return sarlavhalar, tana
print("1-tashrif (cookie yo'q):")
s, t = sorov_yubor()
for q in s.split("\r\n"):
if q.startswith("Set-Cookie"):
print(" server berdi ->", q)
print(" tana:", t)
print()
print("2-tashrif (brauzer cookie ni qaytaradi):")
s, t = sorov_yubor("sessiya=s-abc123")
print(" tana:", t)
print()
print("3-tashrif:")
s, t = sorov_yubor("sessiya=s-abc123")
print(" tana:", t)
oqim.join()
tinglovchi.close()
1-tashrif (cookie yo'q):
server berdi -> Set-Cookie: sessiya=s-abc123; Path=/; HttpOnly; SameSite=Lax
tana: Salom, mehmon! Sizga sessiya berildi.
2-tashrif (brauzer cookie ni qaytaradi):
tana: Xush kelibsiz, Husanboy! Ko'rishlar: 1
3-tashrif:
tana: Xush kelibsiz, Husanboy! Ko'rishlar: 2
Protokol hali ham holatsiz - har so'rov mustaqil. Holat esa serverdagi lug'atda va cookie unga kalit bo'lib xizmat qiladi.
Misolda s-abc123 deb qo'ydik, lekin haqiqiy dasturda u
taxmin qilib bo'lmaydigan bo'lishi kerak.
1, 2, 3 kabi ketma-ket raqamlar berilsa, kimdir
boshqa raqamni yozib qo'yib, o'zga odamning sessiyasiga
kirib oladi.
Python da to'g'ri yo'l:
import secrets
sid = secrets.token_urlsafe(32)
random modulini ishlatmang - u xavfsizlik uchun
mo'ljallanmagan.
Cookie atributlari #
Cookie qiymatidan tashqari bir nechta atribut ham uzatiladi. Ular cookie qachon va qayerga yuborilishini belgilaydi:
COOKIELAR = [
"sessiya=s-abc123; Path=/; HttpOnly; Secure; SameSite=Strict",
"mavzu=qorong; Path=/; Max-Age=31536000",
"kuzatuv=xyz; Domain=.reklama.example; SameSite=None; Secure",
]
IZOHLAR = {
"httponly": "JavaScript o'qiy olmaydi",
"secure": "faqat HTTPS orqali",
"samesite": "begona saytdan kelganda cheklanadi",
"max-age": "necha soniya saqlanadi",
"path": "qaysi yo'llarda yuboriladi",
"domain": "qaysi domenlarga yuboriladi",
}
for matn in COOKIELAR:
bolaklar = [b.strip() for b in matn.split(";")]
nom, qiymat = bolaklar[0].split("=", 1)
print(f"{nom} = {qiymat}")
for b in bolaklar[1:]:
kalit = b.split("=")[0]
qiy = b.split("=", 1)[1] if "=" in b else "-"
print(f" {kalit:<9} {qiy:<10} {IZOHLAR.get(kalit.lower(), '')}")
print()
print("xavfsizlik uchun eng muhim uchtasi:")
for k in ["httponly", "secure", "samesite"]:
print(f" {k:<9} {IZOHLAR[k]}")
sessiya = s-abc123
Path / qaysi yo'llarda yuboriladi
HttpOnly - JavaScript o'qiy olmaydi
Secure - faqat HTTPS orqali
SameSite Strict begona saytdan kelganda cheklanadi
mavzu = qorong
Path / qaysi yo'llarda yuboriladi
Max-Age 31536000 necha soniya saqlanadi
kuzatuv = xyz
Domain .reklama.example qaysi domenlarga yuboriladi
SameSite None begona saytdan kelganda cheklanadi
Secure - faqat HTTPS orqali
xavfsizlik uchun eng muhim uchtasi:
httponly JavaScript o'qiy olmaydi
secure faqat HTTPS orqali
samesite begona saytdan kelganda cheklanadi
| Atribut | Nimadan himoya qiladi |
|---|---|
HttpOnly | Sahifaga tushib qolgan skript cookie ni o'qiy olmaydi |
Secure | Shifrlanmagan HTTP orqali yuborilmaydi |
SameSite | Boshqa saytdagi forma sizning nomingizdan so'rov yubora olmaydi |
Uchalasini ham qo'yish - bir qator kod, lekin ular eng ko'p uchraydigan uchta hujum turini birdan qiyinlashtiradi.
SameSite uchun qiymat tanlash:
| Qiymat | Qachon |
|---|---|
Strict | Bank, admin panel - eng qattiq |
Lax | Odatdagi saytlar uchun yaxshi standart |
None | Faqat haqiqatan kerak bo'lsa, Secure bilan birga |
Bu mavzular "Kiberxavfsizlik asoslari" darsligining 9-bo'limida batafsil ko'rilgan.
Holatni qayerda saqlash kerak? #
Ikki yondashuv bor va ikkalasi ham keng ishlatiladi:
| Server tomonda | Cookie ichida | |
|---|---|---|
| Cookie da nima bor | Faqat identifikator | Ma'lumotning o'zi |
| Hajmi | Kichik | 4 KB gacha |
| Bekor qilish | Oson - omborda o'chirasiz | Qiyin |
| Serverlar ko'p bo'lsa | Umumiy ombor kerak | Kerak emas |
| O'zgartirib bo'ladimi | Yo'q | Imzo bo'lmasa - ha |
Oxirgi qator hal qiluvchi. Ma'lumotni cookie ichida saqlasangiz, uni imzolash shart:
import hashlib
import hmac
MAXFIY = b"server-kaliti-hech-kimga-aytilmaydi"
def imzola(malumot):
imzo = hmac.new(MAXFIY, malumot.encode(), hashlib.sha256).hexdigest()
return f"{malumot}.{imzo[:16]}"
def tekshir(cookie):
if "." not in cookie:
return None
malumot, imzo = cookie.rsplit(".", 1)
kutilgan = hmac.new(MAXFIY, malumot.encode(),
hashlib.sha256).hexdigest()[:16]
# hmac.compare_digest - vaqt bo'yicha xavfsiz taqqoslash
if hmac.compare_digest(imzo, kutilgan):
return malumot
return None
toza = imzola("foydalanuvchi=husanboy&rol=oquvchi")
print("server bergan cookie:")
print(" ", toza)
print()
print("tekshiruv:", tekshir(toza))
# Endi kimdir qiymatni o'zgartirmoqchi bo'ladi
buzilgan = toza.replace("rol=oquvchi", "rol=admin")
print()
print("o'zgartirilgan cookie:")
print(" ", buzilgan)
print("tekshiruv:", tekshir(buzilgan))
print()
print("imzo mos kelmadi, chunki maxfiy kalit faqat serverda")
print("qiymat KO'RINADI, lekin uni O'ZGARTIRIB bo'lmaydi")
server bergan cookie:
foydalanuvchi=husanboy&rol=oquvchi.efb38b66f8dd0c84
tekshiruv: foydalanuvchi=husanboy&rol=oquvchi
o'zgartirilgan cookie:
foydalanuvchi=husanboy&rol=admin.efb38b66f8dd0c84
tekshiruv: None
imzo mos kelmadi, chunki maxfiy kalit faqat serverda
qiymat KO'RINADI, lekin uni O'ZGARTIRIB bo'lmaydi
Yuqoridagi cookie da rol=oquvchi ochiq ko'rinadi. Imzo
uni yashirmaydi - u faqat o'zgartirishdan himoya qiladi.
Shuning uchun cookie ichiga hech qachon quyidagilarni yozmang:
| Yozmang | Sabab |
|---|---|
| Parol yoki uning xeshi | Ochiq ko'rinadi |
| Shaxsiy ma'lumot | Brauzer diskida saqlanadi |
| Ichki ID lar | Tizim tuzilishini oshkor qiladi |
Maxfiy narsa kerak bo'lsa - uni serverda saqlang va cookie da faqat identifikator bering.
hmac.compare_digest ga ham e'tibor bering: oddiy ==
taqqoslash qancha belgi mos kelganiga qarab turlicha vaqt
oladi va bu ma'lumot sizib chiqishiga yo'l ochadi.
Sessiya va token #
Zamonaviy loyihalarda yana bir yondashuv keng tarqalgan - token (masalan JWT). U aslida "cookie ichida ma'lumot" usulining rivojlangan shakli:
| Sessiya | Token | |
|---|---|---|
| Holat qayerda | Serverda | Tokenning o'zida |
| Bekor qilish | Darhol | Muddati tugagunicha kutiladi |
| Bir necha server | Umumiy ombor kerak | Kerak emas |
| Hajmi | Bir necha bayt | Bir necha yuz bayt |
Bekor qilish masalasi ko'pincha kam baholanadi: foydalanuvchi "barcha qurilmalardan chiqish" tugmasini bosganda token yondashuvida uni darhol to'xtatib bo'lmaydi.
Shuning uchun amalda ko'pincha ikkalasi birga ishlatiladi: qisqa muddatli token va uni yangilaydigan, serverda saqlanadigan yozuv.
- Cookie misolini ishga tushiring.
- Serverga ikkinchi sessiya qo'shing va uni sinang.
- Mavjud bo'lmagan sessiya ID si bilan so'rov yuboring.
secrets.token_urlsafebilan tasodifiy ID yasang.- Atributlar misolini ishga tushiring va yangi cookie qo'shing.
- Brauzer ishlab chiquvchi panelida haqiqiy saytning cookie larini ko'ring.
- Imzolangan cookie misolini ishga tushiring.
MAXFIYkalitni o'zgartiring - eski cookie hali ishlaydimi?- Imzoni 16 belgidan 8 ga qisqartiring va bu nima uchun yomon ekanini yozing.
- O'z loyihangiz uchun sessiya yoki token tanlang va sababini asoslang.
Xulosa #
- HTTP holatsiz: har so'rov mustaqil, server oldingisini eslamaydi.
- Cookie - server beradigan va brauzer qaytaradigan kichik matn.
- Server odatda cookie da faqat identifikator saqlaydi, holat esa o'zida turadi.
- Sessiya identifikatori taxmin qilib bo'lmaydigan bo'lishi shart (
secrets). HttpOnly,SecurevaSameSite- sessiya cookie si uchun majburiy uchlik.SameSite=Lax- ko'p sayt uchun to'g'ri standart tanlov.- Ma'lumotni cookie ichida saqlasangiz, uni imzolash shart.
- Imzolash shifrlash emas: qiymat ochiq ko'rinadi, faqat o'zgartirib bo'lmaydi.
- Imzoni
hmac.compare_digestbilan taqqoslang,==bilan emas. - Token yondashuvining asosiy narxi - uni darhol bekor qilib bo'lmasligi.
Keyingi bo'limda barcha bu ma'lumotlarni yo'lda himoya qiladigan qatlamni - TLS ni ko'ramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
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.