From c216adb472d07e598dcc3916953a7a1770db022f Mon Sep 17 00:00:00 2001 From: Faustze Date: Fri, 24 Jul 2026 16:13:09 +0300 Subject: [PATCH] fix: flatten Event Loop section, repair broken RU network translations - content/browser/Event Loop/ was just a two-page wrapper folder with its own index. Moved Rendering Pipeline.md and Event Loop, Microtasks, Macrotasks.md directly into content/browser/ (and content-ru/browser/) and removed the now-redundant index.md, updating every wikilink (including two stale links still pointing at the pre-rename "Event Loop/Event Loop" filename). - content-ru/browser/Network/HTTP Headers & Caching.md was wrapped in a stray ```markdown code fence around the whole file. - content-ru/browser/Network/TCP & TLS Handshake.md had leaked raw claude-cli agent transcript (tool calls, JSON) instead of the translated note. Replaced with a clean translation of the current content/ source. - Updated .translation-manifest.json for the moved/edited source files. --- content-ru/.translation-manifest.json | 7 +- .../Event Loop, Microtasks, Macrotasks.md | 4 +- content-ru/browser/Event Loop/index.md | 12 -- .../browser/Network/HTTP Headers & Caching.md | 2 - .../browser/Network/TCP & TLS Handshake.md | 103 +++++++++++++++--- .../{Event Loop => }/Rendering Pipeline.md | 8 +- content-ru/browser/index.md | 5 +- .../Event Loop, Microtasks, Macrotasks.md | 4 +- content/browser/Event Loop/index.md | 12 -- .../{Event Loop => }/Rendering Pipeline.md | 8 +- content/browser/index.md | 5 +- 11 files changed, 106 insertions(+), 64 deletions(-) rename content-ru/browser/{Event Loop => }/Event Loop, Microtasks, Macrotasks.md (97%) delete mode 100644 content-ru/browser/Event Loop/index.md rename content-ru/browser/{Event Loop => }/Rendering Pipeline.md (94%) rename content/browser/{Event Loop => }/Event Loop, Microtasks, Macrotasks.md (96%) delete mode 100644 content/browser/Event Loop/index.md rename content/browser/{Event Loop => }/Rendering Pipeline.md (92%) diff --git a/content-ru/.translation-manifest.json b/content-ru/.translation-manifest.json index c77d13498bbc..3f98e86edaf8 100644 --- a/content-ru/.translation-manifest.json +++ b/content-ru/.translation-manifest.json @@ -1,13 +1,12 @@ { - "browser/Event Loop/Event Loop, Microtasks, Macrotasks.md": "ef7e18bdfa11924dff151a6a5557be2893e4004c9c10068ffb553f0008c36225", - "browser/Event Loop/Rendering Pipeline.md": "272e73f40aadfd7fbe43603dc75f044beee1672196e992f76f240937a0cb8bd6", - "browser/Event Loop/index.md": "f9f7836aceeba96e0518a91f66bb916e1d194bc7e52f58ba2e8684a643866840", + "browser/Event Loop, Microtasks, Macrotasks.md": "c50fcbd1c514616b299ca0979a0e71e3fb11fe01890273df918cca74205d433c", "browser/Network/CORS.md": "90a34e5d48b1faad3fdb74ecb7b41fa0b78bb87af7e157c439f2c537d60632a8", "browser/Network/Cookies & Storage.md": "9a49a4e936342471acae3b88e5f5f81f9c2c7c83e14be4a19dbe3acb88330d87", "browser/Network/HTTP Headers & Caching.md": "84d40df2788021f2466cb63770346463df8cab99283ec7f78ed57026ee035c09", "browser/Network/TCP & TLS Handshake.md": "40b29f2a89a82ff105ec0b9e581a3b0bf7b6d0b27937deebb636225c2fd8db16", "browser/Network/index.md": "8562b0aabb62de7630dcf0b354e7c903792255721a1c57f519b4f1245651e483", - "browser/index.md": "2eb4623fd4287396fe34aa7ce75076ae5e30f88af39c8a4e3eab03b3530ebab9", + "browser/Rendering Pipeline.md": "39781029a4de64f155bdf7981e5a1124a821bcdac38fbd78b88f60b22a92ca66", + "browser/index.md": "480bbaeb7fa140c3641d10310bc223acb51985cf8c48097b088c2e1181bea311", "headhunter/JavaScript-easy-level.md": "07d772fee0195708ac9b6bdf41e1f0fcd2efcf15861cc34947dbce0975d26277", "headhunter/JavaScript-middle-level.md": "46ae57febadc70bebdc4f8116a7cf2db901c525e2b573bcfa34377be7af45ac0", "headhunter/index.md": "d9888f62e5b1a3e71f67b05616d51e15e1eccb67be651c33da850f48f438afd2", diff --git a/content-ru/browser/Event Loop/Event Loop, Microtasks, Macrotasks.md b/content-ru/browser/Event Loop, Microtasks, Macrotasks.md similarity index 97% rename from content-ru/browser/Event Loop/Event Loop, Microtasks, Macrotasks.md rename to content-ru/browser/Event Loop, Microtasks, Macrotasks.md index eb375f0f7536..08a35a87233b 100644 --- a/content-ru/browser/Event Loop/Event Loop, Microtasks, Macrotasks.md +++ b/content-ru/browser/Event Loop, Microtasks, Macrotasks.md @@ -88,6 +88,6 @@ requestAnimationFrame(animate) > Условие выхода Event Loop для очереди микротасков — «пусто», а самопополняющаяся очередь никогда его не достигает. Очередь rAF же выходит через _снимок_: всё, что добавляется во время батча, откладывается на следующий, независимо от скорости выполнения. -[[browser/Event Loop/index|Event Loop & Rendering]] -[[browser/Event Loop/Rendering Pipeline|Rendering Pipeline — что происходит после опустошения очереди микротасков]] +[[browser/index|Browser]] +[[browser/Rendering Pipeline|Rendering Pipeline — что происходит после опустошения очереди микротасков]] #browser diff --git a/content-ru/browser/Event Loop/index.md b/content-ru/browser/Event Loop/index.md deleted file mode 100644 index 2722dccf2d81..000000000000 --- a/content-ru/browser/Event Loop/index.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: цикл событий ---- - -# Цикл событий и рендеринг - -[[browser/index|← Browser]] - -- [[browser/Event Loop/Event Loop, Microtasks, Macrotasks|Event Loop, Microtasks, Macrotasks]] -- [[browser/Event Loop/Rendering Pipeline|Rendering Pipeline: Layout, Paint, Composite]] - -#browser diff --git a/content-ru/browser/Network/HTTP Headers & Caching.md b/content-ru/browser/Network/HTTP Headers & Caching.md index 5b22fc1465fc..572d05f3b35f 100644 --- a/content-ru/browser/Network/HTTP Headers & Caching.md +++ b/content-ru/browser/Network/HTTP Headers & Caching.md @@ -1,4 +1,3 @@ -```markdown # 📦 HTTP-заголовки и кэширование ## 💡 Основная идея @@ -61,4 +60,3 @@ [[browser/Network/TCP & TLS Handshake|TCP & TLS Handshake — что позволяет пропустить кэширование]] [[browser/Network/CORS|CORS — ещё один сетевой шлюз на стороне браузера]] #browser -``` diff --git a/content-ru/browser/Network/TCP & TLS Handshake.md b/content-ru/browser/Network/TCP & TLS Handshake.md index 27b7d2b06235..d46c1734a577 100644 --- a/content-ru/browser/Network/TCP & TLS Handshake.md +++ b/content-ru/browser/Network/TCP & TLS Handshake.md @@ -1,28 +1,99 @@ -**PowerShell Tool** +# 🔐 TCP & TLS Handshake -Result: +## 💡 Основная идея + +> Всё, что происходит до первого байта HTTP-ответа, — это цепочка рукопожатий, каждое из которых оплачивает гарантию, необходимую следующему уровню: сначала надёжный байтовый поток (TCP), затем доверенный зашифрованный канал (TLS). Понимание того, _почему_ существует каждый круговой обмен пакетами, объясняет, почему HTTPS почти никогда не является узким местом на практике. + +--- + +# 🧭 Полная цепочка ``` -content/browser/Network/HTTP Headers & Caching.md -content/browser/Network/TCP & TLS Handshake.md -content/browser/Network/index.md +DNS resolution (hostname → IP) + → TCP three-way handshake (SYN / SYN-ACK / ACK) — 1 RTT, transport layer + → TLS handshake, HTTPS only — ~1 RTT more (TLS 1.3) + → HTTP request (method + path + headers + body) + → HTTP response (status + headers + body) + → keep-alive: connection stays open, next request reuses it ``` -I'll translate the note and write it to the matching path in `content-ru/browser/Network/`. +## Разрешение DNS + +Маршрутизаторы пересылают пакеты только по IP (сетевой уровень) — доменное имя это чисто человекочитаемый уровень поверх. Браузер физически не может собрать TCP SYN-пакет без числового IP в заголовке, поэтому DNS должен разрешиться раньше TCP. -**Write** +Порядок поиска: кэш браузера → кэш ОС/файл hosts → рекурсивный резолвер (провайдера или публичный, например 8.8.8.8) → если в кэше нет, резолвер проходит по иерархии: корневые серверы → серверы TLD (`.com`) → авторитетный nameserver домена → IP возвращается и кэшируется на срок TTL. Транспорт обычно UDP/53 (или DoH/DoT поверх HTTPS/TLS для приватности). -```` -{ - "file_path": "/home/faust/notes/content-ru/browser/Network/TCP & TLS Handshake.md", - "content": "# \ud83d\udd10 TCP & TLS Handshake\n\n## \ud83d\udca1 Основная идея\n\n> Всё, что происходит до первого байта HTTP-ответа, — это цепочка рукопожатий, каждое из которых оплачивает гарантию, необходимую следующему уровню: сначала надёжный байтовый поток (TCP), затем доверенный зашифрованный канал (TLS). Понимание того, *почему* существует каждый круговой обмен пакетами, объясняет, почему HTTPS почти никогда не является узким местом на практике.\n\n---\n# \ud83e\udded Полная цепочка\n\n```\nDNS resolution (hostname → IP)\n → TCP three-way handshake (SYN / SYN-ACK / ACK) — 1 RTT, transport layer\n → TLS handshake, HTTPS only — ~1 RTT more (TLS 1.3)\n → HTTP request (method + path + headers + body)\n → HTTP response (status + headers + body)\n → keep-alive: connection stays open, next request reuses it\n```\n\n## Разрешение DNS\n\nМаршрутизаторы пересылают пакеты только по IP (сетевой уровень) — доменное имя это чисто человекочитаемый уровень поверх. Браузер физически не может собрать TCP SYN-пакет без числового IP в заголовке, поэтому DNS должен разрешиться раньше TCP.\n\nПорядок поиска: кэш браузера → кэш ОС/файл hosts → рекурсивный резолвер (провайдера или публичный, например 8.8.8.8) → если в кэше нет, резолвер проходит по иерархии: корневые серверы → серверы TLD (`.com`) → авторитетный nameserver домена → IP возвращается и кэшируется на срок TTL. Транспорт обычно UDP/53 (или DoH/DoT поверх HTTPS/TLS для приватности).\n\n---\n# \ud83e\udd1d TCP-рукопожатие\n\n```\nClient --- SYN (seq=x) --------------> Server\nClient <-- SYN-ACK (seq=y, ack=x+1) -- Server\nClient --- ACK (ack=y+1) -------------> Server\n```\n\n- **SYN** — клиент отправляет случайный начальный порядковый номер `seq=x`, отправную точку для нумерации каждого байта, который он будет отправлять (нужно для обнаружения потери/дублирования/переупорядочивания).\n- **SYN-ACK** — сервер подтверждает SYN клиента (`ack=x+1`) **и одновременно** отправляет свой собственный SYN (`seq=y`). Оба флага в одном пакете — это piggyback: TCP полнодуплексен (два независимых байтовых потока, каждый со своим счётчиком), и если бы сервер отправлял ACK и свой SYN отдельно, это добавило бы целый лишний круговой обмен (4 сообщения / 2 RTT вместо 3 / 1 RTT).\n- **ACK** — клиент подтверждает `seq=y` сервера (`ack=y+1`). Данные могут идти сразу после этого; клиент отправляет этот финальный ACK, не дожидаясь ответа на него, поэтому всё тройное рукопожатие укладывается в **1 RTT**, а не 3.\n\nЭто устанавливает надёжный, упорядоченный байтовый поток **до того**, как хотя бы один байт HTTP сможет пройти — цена гарантии надёжности TCP (доставка + порядок).\n\n---\n# \ud83d\udd12 TLS-рукопожатие (TLS 1.3)\n\nНадстраивается поверх уже установленного TCP-соединения, для `https://`.\n\n1. **Client Hello** — поддерживаемые наборы шифров, версия TLS, случайное число. На этом этапе ничего ещё не зашифровано.\n2. **Server Hello + сертификат** — публичный ключ сервера (внутри сертификата), цепочка подписей вплоть до CA и выбранный набор шифров.\n3. **Проверка сертификата.** Сертификат — это набор полей (публичный ключ сервера, домен, срок действия), подписанный **приватным ключом CA** — не сервера. Механика подписи: CA хэширует эти поля → шифрует хэш своим приватным ключом → прикрепляет результат как подпись. Браузер берёт *публичный* ключ CA из **хранилища доверия** (списка доверенных корневых CA, предустановленного в ОС/браузере — никогда не загружается по сети), расшифровывает подпись, чтобы получить хэш, вычисленный CA, и независимо пересчитывает хэш из тех же полей сам. Если они совпадают, значит CA подтвердил, что этот публичный ключ принадлежит этому домену. Несовпадение или сломанная цепочка → `NET::ERR_CERT_*`.\n4. **Доказательство владения приватным ключом (подпись транскрипта).** Сертификат публичен и может быть скопирован — MITM мог бы предъявить чужой валидный сертификат. Поэтому сервер отдельно подписывает **своим собственным** приватным ключом хэш *транскрипта*: полной последовательности сообщений, которыми обменялись в рамках именно этого рукопожатия. Клиент проверяет эту подпись публичным ключом сервера (из сертификата). Это замыкает цепочку доверия: CA подтвердил, что ключ принадлежит домену, а подпись транскрипта доказывает, что сторона на другом конце прямо сейчас реально владеет этим ключом — а не просто переслала копию сертификата.\n5. **Обмен ключами (ephemeral Diffie-Hellman / ECDHE).** Сам секрет сессии никогда не передаётся по сети — обе стороны обмениваются только публичными DH-значениями, и каждая независимо вычисляет один и тот же секрет. Показатели степени **эфемерны**: генерируются заново для каждого рукопожатия и немедленно уничтожаются после. Приватный ключ сертификата вообще не участвует в этом вычислении — он только подписывает (шаг 4). Отсюда и берётся **forward secrecy**: даже если приватный ключ сертификата утечёт позже, это не поможет расшифровать прошлый трафик, потому что секрет этого трафика был получен из уже уничтоженных эфемерных значений, а не из ключа сертификата. (Наблюдатель видит в трафике только публичные значения — восстановление секрета из них означает решение задачи дискретного логарифма, вычислительно неосуществимо.)\n6. **Переход на симметричное шифрование** — весь последующий трафик использует быстрый симметричный шифр (AES и т.п.) с ключом из секрета шага 5.\n\nTLS 1.3 укладывает всё рукопожатие в **1 RTT** (TLS 1.2 требовал 2).\n\n## Асимметричная криптография ≠ асимметричное шифрование\n\nАсимметричная криптография — это общий термин как минимум для трёх разных операций над парой ключей: (a) шифрование публичным ключом / расшифровка приватным — например, почта PGP; (b) подпись приватным ключом / проверка публичным — шаги 3–4 выше; (c) согласование общего секрета без шифрования чего-либо — ECDHE, шаг 5. Только (a) буквально является «асимметричным шифрованием данных», и именно это TLS 1.3 вообще не использует. Конкретное сравнение: версии до TLS 1.3 шифровали pre-master secret публичным ключом сервера — классическое асимметричное шифрование (операция a), но без forward secrecy, поскольку тот же долгоживущий приватный ключ мог расшифровать его при утечке позже. TLS 1.3 заменил это на ECDHE (операция c) специально ради forward secrecy.\n\n---\n# \u267b\ufe0f Keep-alive против возобновления сессии\n\nДва разных механизма избежать нового рукопожатия, на двух разных уровнях:\n\n- **Keep-alive** (уровень HTTP, `Connection: keep-alive`, поведение по умолчанию в HTTP/1.1) — держит **уже открытое** TCP+TLS соединение живым между запросами; следующий запрос переиспользует его вообще без нового рукопожатия. Умирает при закрытии вкладки/браузера или таймауте простоя.\n- **Возобновление сессии (session resumption)** (уровень TLS) — для **нового** соединения (старое уже закрыто: новая вкладка, визит на следующий день). При первом рукопожатии сервер выдаёт зашифрованный **билет сессии (session ticket)**. При новом соединении клиент предъявляет билет, и обе стороны выполняют сокращённое рукопожатие вместо полного. Переживает перезапуски браузера (билеты живут часы/дни).\n\n**Тест, чтобы отличить их друг от друга:** то же соединение, никогда не закрывалось → keep-alive. Новое соединение, но рукопожатие заметно быстрее полного → возобновление сессии.\n\n## TLS 1.3 0-RTT\n\nСтроится на том же билете сессии, что и возобновление, но идёт на шаг дальше: клиент отправляет зашифрованные данные приложения (например, сам HTTP-запрос) **в самом первом пакете**, вместе с Client Hello — не дожидаясь никакого ответа. Это работает, потому что билет несёт pre-shared key (PSK) из предыдущего соединения. «0» относится к количеству **дополнительных круговых обменов до того, как реальные данные смогут пойти**, а не к тому, что само рукопожатие завершается мгновенно.\n\nНа самом деле здесь три уровня, а не два:\n\n1. **Полное рукопожатие** — 1 RTT, сертификат проверяется с нуля.\n2. **Возобновление сессии без 0-RTT** — всё ещё 1 RTT, но рукопожатие сокращено через PSK; повторная проверка сертификата не нужна.\n3. **0-RTT** — данные уходят до завершения хотя бы одного кругового обмена.\n\n**Почему данные 0-RTT рискованны: повтор (replay), а не кража ключа.** MITM не может расшифровать или подделать данные 0-RTT — шифрование по-прежнему защищает конфиденциальность и целостность. Но он *может* захватить зашифрованный пакет и отправить его серверу повторно несколько раз. Обычно свежесть гарантируется свежими случайными значениями, обмен которыми происходит интерактивно за один круговой обмен; данные 0-RTT отправляются до того, как это интерактивное подтверждение существует, поэтому у сервера нет встроенного способа отличить повтор от по-настоящему нового запроса.\n\nИменно поэтому 0-RTT ограничен **идемпотентными** операциями. Идемпотентность = повтор одного и того же запроса любое число раз даёт то же самое конечное состояние (GET, PUT, DELETE — повторить один раз или десять, результат тот же). Неидемпотентные (POST, например `перевести $100`) создают новый эффект при каждом вызове — повторить 5 раз, произойдёт 5 переводов.\n\nНа практике (RFC 8470) сочетаются два уровня защиты:\n\n1. **Уровень HTTP** — запросы, пришедшие как 0-RTT, помечаются `Early-Data: 1`. Приложение проверяет метод: безопасный (GET) → обрабатывается как обычно; небезопасный (POST/PUT/DELETE) → отвечает `425 Too Early`, не выполняя его, и клиент повторяет тот же запрос после завершения полного рукопожатия.\n2. **Уровень TLS** — серверы могут поддерживать ограниченное окно анти-повтора уже виденных билетов/nonce, но это плохо масштабируется на несколько серверов за балансировщиком нагрузки — вторичная защита, а не основная.\n\n---\n# \ud83e\udde0 Почему HTTPS на практике едва ли медленнее HTTP\n\nРукопожатие оплачивается **один раз на соединение**, а не один раз на запрос. `keep-alive` держит TCP+TLS открытыми, HTTP/2 мультиплексирует множество запросов через одно соединение. Накладные расходы заметны только там, где браузер открывает **много новых соединений** к разным origin (первый визит на страницу, загруженную со сторонними доменами — каждый новый origin означает своё собственное TCP+TLS рукопожатие).\n\n[[browser/Network/index|HTTP & Network]]\n[[browser/Network/HTTP Headers & Caching|HTTP Headers & Caching]]\n#browser\n" -} -```` +--- -Result: +# 🤝 TCP-рукопожатие ``` -File created successfully at: /home/faust/notes/content-ru/browser/Network/TCP & TLS Handshake.md +Client --- SYN (seq=x) --------------> Server +Client <-- SYN-ACK (seq=y, ack=x+1) -- Server +Client --- ACK (ack=y+1) -------------> Server ``` -Translated and saved to `content-ru/browser/Network/TCP & TLS Handshake.md`, mirroring the English source path. +- **SYN** — клиент отправляет случайный начальный порядковый номер `seq=x`, отправную точку для нумерации каждого байта, который он будет отправлять (нужно для обнаружения потери/дублирования/переупорядочивания). +- **SYN-ACK** — сервер подтверждает SYN клиента (`ack=x+1`) **и одновременно** отправляет свой собственный SYN (`seq=y`). Оба флага в одном пакете — это piggyback: TCP полнодуплексен (два независимых байтовых потока, каждый со своим счётчиком), и если бы сервер отправлял ACK и свой SYN отдельно, это добавило бы целый лишний круговой обмен (4 сообщения / 2 RTT вместо 3 / 1 RTT). +- **ACK** — клиент подтверждает `seq=y` сервера (`ack=y+1`). Данные могут идти сразу после этого; клиент отправляет этот финальный ACK, не дожидаясь ответа на него, поэтому всё тройное рукопожатие укладывается в **1 RTT**, а не 3. + +Это устанавливает надёжный, упорядоченный байтовый поток **до того**, как хотя бы один байт HTTP сможет пройти — цена гарантии надёжности TCP (доставка + порядок). + +--- + +# 🔒 TLS-рукопожатие (TLS 1.3) + +Надстраивается поверх уже установленного TCP-соединения, для `https://`. + +1. **Client Hello** — поддерживаемые наборы шифров, версия TLS, случайное число. На этом этапе ничего ещё не зашифровано. +2. **Server Hello + сертификат** — публичный ключ сервера (внутри сертификата), цепочка подписей вплоть до CA и выбранный набор шифров. +3. **Проверка сертификата.** Сертификат — это набор полей (публичный ключ сервера, домен, срок действия), подписанный **приватным ключом CA** — не сервера. Механика подписи: CA хэширует эти поля → шифрует хэш своим приватным ключом → прикрепляет результат как подпись. Браузер берёт _публичный_ ключ CA из **хранилища доверия** (списка доверенных корневых CA, предустановленного в ОС/браузере — никогда не загружается по сети), расшифровывает подпись, чтобы получить хэш, вычисленный CA, и независимо пересчитывает хэш из тех же полей сам. Если они совпадают, значит CA подтвердил, что этот публичный ключ принадлежит этому домену. Несовпадение или сломанная цепочка → `NET::ERR_CERT_*`. +4. **Доказательство владения приватным ключом (подпись транскрипта).** Сертификат публичен и может быть скопирован — MITM мог бы предъявить чужой валидный сертификат. Поэтому сервер отдельно подписывает **своим собственным** приватным ключом хэш _транскрипта_: полной последовательности сообщений, которыми обменялись в рамках именно этого рукопожатия. Клиент проверяет эту подпись публичным ключом сервера (из сертификата). Это замыкает цепочку доверия: CA подтвердил, что ключ принадлежит домену, а подпись транскрипта доказывает, что сторона на другом конце прямо сейчас реально владеет этим ключом — а не просто переслала копию сертификата. +5. **Обмен ключами (ephemeral Diffie-Hellman / ECDHE).** Сам секрет сессии никогда не передаётся по сети — обе стороны обмениваются только публичными DH-значениями, и каждая независимо вычисляет один и тот же секрет. Показатели степени **эфемерны**: генерируются заново для каждого рукопожатия и немедленно уничтожаются после. Приватный ключ сертификата вообще не участвует в этом вычислении — он только подписывает (шаг 4). Отсюда и берётся **forward secrecy**: даже если приватный ключ сертификата утечёт позже, это не поможет расшифровать прошлый трафик, потому что секрет этого трафика был получен из уже уничтоженных эфемерных значений, а не из ключа сертификата. (Наблюдатель видит в трафике только публичные значения — восстановление секрета из них означает решение задачи дискретного логарифма, вычислительно неосуществимо.) +6. **Переход на симметричное шифрование** — весь последующий трафик использует быстрый симметричный шифр (AES и т.п.) с ключом из секрета шага 5. + +TLS 1.3 укладывает всё рукопожатие в **1 RTT** (TLS 1.2 требовал 2). + +## Асимметричная криптография ≠ асимметричное шифрование + +Асимметричная криптография — это общий термин как минимум для трёх разных операций над парой ключей: (a) шифрование публичным ключом / расшифровка приватным — например, почта PGP; (b) подпись приватным ключом / проверка публичным — шаги 3–4 выше; (c) согласование общего секрета без шифрования чего-либо — ECDHE, шаг 5. Только (a) буквально является «асимметричным шифрованием данных», и именно это TLS 1.3 вообще не использует. Конкретное сравнение: версии до TLS 1.3 шифровали pre-master secret публичным ключом сервера — классическое асимметричное шифрование (операция a), но без forward secrecy, поскольку тот же долгоживущий приватный ключ мог расшифровать его при утечке позже. TLS 1.3 заменил это на ECDHE (операция c) специально ради forward secrecy. + +--- + +# ♻️ Keep-alive против возобновления сессии + +Два разных механизма избежать нового рукопожатия, на двух разных уровнях: + +- **Keep-alive** (уровень HTTP, `Connection: keep-alive`, поведение по умолчанию в HTTP/1.1) — держит **уже открытое** TCP+TLS соединение живым между запросами; следующий запрос переиспользует его вообще без нового рукопожатия. Умирает при закрытии вкладки/браузера или таймауте простоя. +- **Возобновление сессии (session resumption)** (уровень TLS) — для **нового** соединения (старое уже закрыто: новая вкладка, визит на следующий день). При первом рукопожатии сервер выдаёт зашифрованный **билет сессии (session ticket)**. При новом соединении клиент предъявляет билет, и обе стороны выполняют сокращённое рукопожатие вместо полного. Переживает перезапуски браузера (билеты живут часы/дни). + +**Тест, чтобы отличить их друг от друга:** то же соединение, никогда не закрывалось → keep-alive. Новое соединение, но рукопожатие заметно быстрее полного → возобновление сессии. + +## TLS 1.3 0-RTT + +Строится на том же билете сессии, что и возобновление, но идёт на шаг дальше: клиент отправляет зашифрованные данные приложения (например, сам HTTP-запрос) **в самом первом пакете**, вместе с Client Hello — не дожидаясь никакого ответа. Это работает, потому что билет несёт pre-shared key (PSK) из предыдущего соединения. «0» относится к количеству **дополнительных круговых обменов до того, как реальные данные смогут пойти**, а не к тому, что само рукопожатие завершается мгновенно. + +На самом деле здесь три уровня, а не два: + +1. **Полное рукопожатие** — 1 RTT, сертификат проверяется с нуля. +2. **Возобновление сессии без 0-RTT** — всё ещё 1 RTT, но рукопожатие сокращено через PSK; повторная проверка сертификата не нужна. +3. **0-RTT** — данные уходят до завершения хотя бы одного кругового обмена. + +**Почему данные 0-RTT рискованны: повтор (replay), а не кража ключа.** MITM не может расшифровать или подделать данные 0-RTT — шифрование по-прежнему защищает конфиденциальность и целостность. Но он _может_ захватить зашифрованный пакет и отправить его серверу повторно несколько раз. Обычно свежесть гарантируется свежими случайными значениями, обмен которыми происходит интерактивно за один круговой обмен; данные 0-RTT отправляются до того, как это интерактивное подтверждение существует, поэтому у сервера нет встроенного способа отличить повтор от по-настоящему нового запроса. + +Именно поэтому 0-RTT ограничен **идемпотентными** операциями. Идемпотентность = повтор одного и того же запроса любое число раз даёт то же самое конечное состояние (GET, PUT, DELETE — повторить один раз или десять, результат тот же). Неидемпотентные (POST, например «перевести $100») создают новый эффект при каждом вызове — повторить 5 раз, произойдёт 5 переводов. + +На практике (RFC 8470) сочетаются два уровня защиты: + +1. **Уровень HTTP** — запросы, пришедшие как 0-RTT, помечаются `Early-Data: 1`. Приложение проверяет метод: безопасный (GET) → обрабатывается как обычно; небезопасный (POST/PUT/DELETE) → отвечает `425 Too Early`, не выполняя его, и клиент повторяет тот же запрос после завершения полного рукопожатия. +2. **Уровень TLS** — серверы могут поддерживать ограниченное окно анти-повтора уже виденных билетов/nonce, но это плохо масштабируется на несколько серверов за балансировщиком нагрузки — вторичная защита, а не основная. + +--- + +# 🧠 Почему HTTPS на практике едва ли медленнее HTTP + +Рукопожатие оплачивается **один раз на соединение**, а не один раз на запрос. `keep-alive` держит TCP+TLS открытыми, HTTP/2 мультиплексирует множество запросов через одно соединение. Накладные расходы заметны только там, где браузер открывает **много новых соединений** к разным origin (первый визит на страницу, загруженную со сторонними доменами — каждый новый origin означает своё собственное TCP+TLS рукопожатие). + +[[browser/Network/index|HTTP & Network]] +[[browser/Network/HTTP Headers & Caching|HTTP Headers & Caching]] +#browser diff --git a/content-ru/browser/Event Loop/Rendering Pipeline.md b/content-ru/browser/Rendering Pipeline.md similarity index 94% rename from content-ru/browser/Event Loop/Rendering Pipeline.md rename to content-ru/browser/Rendering Pipeline.md index 56ba1dfd792a..7918b50ac5ed 100644 --- a/content-ru/browser/Event Loop/Rendering Pipeline.md +++ b/content-ru/browser/Rendering Pipeline.md @@ -17,7 +17,7 @@ Layout → Paint (пиксели: цвет, текст, тени) Paint → Composite (GPU собирает слои) ``` -`element.style.width = '100px'` **не** триггерит layout немедленно. Браузер просто помечает элемент (и часто его поддерево) как "грязный" и откладывает пересчёт до следующей естественной точки рендера — шага, который идёт сразу после того, как очередь микрозадач опустеет и отработают колбэки rAF в [[browser/Event Loop/Event Loop|Event Loop]]. +`element.style.width = '100px'` **не** триггерит layout немедленно. Браузер просто помечает элемент (и часто его поддерево) как "грязный" и откладывает пересчёт до следующей естественной точки рендера — шага, который идёт сразу после того, как очередь микрозадач опустеет и отработают колбэки rAF в [[browser/Event Loop, Microtasks, Macrotasks|Event Loop]]. Важное различие: **CSSOM** (распарсенные правила из `