{"id":985,"date":"2026-05-13T10:02:31","date_gmt":"2026-05-13T08:02:31","guid":{"rendered":"https:\/\/www.sabatka.net\/en\/?p=985"},"modified":"2026-05-18T08:01:33","modified_gmt":"2026-05-18T06:01:33","slug":"gtm-vs-csp-tracking-and-security","status":"publish","type":"post","link":"https:\/\/www.sabatka.net\/cs\/gtm-vs-csp-tracking-and-security\/","title":{"rendered":"GTM vs. CSP"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">V\u00fdvoj\u00e1\u0159 nasad\u00ed Content Security Policy na firemn\u00ed web \u2014 a tracking se v tichosti rozbije. Nebo naopak: analytik p\u0159id\u00e1 tag do Google Tag Manager (GTM) a protla\u010d\u00ed v\u00fdjimku v CSP \u2014 m\u011b\u0159en\u00ed funguje, ale web je d\u011brav\u00fd.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Google Tag Manager (GTM) je ze sv\u00e9 podstaty script injector \u2014 vkl\u00e1d\u00e1 do str\u00e1nky ciz\u00ed skripty. Content Security Policy (CSP) je script blocker \u2014 blokuje v\u0161e, co nen\u00ed na allowlistu. Kdy\u017e je nasad\u00edte oba bez rozmyslu, bu\u010f p\u0159ijdete o data, nebo o bezpe\u010dnost. Nejde o HTTP hlavi\u010dky. Jde o to, jestli m\u00e1te data pro rozhodov\u00e1n\u00ed \u2014 a jestli jsou v bezpe\u010d\u00ed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">V <a href=\"https:\/\/www.sabatka.net\/cs\/gtm-security-risks\/\">p\u0159edchoz\u00edm \u010dl\u00e1nku<\/a> jsem uk\u00e1zal, co v\u0161echno se m\u016f\u017ee st\u00e1t, kdy\u017e GTM nem\u00e1 dohled \u2014 od nevinn\u00fdch chyb po zdokumentovan\u00e9 \u00fatoky na e-shopy. Te\u010f se pod\u00edv\u00e1me na technick\u00e9 \u0159e\u0161en\u00ed: jak nastavit CSP tak, aby m\u011b\u0159en\u00ed fungovalo a web z\u016fstal chr\u00e1n\u011bn\u00fd.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button scroll_to_subscribe\"><a class=\"wp-block-button__link wp-element-button\" href=\"#\">Chci odeb\u00edrat novinky<\/a><\/div>\n\n\n\n<div class=\"wp-block-button linkedinShare\"><a class=\"wp-block-button__link wp-element-button\">Sd\u00edlet na LinkedIN<\/a><\/div>\n<\/div>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Co je Content Security Policy<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">CSP je HTTP hlavi\u010dka, kterou server \u0159\u00edk\u00e1 prohl\u00ed\u017ee\u010di: \u201eSm\u00ed\u0161 spou\u0161t\u011bt skripty jen z t\u011bchto zdroj\u016f.&#8220; Nic v\u00edc, nic m\u00ed\u0148.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Content-Security-Policy: \n  script-src 'self' https:\/\/*.googletagmanager.com;\n  connect-src 'self' https:\/\/*.google-analytics.com;\n  img-src 'self' https:\/\/*.google-analytics.com;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Pro analytiku jsou relevantn\u00ed hlavn\u011b tyto direktivy:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>script-src<\/code><\/strong> \u2014 kter\u00e9 skripty se sm\u00ed spou\u0161t\u011bt (nejd\u016fle\u017eit\u011bj\u0161\u00ed)<\/li>\n\n\n\n<li><strong><code>connect-src<\/code><\/strong> \u2014 kam se sm\u00ed pos\u00edlat data (XHR, fetch, beacony)<\/li>\n\n\n\n<li><strong><code>img-src<\/code><\/strong> \u2014 odkud se sm\u00ed na\u010d\u00edtat obr\u00e1zky (a trackingov\u00e9 pixely)<\/li>\n\n\n\n<li><strong><code>frame-src<\/code><\/strong> \u2014 povolen\u00e9 iframy<\/li>\n\n\n\n<li><strong><code>style-src<\/code><\/strong> \u2014 styly (relevantn\u00ed pro GTM preview mode)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Prohl\u00ed\u017ee\u010d nerozli\u0161uje mezi \u201ehodn\u00fdm&#8220; skriptem GA4 a \u0161kodliv\u00fdm JavaScriptem.<\/strong> Pokud skript nen\u00ed na allowlistu, prohl\u00ed\u017ee\u010d ho zablokuje. Ti\u0161e, bez varov\u00e1n\u00ed pro u\u017eivatele \u2014 a \u010dasto bez varov\u00e1n\u00ed pro v\u00e1s.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CSP chr\u00e1n\u00ed proti XSS \u00fatok\u016fm, data exfiltration a injektov\u00e1n\u00ed \u0161kodliv\u00e9ho k\u00f3du. D\u011bl\u00e1 to dob\u0159e. Probl\u00e9m nast\u00e1v\u00e1 ve chv\u00edli, kdy do rovnice vstoup\u00ed tag manager.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Pro\u010d je GTM pro CSP no\u010dn\u00ed m\u016fra<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">GTM funguje ve dvou \u00farovn\u00edch \u2014 a ob\u011b jsou pro CSP probl\u00e9m.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Prvn\u00ed \u00farove\u0148:<\/strong> kontejnerov\u00fd snippet. Inline skript v <code><\/code> str\u00e1nky. Pot\u0159ebuje povolen\u00ed v <code>script-src<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Druh\u00e1 \u00farove\u0148:<\/strong> tagy na\u010dten\u00e9 kontejnerem. GTM si st\u00e1hne konfiguraci a dynamicky vlo\u017e\u00ed do str\u00e1nky dal\u0161\u00ed skripty \u2014 GA4, Meta Pixel, Hotjar, LinkedIn Insight Tag\u2026 Ka\u017ed\u00fd vendor pot\u0159ebuje vlastn\u00ed dom\u00e9ny v CSP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ka\u017ed\u00fd nov\u00fd tag v GTM = potenci\u00e1ln\u00ed nov\u00e1 dom\u00e9na v CSP.<\/strong> Marke\u0165\u00e1k p\u0159id\u00e1 tag za 2 minuty. Zm\u011bna CSP hlavi\u010dky vy\u017eaduje Jira ticket, code review, deploy a \u010dek\u00e1n\u00ed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Re\u00e1ln\u00e9 d\u016fsledky \u0161patn\u00e9 konfigurace:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Tich\u00fd data loss<\/strong> \u2014 tracking p\u0159estane fungovat, ale nikdo si toho nev\u0161imne. Data gap se ned\u00e1 zp\u011btn\u011b doplnit.<\/li>\n\n\n\n<li><strong>Rozbit\u00e9 kampan\u011b<\/strong> \u2014 konverzn\u00ed pixely neodp\u00e1l\u00ed, kampan\u011b nelze vyhodnotit.<\/li>\n\n\n\n<li><strong>Nefunk\u010dn\u00ed debug<\/strong> \u2014 GTM preview mode vy\u017eaduje direktivy pro <code>tagmanager.google.com<\/code>, bez nich lad\u011bn\u00ed nefunguje.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Za chv\u00edli uk\u00e1\u017eu, jak to \u0159e\u0161it. Nejd\u0159\u00edv je ale pot\u0159eba pochopit, pro\u010d \u0161patn\u011b nastaven\u00e9 CSP m\u016f\u017ee b\u00fdt hor\u0161\u00ed ne\u017e \u017e\u00e1dn\u00e9.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Kdy\u017e l\u00e9k zab\u00edj\u00ed: GTM jako bezpe\u010dnostn\u00ed riziko<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bezpe\u010dnostn\u00ed firma Raxis demonstrovala \u00fatok, ve kter\u00e9m vyu\u017eila GTM kontejner k obejit\u00ed WAF i CSP:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u00dato\u010dn\u00edk najde XSS zranitelnost na webu<\/li>\n\n\n\n<li>Vlo\u017e\u00ed odkaz na vlastn\u00ed GTM kontejner se \u0161kodliv\u00fdm Custom HTML tagem<\/li>\n\n\n\n<li>Payload \u017eije na <code>googletagmanager.com<\/code> \u2014 WAF ho nevid\u00ed jako hrozbu, CSP ho povol\u00ed<\/li>\n\n\n\n<li>K\u00f3d se spust\u00ed v kontextu str\u00e1nky \u2014 p\u0159\u00edstup ke cookies, session token\u016fm, formul\u00e1\u0159\u016fm<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Google to uznal jako \u201ehonorable mention\u201c v Bug Bounty programu. V\u00edc zdokumentovan\u00fdch \u00fatok\u016f p\u0159es GTM \u2014 v\u010detn\u011b kr\u00e1de\u017e\u00ed platebn\u00edch \u00fadaj\u016f ze stovek e-shop\u016f \u2014 v <a href=\"https:\/\/www.sabatka.net\/cs\/gtm-security-risks\/\">p\u0159edchoz\u00edm \u010dl\u00e1nku<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>T\u0159i podm\u00ednky mus\u00ed platit sou\u010dasn\u011b:<\/strong> (1) XSS zranitelnost na webu, (2) CSP bez nonce pro GTM skripty, (3) <code>unsafe-inline<\/code> nebo jin\u00e1 slab\u00e1 direktiva v CSP. Spl\u0148ujete v\u0161echny t\u0159i? M\u00e1te probl\u00e9m.<\/p>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-794e3cfa wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:33.33%\">\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"1024\" height=\"1024\" data-src=\"https:\/\/www.sabatka.net\/wp-content\/uploads\/2026\/04\/null-did-you-know.png\" alt=\"V\u011bd\u011bli jste? \u2014 informa\u010dn\u00ed panel\" class=\"wp-image-936 lazyload\" data-srcset=\"https:\/\/www.sabatka.net\/wp-content\/uploads\/2026\/04\/null-did-you-know.png 1024w, https:\/\/www.sabatka.net\/wp-content\/uploads\/2026\/04\/null-did-you-know-300x300.png 300w, https:\/\/www.sabatka.net\/wp-content\/uploads\/2026\/04\/null-did-you-know-150x150.png 150w, https:\/\/www.sabatka.net\/wp-content\/uploads\/2026\/04\/null-did-you-know-768x768.png 768w\" data-sizes=\"(max-width: 1024px) 100vw, 1024px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1024px; --smush-placeholder-aspect-ratio: 1024\/1024;\" \/><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:66.66%\">\n<h3 class=\"wp-block-heading\"><strong><strong>V\u011bdeck\u00e1 pozn\u00e1mka<\/strong><\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Je to jako <a href=\"https:\/\/cs.wikipedia.org\/wiki\/Kob%C5%99%C3%AD_efekt\" target=\"_blank\" rel=\"noopener\">kob\u0159\u00ed efekt<\/a> \u2014 britsk\u00e1 koloni\u00e1ln\u00ed spr\u00e1va v Indii vypsala odm\u011bnu za usmrcen\u00e9 kobry. Lid\u00e9 za\u010dali kobry chovat. Kdy\u017e vl\u00e1da odm\u011bnu zru\u0161ila, chovatel\u00e9 kobry vypustili a populace vzrostla. \u0158e\u0161en\u00ed zhor\u0161ilo probl\u00e9m. CSP nasazen\u00e9 \u201eaby web byl bezpe\u010dn\u00fd&#8220;, ale oslaben\u00e9 kv\u016fli GTM na <code>unsafe-inline<\/code>, funguje stejn\u011b \u2014 vytv\u00e1\u0159\u00ed fale\u0161n\u00fd pocit bezpe\u010d\u00ed a otev\u00edr\u00e1 dve\u0159e \u00fato\u010dn\u00edk\u016fm.<\/p>\n<\/div>\n<\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0160patn\u011b nastaven\u00e9 CSP + GTM je hor\u0161\u00ed ne\u017e \u017e\u00e1dn\u00e9 CSP.<\/strong> Ne jen psychologicky \u2014 i technicky. CSP s <code>unsafe-inline<\/code> explicitn\u011b \u0159\u00edk\u00e1 prohl\u00ed\u017ee\u010di \u201espou\u0161t\u011bj jak\u00fdkoli inline skript.&#8220; V\u00fdsledek je stejn\u00fd jako bez CSP, ale bezpe\u010dnostn\u00ed audity vid\u00ed \u201eCSP: ano&#8220; a jdou d\u00e1l. T\u00fdm p\u0159estane investovat do dal\u0161\u00edch ochran, proto\u017ee \u201eCSP m\u00e1me.&#8220; A \u00fatok typu Raxis ukazuje, jak p\u0159esn\u011b tuto fale\u0161nou jistotu zneu\u017e\u00edt.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Nonce + strict-dynamic: bezpe\u010dn\u00e1 cesta<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Za m\u011b ide\u00e1ln\u00ed cesta \u2014 pokud jde realizovat.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Nonce<\/strong> je n\u00e1hodn\u00fd token (\u0159et\u011bzec znak\u016f), kter\u00fd server vygeneruje pro ka\u017ed\u00fd HTTP response:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Server vygeneruje unik\u00e1tn\u00ed nonce (nap\u0159. <code>a8f5e2b1<\/code>)<\/li>\n\n\n\n<li>Nonce se vlo\u017e\u00ed do CSP hlavi\u010dky: <code>script-src 'nonce-a8f5e2b1' 'strict-dynamic'<\/code><\/li>\n\n\n\n<li>Stejn\u00fd nonce se p\u0159id\u00e1 na GTM snippet: <script nonce=\"a8f5e2b1\"><\/li>\n\n\n\n<li>GTM automaticky propaguje nonce na built-in a template tagy<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>Content-Security-Policy: script-src 'nonce-a8f5e2b1' 'strict-dynamic'\n\n<script nonce=\"a8f5e2b1\">\n  (function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-XXXXX');\n<\/script><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><code>strict-dynamic<\/code> je CSP3 standard (<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Reference\/Headers\/Content-Security-Policy\/script-src\" target=\"_blank\" rel=\"noopener\">definovan\u00fd v MDN specifikaci<\/a>). \u0158\u00edk\u00e1: \u201ed\u016fv\u011b\u0159uj skript\u016fm, kter\u00e9 na\u010dte ji\u017e schv\u00e1len\u00fd skript.\" Nemus\u00edte vypisovat vendorov\u00e9 dom\u00e9ny \u2014 GTM kontejner je schv\u00e1len\u00fd p\u0159es nonce a v\u0161e, co na\u010dte, d\u011bd\u00ed d\u016fv\u011bru.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Google ofici\u00e1ln\u00ed dokumentace <code>strict-dynamic<\/code> p\u0159\u00edmo neuv\u00e1d\u00ed. Je to ale zaveden\u00fd a funguj\u00edc\u00ed p\u0159\u00edstup, doporu\u010dovan\u00fd komunitou.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Pozor na Custom HTML tagy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">GTM propaguje nonce automaticky na <strong>built-in tagy a \u0161ablony z Community Template Gallery<\/strong>. Na Custom HTML tagy nonce <strong>nepropaguje<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pokud m\u00e1te Custom HTML tag, mus\u00edte:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Ru\u010dn\u011b p\u0159idat prom\u011bnnou <code>{{nonce}}<\/code> do ka\u017ed\u00e9ho do ka\u017ed\u00e9ho <code>script<\/code> tagu v Custom HTML<\/li>\n\n\n\n<li>\u0158e\u0161it Chrome-specific workaround \u2014 Chrome maskuje atribut <code>nonce<\/code>, tak\u017ee pot\u0159ebujete <code>data-nonce<\/code><\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Nen\u00ed to nemo\u017en\u00e9, ale je to k\u0159ehk\u00e9 a vy\u017eaduje \u00fadr\u017ebu p\u0159i ka\u017ed\u00e9m nov\u00e9m Custom HTML tagu.<\/p>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Omezen\u00ed nonce p\u0159\u00edstupu<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Nefunguje s full-page cache (ka\u017ed\u00fd response mus\u00ed m\u00edt unik\u00e1tn\u00ed nonce)<\/li>\n\n\n\n<li>Vy\u017eaduje server-side \u00fapravu \u2014 ne v\u017edy maj\u00ed analytici p\u0159\u00edstup k serveru<\/li>\n\n\n\n<li>Edge cases s n\u011bkter\u00fdmi SPA frameworky (Next.js \u2014 client-side komponenty nemohou generovat nonce server-side)<\/li>\n<\/ul>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Whitelist dom\u00e9n: pragmatick\u00e1 cesta<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Nonce vy\u017eaduje dynamick\u00e9 generov\u00e1n\u00ed tokenu v aplika\u010dn\u00edm k\u00f3du p\u0159i ka\u017ed\u00e9m requestu \u2014 \u00fapravy v middleware nebo serverov\u00e9m frameworku. Whitelist je jednodu\u0161\u0161\u00ed: nastav\u00edte statick\u00e9 hodnoty v konfiguraci webserveru (nginx, Apache), CDN, nebo p\u0159es <code><meta><\/code> tag. Oboj\u00ed vy\u017eaduje konfiguraci na stran\u011b serveru (nebo <code><meta><\/code> tag), ale whitelist je statick\u00e1 konfigurace, ne \u00faprava aplika\u010dn\u00edho k\u00f3du:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Content-Security-Policy:\n  script-src 'self' https:\/\/*.googletagmanager.com;\n  connect-src 'self' https:\/\/*.google-analytics.com \n                     https:&#47;&#47;*.analytics.google.com;\n  img-src 'self' https:\/\/*.google-analytics.com;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Pro ka\u017ed\u00fd dal\u0161\u00ed vendor (Meta, LinkedIn, Hotjar\u2026) p\u0159id\u00e1te jeho dom\u00e9ny.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Funguje to? Ano.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Je to elegantn\u00ed? Ne.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Vendo\u0159i m\u011bn\u00ed dom\u00e9ny bez varov\u00e1n\u00ed \u2192 CSP se rozbije a zjist\u00edte to z absence dat<\/li>\n\n\n\n<li>Geo-specifick\u00e9 dom\u00e9ny (<code>google.fr<\/code> vs <code>google.com<\/code>) z\u00e1vis\u00ed na lokaci u\u017eivatele<\/li>\n\n\n\n<li>Ka\u017ed\u00fd nov\u00fd tag v GTM = Jira ticket, deploy, \u010dek\u00e1n\u00ed<\/li>\n\n\n\n<li>\u00dadr\u017eba je pr\u016fb\u011b\u017en\u00e1 \u2014 \u201enastavit a zapomenout\" nefunguje<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Pro weby s full-page cache nebo tam, kde nen\u00ed kapacita na \u00fapravu aplika\u010dn\u00ed vrstvy, to ale m\u016f\u017ee b\u00fdt jedin\u00e1 realistick\u00e1 cesta.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">\u0160ablony vs. Custom HTML: tady se l\u00e1me chleba<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Custom HTML tagy<\/strong> a <strong>Custom JavaScript prom\u011bnn\u00e9<\/strong> jsou z pohledu CSP problematick\u00e9. Custom JS prom\u011bnn\u00e9 vy\u017eaduj\u00ed <code>unsafe-eval<\/code> v <code>script-src<\/code> \u2014 bez n\u011bj vrac\u00ed <code>undefined<\/code> (<a href=\"https:\/\/developers.google.com\/tag-platform\/security\/guides\/csp\" target=\"_blank\" rel=\"noopener\">Google dokumentace<\/a>). Custom HTML tagy mohou fungovat s nonce, ale vy\u017eaduj\u00ed ru\u010dn\u00ed konfiguraci a browser workaroundy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>unsafe-eval<\/code> je je\u0161t\u011b riskantn\u011bj\u0161\u00ed ne\u017e <code>unsafe-inline<\/code> \u2014 povoluje <code>eval()<\/code>, <code>new Function()<\/code> a dal\u0161\u00ed dynamick\u00e9 spou\u0161t\u011bn\u00ed k\u00f3du. P\u0159esn\u011b to, proti \u010demu CSP chr\u00e1n\u00ed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>GTM \u0161ablony<\/strong> (Community Template Gallery nebo vlastn\u00ed) tento probl\u00e9m nemaj\u00ed. B\u011b\u017e\u00ed v sandboxovan\u00e9m prost\u0159ed\u00ed GTM kontejneru, funguj\u00ed jako metody uvnit\u0159 <code>gtm.js<\/code> a nepot\u0159ebuj\u00ed <code>unsafe-eval<\/code> ani <code>unsafe-inline<\/code>. GTM API (<code>sendPixel<\/code>, <code>injectScript<\/code>, <code>setCookie<\/code>\u2026) je navr\u017eeno pro pr\u00e1ci s CSP.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Google explicitn\u011b doporu\u010duje migraci z Custom HTML na \u0161ablony<\/strong> jako bezpe\u010dnou alternativu.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pokud m\u00e1te striktn\u00ed CSP a Custom HTML tagy, vol\u00edte ze t\u0159\u00ed mo\u017enost\u00ed:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>P\u0159epsat na \u0161ablony<\/strong> \u2014 nejbezpe\u010dn\u011bj\u0161\u00ed, ale pr\u00e1ce nav\u00edc. Nav\u00edc ne v\u0161e je mo\u017en\u00e9 v\u016fbec do \u0161ablon p\u0159epsat.<\/li>\n\n\n\n<li><strong>Ru\u010dn\u011b nakonfigurovat nonce<\/strong> pro Custom HTML tagy + browser workaroundy \u2014 funguje, ale k\u0159ehk\u00e9<\/li>\n\n\n\n<li><strong>Povolit <code>unsafe-eval<\/code> \/ <code>unsafe-inline<\/code><\/strong> jako fallback \u2014 nejjednodu\u0161\u0161\u00ed, ale podkop\u00e1v\u00e1 \u00fa\u010del CSP<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Jakou cestu zvolit? Z\u00e1le\u017e\u00ed na po\u010dtu Custom HTML tag\u016f a na tom, jak striktn\u00ed bezpe\u010dnostn\u00ed po\u017eadavky m\u00e1te. \u010c\u00edm v\u00edc tag\u016f a \u010d\u00edm vy\u0161\u0161\u00ed compliance n\u00e1roky, t\u00edm v\u00edc se vyplat\u00ed investice do migrace na \u0161ablony.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Jak do toho zapad\u00e1 server-side GTM?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">sGTM m\u016f\u017ee CSP m\u00edrn\u011b zjednodu\u0161it, ale rozhodn\u011b ho nevy\u0159e\u0161\u00ed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Co sGTM re\u00e1ln\u011b zjednodu\u0161\u00ed:<\/strong> loading GTM kontejneru. Soubor <code>gtm.js<\/code> se serv\u00edruje z va\u0161\u00ed subdom\u00e9ny p\u0159es sGTM \u2014 obsah je identick\u00fd s t\u00edm, co stahujete z Google dom\u00e9ny, ale v <code>script-src<\/code> pot\u0159ebujete jen va\u0161i dom\u00e9nu m\u00edsto <code>googletagmanager.com<\/code>. S Google Tag Gateway v\u00e1m pak m\u016f\u017ee sta\u010dit direktiva <code>self<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Co sGTM ne\u0159e\u0161\u00ed:<\/strong> web kontejner GTM stejn\u011b ve v\u011bt\u0161in\u011b implementac\u00ed stahuje skripty z dom\u00e9n t\u0159et\u00edch stran a pos\u00edl\u00e1 na n\u011b data. N\u011bkter\u00e9 platformy vy\u017eatuj\u00ed pos\u00edlat data frontend i ze serveru (nap\u0159. Meta Pixel + Conversions API p\u0159es sGTM). A n\u011bkter\u00e9 n\u00e1stroje (MS Clarity, Hotjar) nemaj\u00ed server-side verzi v\u016fbec. Jejich skripty mus\u00ed z\u016fstat na str\u00e1nce \u2014 a t\u00edm p\u00e1dem i v CSP.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Report-Only a monitoring: ne\u017e zapnete ostr\u00fd provoz<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Rada pro ka\u017ed\u00e9ho, kdo s CSP za\u010d\u00edn\u00e1: <strong>nezap\u00ednejte enforcement hned.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Za\u010dn\u011bte s <code>Content-Security-Policy-Report-Only<\/code>. Funguje jako ostr\u00e1 CSP, ale m\u00edsto blokov\u00e1n\u00ed jen sb\u00edr\u00e1 hl\u00e1\u0161en\u00ed o violac\u00edch. Nechte ji b\u011b\u017eet minim\u00e1ln\u011b 7 dn\u00ed.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Content-Security-Policy-Report-Only:\n  script-src 'nonce-{token}' 'strict-dynamic';\n  report-uri \/csp-report-endpoint;<\/code><\/pre>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Kam pos\u00edlat violation reporty<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Dedikovan\u00fd endpoint loguj\u00edc\u00ed do BigQuery nebo logovac\u00edho n\u00e1stroje<\/li>\n\n\n\n<li>JavaScript listener na <code>securitypolicyviolation<\/code> event \u2014 violace vid\u00edte p\u0159\u00edmo v prohl\u00ed\u017ee\u010di<\/li>\n\n\n\n<li>GTM Tag Assistant \u2014 um\u00ed zobrazit zdroje blokovan\u00e9 CSP<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Preview mode \u2014 p\u0159ehl\u00e9dnut\u00fd probl\u00e9m<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">GTM debug mode vy\u017eaduje vlastn\u00ed direktivy. Bez nich lad\u011bn\u00ed nefunguje:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>script-src: https:\/\/googletagmanager.com https:\/\/tagmanager.google.com\nstyle-src:  https:\/\/tagmanager.google.com https:\/\/fonts.googleapis.com\nimg-src:    https:\/\/ssl.gstatic.com https:\/\/www.gstatic.com\nfont-src:   https:\/\/fonts.gstatic.com data:<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Zapomenout na tohle znamen\u00e1, \u017ee v\u00e1m debug mode bu\u010f nebude fungovat v\u016fbec, nebo bude lad\u011bn\u00ed nep\u0159\u00edjemn\u00e9.<\/p>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Proces je d\u016fle\u017eit\u011bj\u0161\u00ed ne\u017e konfigurace<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Sebelep\u0161\u00ed CSP je k ni\u010demu, pokud zm\u011bna trv\u00e1 m\u011bs\u00edc. Rychl\u00e9 workflow pro CSP aktualizace (ide\u00e1ln\u011b do 1 dne) je stejn\u011b d\u016fle\u017eit\u00e9 jako samotn\u00e9 nastaven\u00ed. Analytik mus\u00ed v\u011bd\u011bt o CSP, v\u00fdvoj\u00e1\u0159 o tracking z\u00e1vislostech.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Z\u00e1v\u011bry<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>CSP a GTM nejsou nep\u0159\u00e1tel\u00e9. Ale vy\u017eaduj\u00ed koordinaci mezi security a analytics t\u00fdmy.<\/li>\n\n\n\n<li>Praktick\u00fd krok: otev\u0159ete browser console na sv\u00e9m webu. Hledejte n\u011bjak\u00e9 CSP hl\u00e1\u0161en\u00ed (\u010derven\u00e9 errory). Pokud tam jsou, v\u00edte, kde za\u010d\u00edt. Pokud ne \u2014 pod\u00edvejte se, jestli CSP v\u016fbec m\u00e1te.<\/li>\n\n\n\n<li>Pokud jste je\u0161t\u011b ne\u010detli <a href=\"https:\/\/www.notion.so\/cs\/gtm-security-risks\" target=\"_blank\" rel=\"noopener\">prvn\u00ed d\u00edl o bezpe\u010dnostn\u00edch rizic\u00edch GTM<\/a>, za\u010dn\u011bte tam \u2014 ukazuje, co se m\u016f\u017ee st\u00e1t, kdy\u017e GTM nem\u00e1 dohled.<\/li>\n<\/ol>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button scroll_to_subscribe\"><a class=\"wp-block-button__link wp-element-button\" href=\"#\">Chci odeb\u00edrat novinky<\/a><\/div>\n\n\n\n<div class=\"wp-block-button linkedinShare\"><a class=\"wp-block-button__link wp-element-button\">Sd\u00edlet na LinkedIN<\/a><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>V\u00fdvoj\u00e1\u0159 nasad\u00ed Content Security Policy na firemn\u00ed web \u2014 a tracking se v tichosti rozbije. Nebo naopak: analytik p\u0159id\u00e1 tag do Google Tag Manager (GTM) a protla\u010d\u00ed v\u00fdjimku v CSP \u2014 m\u011b\u0159en\u00ed funguje, ale web je d\u011brav\u00fd. Google Tag Manager (GTM) je ze sv\u00e9 podstaty script injector \u2014 vkl\u00e1d\u00e1 do str\u00e1nky ciz\u00ed skripty. Content Security [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":990,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[31,9,10],"tags":[],"class_list":["post-985","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-security","category-digital-analytics","category-google-tag-manager-gtm"],"_links":{"self":[{"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/posts\/985","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/comments?post=985"}],"version-history":[{"count":29,"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/posts\/985\/revisions"}],"predecessor-version":[{"id":1116,"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/posts\/985\/revisions\/1116"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/media\/990"}],"wp:attachment":[{"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/media?parent=985"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/categories?post=985"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sabatka.net\/cs\/wp-json\/wp\/v2\/tags?post=985"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}