{"id":1995,"date":"2025-11-17T22:36:58","date_gmt":"2025-11-17T19:36:58","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/cspyi-dogru-kurmak-wordpress-laravelde-nonce-hash-report-to-ve-inline-scriptleri-tatli-tatli-ehlilestirmek\/"},"modified":"2025-11-17T22:36:58","modified_gmt":"2025-11-17T19:36:58","slug":"cspyi-dogru-kurmak-wordpress-laravelde-nonce-hash-report-to-ve-inline-scriptleri-tatli-tatli-ehlilestirmek","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/cspyi-dogru-kurmak-wordpress-laravelde-nonce-hash-report-to-ve-inline-scriptleri-tatli-tatli-ehlilestirmek\/","title":{"rendered":"CSP\u2019yi Do\u011fru Kurmak: WordPress\/Laravel\u2019de Nonce, Hash, report-to ve Inline Script\u2019leri Tatl\u0131 Tatl\u0131 Ehlile\u015ftirmek"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><div id=\"toc_container\" class=\"toc_transparent no_bullets\"><p class=\"toc_title\">\u0130&ccedil;indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#Giris_Bir_Script_Bir_Kahve_ve_Kucuk_Bir_Panik\"><span class=\"toc_number toc_depth_1\">1<\/span> Giri\u015f: Bir Script, Bir Kahve ve K\u00fc\u00e7\u00fck Bir Panik<\/a><\/li><li><a href=\"#CSP_Neyi_Cozer_Neyi_Bozar_Zihinde_Dogru_Cerceveyi_Kurmak\"><span class=\"toc_number toc_depth_1\">2<\/span> CSP Neyi \u00c7\u00f6zer, Neyi Bozar? Zihinde Do\u011fru \u00c7er\u00e7eveyi Kurmak<\/a><\/li><li><a href=\"#Nonce_mi_Hash_mi_Inline_Scriptlerle_Uyumlu_Yasamanin_Yollari\"><span class=\"toc_number toc_depth_1\">3<\/span> Nonce mi Hash mi? Inline Script\u2019lerle Uyumlu Ya\u015faman\u0131n Yollar\u0131<\/a><\/li><li><a href=\"#WordPresste_CSP_Enqueue_Dunyasinda_Nonce_Hash_ve_Ufak_Tuzaklar\"><span class=\"toc_number toc_depth_1\">4<\/span> WordPress\u2019te CSP: Enqueue D\u00fcnyas\u0131nda Nonce, Hash ve Ufak Tuzaklar<\/a><ul><li><a href=\"#Temel_yaklasim_Her_istekte_nonce_uret_scriptstyle_etiketlerine_ilistir\"><span class=\"toc_number toc_depth_2\">4.1<\/span> Temel yakla\u015f\u0131m: Her istekte nonce \u00fcret, script\/style etiketlerine ili\u015ftir<\/a><\/li><li><a href=\"#Inline_bagimliliklar_onclickten_addEventListenera_minik_goc\"><span class=\"toc_number toc_depth_2\">4.2<\/span> Inline ba\u011f\u0131ml\u0131l\u0131klar: onclick\u2019ten addEventListener\u2019a minik g\u00f6\u00e7<\/a><\/li><li><a href=\"#Emoji_oEmbed_ve_ufak_surprizler\"><span class=\"toc_number toc_depth_2\">4.3<\/span> Emoji, oEmbed ve ufak s\u00fcrprizler<\/a><\/li><li><a href=\"#Hash_ile_degismeyen_kucuk_snippetler\"><span class=\"toc_number toc_depth_2\">4.4<\/span> Hash ile de\u011fi\u015fmeyen k\u00fc\u00e7\u00fck snippet\u2019ler<\/a><\/li><\/ul><\/li><li><a href=\"#Laravelde_CSP_Middleware_Blade_ve_ViteLivewire_Uyumunu_Kurmak\"><span class=\"toc_number toc_depth_1\">5<\/span> Laravel\u2019de CSP: Middleware, Blade ve Vite\/Livewire Uyumunu Kurmak<\/a><ul><li><a href=\"#Middleware_ile_merkezi_politika_request_basina_nonce\"><span class=\"toc_number toc_depth_2\">5.1<\/span> Middleware ile merkezi politika, request ba\u015f\u0131na nonce<\/a><\/li><li><a href=\"#Vite_Livewire_Alpine_ve_arkadaslari\"><span class=\"toc_number toc_depth_2\">5.2<\/span> Vite, Livewire, Alpine ve arkada\u015flar\u0131<\/a><\/li><li><a href=\"#Hashler_nerede_isimize_yarar\"><span class=\"toc_number toc_depth_2\">5.3<\/span> Hash\u2019ler nerede i\u015fimize yarar?<\/a><\/li><\/ul><\/li><li><a href=\"#Raporlama_report-to_report-uri_ve_Ihlalleri_Sakin_Sakin_Izlemek\"><span class=\"toc_number toc_depth_1\">6<\/span> Raporlama: report-to, report-uri ve \u0130hlalleri Sakin Sakin \u0130zlemek<\/a><\/li><li><a href=\"#Sunucu_Basliklari_CDN_ve_Dagitim_Rutinleri_Is_Sahada_Bitiyor\"><span class=\"toc_number toc_depth_1\">7<\/span> Sunucu Ba\u015fl\u0131klar\u0131, CDN ve Da\u011f\u0131t\u0131m Rutinleri: \u0130\u015f Sahada Bitiyor<\/a><ul><li><a href=\"#NginxApacheProxy_Basligi_nerede_set_edecegiz\"><span class=\"toc_number toc_depth_2\">7.1<\/span> Nginx\/Apache\/Proxy: Ba\u015fl\u0131\u011f\u0131 nerede set edece\u011fiz?<\/a><\/li><li><a href=\"#Guvenlik_katmanlarini_yan_yana_dizmek\"><span class=\"toc_number toc_depth_2\">7.2<\/span> G\u00fcvenlik katmanlar\u0131n\u0131 yan yana dizmek<\/a><\/li><\/ul><\/li><li><a href=\"#Kucuk_Pratikler_Inlinei_Azalt_Davranisi_Tasi_Ihlali_Izle\"><span class=\"toc_number toc_depth_1\">8<\/span> K\u00fc\u00e7\u00fck Pratikler: Inline\u2019\u0131 Azalt, Davran\u0131\u015f\u0131 Ta\u015f\u0131, \u0130hlali \u0130zle<\/a><\/li><li><a href=\"#Ornek_Politikalar_Baslangic_Icin_Tatli_Bir_Taban\"><span class=\"toc_number toc_depth_1\">9<\/span> \u00d6rnek Politikalar: Ba\u015flang\u0131\u00e7 \u0130\u00e7in Tatl\u0131 Bir Taban<\/a><\/li><li><a href=\"#Kapanis_CSPyi_Gundelik_Hayata_Katmak\"><span class=\"toc_number toc_depth_1\">10<\/span> Kapan\u0131\u015f: CSP\u2019yi G\u00fcndelik Hayata Katmak<\/a><\/li><\/ul><\/div>\n<h2 id='section-1'><span id=\"Giris_Bir_Script_Bir_Kahve_ve_Kucuk_Bir_Panik\">Giri\u015f: Bir Script, Bir Kahve ve K\u00fc\u00e7\u00fck Bir Panik<\/span><\/h2>\n<p>Hi\u00e7 \u015f\u00f6yle oldu mu? Siteyi canl\u0131ya atm\u0131\u015fs\u0131n, her \u015fey t\u0131k\u0131r t\u0131k\u0131r. Sonra bir g\u00fcn, m\u00fc\u015fteri \u201csepette butonlar \u00e7al\u0131\u015fm\u0131yor\u201d diye ar\u0131yor. Taray\u0131c\u0131 konsoluna bak\u0131yorsun: \u201cRefused to execute inline script because it violates the Content Security Policy\u201d. O an bir kahve al\u0131p derin nefes \u00e7ekiyorsun. Evet, konu <strong>CSP<\/strong>. \u0130yi kuruldu\u011funda harika bir kalkan; yanl\u0131\u015f kuruldu\u011funda, sitede masum g\u00f6r\u00fcnen her t\u0131klamay\u0131 bile durdurabilen bir bek\u00e7i.<\/p>\n<p>Benim de ba\u015f\u0131ma geldi. Bir WordPress temas\u0131, iki minik inline script ve bir Laravel projesinde Vite ile canl\u0131 g\u00fcncelleme derken, CSP hepsini duvara toslatt\u0131. Sonra d\u00fc\u015f\u00fcnd\u00fcm ki: \u201cBu i\u015fi sakin sakin toparlayal\u0131m. Nonce en mant\u0131kl\u0131s\u0131 m\u0131, hash nerede i\u015fimize yarar, report-to nas\u0131l devreye girer, inline script\u2019leri nas\u0131l ehlile\u015ftiririz?\u201d Bu yaz\u0131da, aynen bir arkada\u015f muhabbeti gibi, ba\u015ftan sona birlikte y\u00fcr\u00fcyelim. WordPress ve Laravel \u00fczerinde \u00f6rneklerle, <strong>nonce\/hash se\u00e7iminden<\/strong> <strong>report-to<\/strong>\u2019ya, <strong>inline script<\/strong>\u2019leri g\u00fcvenli h\u00e2le getirme yollar\u0131na kadar pratik bir rehber olacak.<\/p>\n<p>Haz\u0131rsan kahveni kap, konsolu a\u00e7, birlikte CSP\u2019yi bir y\u00fck de\u011fil, bir konfor alan\u0131na d\u00f6n\u00fc\u015ft\u00fcrelim.<\/p>\n<h2 id='section-2'><span id=\"CSP_Neyi_Cozer_Neyi_Bozar_Zihinde_Dogru_Cerceveyi_Kurmak\">CSP Neyi \u00c7\u00f6zer, Neyi Bozar? Zihinde Do\u011fru \u00c7er\u00e7eveyi Kurmak<\/span><\/h2>\n<p>CSP asl\u0131nda \u201ckaynaklar\u0131 kimden ve nas\u0131l y\u00fckleyece\u011fimizi\u201d tarif eden bir g\u00fcvenlik politikas\u0131. Bir nevi siteye g\u00fcvenlikten anlayan bir bek\u00e7i koymak gibi. Bu bek\u00e7i bilmedi\u011fi bir kaynaktan script g\u00f6r\u00fcnce i\u00e7eri alm\u0131yor. Bu g\u00fczel; \u00e7\u00fcnk\u00fc k\u00f6t\u00fc niyetli eklenen bir snippet\u2019in etkisini k\u0131r\u0131yor. Ama bir de madalyonun \u00f6b\u00fcr y\u00fcz\u00fc var: Tema kurarken, minik bir <em>onclick<\/em> yazm\u0131\u015fs\u0131n ya da bir eklenti ufak bir inline script basm\u0131\u015f; bek\u00e7i bunu da sevmiyor. \u0130\u015fte can s\u0131kan yer buras\u0131.<\/p>\n<p>Ben bu i\u015fe hep \u015f\u00f6yle yakla\u015f\u0131yorum: \u00d6nce en s\u0131k\u0131 ayarla ba\u015fl\u0131yorum; sonra \u201cger\u00e7ekten\u201d ihtiyac\u0131m olan kap\u0131lar\u0131 tek tek a\u00e7\u0131yorum. \u201cdefault-src &#8216;self&#8217;\u201d gibi dar ba\u015flayan bir politika, bana nerede tak\u0131ld\u0131\u011f\u0131m\u0131 \u00e7ok net g\u00f6steriyor. Ard\u0131ndan script ve style i\u00e7in gerekiyorsa <strong>nonce<\/strong>, de\u011fi\u015fmeyecek minik kodlar i\u00e7in <strong>hash<\/strong>, \u00fc\u00e7\u00fcnc\u00fc parti servisler i\u00e7in spesifik <em>connect-src<\/em>, <em>img-src<\/em> gibi direktiflerle daireyi geni\u015fletiyorum. B\u00f6ylece kontrol bende kal\u0131yor, panik yok.<\/p>\n<p>\u015eunu da s\u00f6yleyeyim: \u201cunsafe-inline\u201d ile i\u015fi bir gecede \u00e7\u00f6z\u00fcp ge\u00e7mek kolay. Ama bu, kap\u0131y\u0131 ard\u0131na kadar a\u00e7mak demek; CSP\u2019den bekledi\u011fimiz g\u00fcvenlik etkisini b\u00fcy\u00fck \u00f6l\u00e7\u00fcde d\u00fc\u015f\u00fcr\u00fcyor. Onun yerine \u201cinline\u201d ihtiya\u00e7lar\u0131 usul usul <strong>nonce<\/strong> veya <strong>hash<\/strong> ile ehlile\u015ftirmek, orta vadede \u00e7ok daha huzurlu bir hayat sunuyor.<\/p>\n<h2 id='section-3'><span id=\"Nonce_mi_Hash_mi_Inline_Scriptlerle_Uyumlu_Yasamanin_Yollari\">Nonce mi Hash mi? Inline Script\u2019lerle Uyumlu Ya\u015faman\u0131n Yollar\u0131<\/span><\/h2>\n<p>Nonce ve hash, inline script\u2019leri \u201cakredite\u201d etmenin iki tatl\u0131 yolu. Nonce, sayfa y\u00fcklenirken rastgele \u00fcretilen bir bilet gibi d\u00fc\u015f\u00fcn\u00fcl\u00fcr. Senin script etiketinin \u00fcst\u00fcne bu bileti (nonce de\u011feri) ili\u015ftirirsin; CSP de \u201ctamam, bu bilet benden, ge\u00e7i\u015f serbest\u201d der. Avantaj\u0131, i\u00e7erik de\u011fi\u015fse bile ayn\u0131 sayfa i\u00e7indeki script nonce\u2019\u0131 ta\u015f\u0131d\u0131\u011f\u0131 s\u00fcrece \u00e7al\u0131\u015f\u0131r. Dezavantaj\u0131, her istekte yeni bir nonce \u00fcretip script etiketlerine takmay\u0131 unutmamal\u0131s\u0131n.<\/p>\n<p>Hash ise i\u00e7eri\u011fin parmak izi. Inline kodun de\u011fi\u015fmezse harika \u00e7al\u0131\u015f\u0131r. Mesela her sayfada ayn\u0131 ufak \u201ctheme switcher\u201d sat\u0131r\u0131n var; bir kere hash\u2019ini al\u0131rs\u0131n, CSP\u2019ye eklersin, bitti. Buradaki d\u00fc\u011f\u00fcm, kodda minicik bir bo\u015fluk de\u011fi\u015fse bile hash\u2019in de\u011fi\u015fmesidir. Otomasyonun yoksa u\u011fra\u015ft\u0131r\u0131r; ama de\u011fi\u015fmeyen snippet\u2019ler i\u00e7in temiz bir \u00e7\u00f6z\u00fcm.<\/p>\n<p>Ben genelde \u015f\u00f6yle yap\u0131yorum: B\u00fcy\u00fck picture\u2019da t\u00fcm script\u2019leri m\u00fcmk\u00fcn oldu\u011funca dosyaya ta\u015f\u0131yorum. Kalan mecburi inline\u2019lar i\u00e7in <strong>nonce<\/strong> kullan\u0131yorum. Bir iki yerde hi\u00e7 de\u011fi\u015fmeyen minicik kodlar varsa, onlar i\u00e7in <strong>hash<\/strong>. B\u00f6ylece ne \u201cunsafe-inline\u201da mecbur kal\u0131yorum, ne de projeyi bo\u011facak kadar kural ekliyorum. Denge tatl\u0131d\u0131r.<\/p>\n<h2 id='section-4'><span id=\"WordPresste_CSP_Enqueue_Dunyasinda_Nonce_Hash_ve_Ufak_Tuzaklar\">WordPress\u2019te CSP: Enqueue D\u00fcnyas\u0131nda Nonce, Hash ve Ufak Tuzaklar<\/span><\/h2>\n<h3><span id=\"Temel_yaklasim_Her_istekte_nonce_uret_scriptstyle_etiketlerine_ilistir\">Temel yakla\u015f\u0131m: Her istekte nonce \u00fcret, script\/style etiketlerine ili\u015ftir<\/span><\/h3>\n<p>WordPress\u2019te i\u015fin kalbi <em>enqueue<\/em> sistemi. Bir sayfada hangi script ve stilin y\u00fcklenece\u011fini buradan y\u00f6netiyoruz. CSP i\u00e7in yakla\u015f\u0131m basit: Her istekte bir nonce \u00fcret, hem yan\u0131t ba\u015fl\u0131\u011f\u0131na (header) koy, hem de WordPress\u2019in bast\u0131\u011f\u0131 script ve style etiketlerine ili\u015ftir. B\u00f6ylece inline yazmak zorunda kald\u0131\u011f\u0131n ufak kodlar da ya\u015famaya devam edebilir.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/\/ functions.php veya bir k\u00fc\u00e7\u00fck mu-plugin\nfunction dc_csp_get_nonce() {\n    static $nonce = null;\n    if ($nonce === null) {\n        $nonce = base64_encode(random_bytes(16));\n    }\n    return $nonce;\n}\n\nadd_action('send_headers', function () {\n    $nonce = dc_csp_get_nonce();\n    $csp = &quot;default-src 'self'; &quot;\n         . &quot;base-uri 'self'; object-src 'none'; frame-ancestors 'self'; &quot;\n         . &quot;img-src 'self' data: blob:; font-src 'self' data:; &quot;\n         . &quot;connect-src 'self'; &quot;\n         . &quot;style-src 'self' 'nonce-{$nonce}'; &quot;\n         . &quot;script-src 'self' 'nonce-{$nonce}'; &quot;\n         . &quot;report-uri https:\/\/rapor.example.com\/csp&quot;;\n\n    header('Content-Security-Policy: ' . $csp);\n});\n\nadd_filter('script_loader_tag', function ($tag) {\n    $nonce = dc_csp_get_nonce();\n    return str_replace('&lt;script &amp;#039;, &quot;&lt;script nonce=&amp;#039;{$nonce}&amp;#039; &quot;, $tag);\n}, 10);\n\nadd_filter(&amp;#039;style_loader_tag&amp;#039;, function ($tag) {\n    $nonce = dc_csp_get_nonce();\n    return str_replace(&amp;#039;&lt;link &amp;#039;, &quot;&lt;link nonce=&amp;#039;{$nonce}&amp;#039; &quot;, $tag);\n}, 10);\n<\/code><\/pre>\n<p>Burada iki kritik nokta var. Birincisi, nonce her istek i\u00e7in taze olmal\u0131. \u0130kincisi, WordPress\u2019in bast\u0131\u011f\u0131 t\u00fcm script ve style etiketlerine bu nonce\u2019\u0131 takmay\u0131 unutmamak gerekiyor. \u201cBen inline yazaca\u011f\u0131m, nas\u0131l olacak?\u201d dersen, WordPress\u2019in yeni fonksiyonu imdada yeti\u015fiyor:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/\/ WP 5.7+: inline script basarken nonce verebilirsin\nwp_print_inline_script_tag(\n    'console.log(&quot;Merhaba CSP&quot;);',\n    array( 'nonce' =&gt; dc_csp_get_nonce() )\n);\n<\/code><\/pre>\n<h3><span id=\"Inline_bagimliliklar_onclickten_addEventListenera_minik_goc\">Inline ba\u011f\u0131ml\u0131l\u0131klar: onclick\u2019ten addEventListener\u2019a minik g\u00f6\u00e7<\/span><\/h3>\n<p>WordPress temalar\u0131nda s\u0131k g\u00f6rd\u00fc\u011f\u00fcm \u015feylerden biri, HTML etiketlerinin \u00fcst\u00fcnde <em>onclick<\/em>, <em>onchange<\/em> gibi inline event\u2019ler. CSP bunu sevmez. \u00c7\u00f6z\u00fcm basit: O event\u2019leri kald\u0131r, ilgili elementi bir id veya data-attribute ile i\u015faretle, a\u00e7\u0131l\u0131\u015fta bir <em>addEventListener<\/em> ile ba\u011fla. \u0130lk ba\u015fta zahmetli gibi g\u00f6r\u00fcn\u00fcr; ama d\u00fczenli bir yap\u0131ya ge\u00e7ince, tema zaten daha okunakl\u0131 oluyor.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">&lt;!-- Eskiden --&gt;\n&lt;button id='buy' onclick='addToCart()'&gt;Sepete Ekle&lt;\/button&gt;\n\n&lt;!-- Sonra --&gt;\n&lt;button id='buy' data-action='add-to-cart'&gt;Sepete Ekle&lt;\/button&gt;\n\n&lt;script nonce='...'\n&gt;document.querySelector('[data-action=&quot;add-to-cart&quot;]').addEventListener('click', addToCart);&lt;\/script&gt;\n<\/code><\/pre>\n<h3><span id=\"Emoji_oEmbed_ve_ufak_surprizler\">Emoji, oEmbed ve ufak s\u00fcrprizler<\/span><\/h3>\n<p>WordPress baz\u0131 sayfalara otomatik inline kodlar serpi\u015ftirebiliyor. Emoji alg\u0131lama script\u2019i, oEmbed \u00f6nizlemelerinin baz\u0131 dokunu\u015flar\u0131 derken CSP \u201cdur bakal\u0131m\u201d diyebilir. \u0130htiyac\u0131n yoksa bu \u00f6zellikleri kapatmak rahatlat\u0131r.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/\/ Emoji script ve stilini kapat\nremove_action('wp_head', 'print_emoji_detection_script', 7);\nremove_action('wp_print_styles', 'print_emoji_styles');\n<\/code><\/pre>\n<p>\u00dc\u00e7\u00fcnc\u00fc parti servisler (analitik, harita, chat widget\u2019lar\u0131) i\u00e7in de do\u011fru <em>script-src<\/em> ve <em>connect-src<\/em> domain\u2019lerini CSP\u2019ye eklemek gerekir. E\u011fer etiketi dosya olarak y\u00fckl\u00fcyorsan, nonce ta\u015f\u0131mas\u0131na gerek yok. Ama beklenmedik bir inline snippet bas\u0131yorsa, onun i\u00e7in nonce veya hash d\u00fc\u015f\u00fcnmelisin.<\/p>\n<h3><span id=\"Hash_ile_degismeyen_kucuk_snippetler\">Hash ile de\u011fi\u015fmeyen k\u00fc\u00e7\u00fck snippet\u2019ler<\/span><\/h3>\n<p>Hi\u00e7 de\u011fi\u015fmeyen k\u00fc\u00e7\u00fcc\u00fck bir inline kodun varsa, hash yakla\u015f\u0131m\u0131 p\u00fcr\u00fczs\u00fcz \u00e7al\u0131\u015f\u0131r. \u00d6rne\u011fin:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">$snippet  = &quot;document.body.classList.add('ready');&quot;;\n$sha256   = base64_encode(hash('sha256', $snippet, true));\n$csp_part = &quot;'sha256-{$sha256}'&quot;; \/\/ script-src'ye ekle\n<\/code><\/pre>\n<p>Burada \u00f6nemli olan, snippet\u2019in birebir ayn\u0131 olmas\u0131. Bo\u015fluk bile de\u011fi\u015firse hash uymayacak. Bunun i\u00e7in snippet\u2019i bir dosyaya ta\u015f\u0131y\u0131p build s\u00fcrecinde hash \u00fcretmek, sonra CSP\u2019ye enjekte etmek temiz bir pratik.<\/p>\n<h2 id='section-5'><span id=\"Laravelde_CSP_Middleware_Blade_ve_ViteLivewire_Uyumunu_Kurmak\">Laravel\u2019de CSP: Middleware, Blade ve Vite\/Livewire Uyumunu Kurmak<\/span><\/h2>\n<h3><span id=\"Middleware_ile_merkezi_politika_request_basina_nonce\">Middleware ile merkezi politika, request ba\u015f\u0131na nonce<\/span><\/h3>\n<p>Laravel\u2019de en sevdi\u011fim yakla\u015f\u0131m, bir middleware ile tek merkezden CSP \u00fcretmek. Request ba\u015f\u0131na nonce \u00fcret, hem header\u2019a koy hem de Blade\u2019e ta\u015f\u0131. B\u00f6ylece layout i\u00e7inde bast\u0131\u011f\u0131n script\u2019ler kolayca uyumlan\u0131r.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/\/ app\/Http\/Middleware\/ContentSecurityPolicy.php\nnamespace AppHttpMiddleware;\n\nuse Closure;\n\nclass ContentSecurityPolicy\n{\n    public function handle($request, Closure $next)\n    {\n        $nonce = base64_encode(random_bytes(16));\n        app()-&gt;instance('csp_nonce', $nonce);\n\n        $response = $next($request);\n\n        $policy = &quot;default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'; &quot;\n                . &quot;img-src 'self' data: blob:; font-src 'self' data:; &quot;\n                . &quot;connect-src 'self' https:\/\/api.example.com; &quot;\n                . &quot;style-src 'self' 'nonce-{$nonce}'; &quot;\n                . &quot;script-src 'self' 'nonce-{$nonce}'; &quot;\n                . &quot;report-uri https:\/\/rapor.example.com\/csp; report-to csp&quot;;\n\n        \/\/ Reporting-Endpoints (yeni d\u00fcnyaya bir kap\u0131)\n        $response-&gt;headers-&gt;set('Reporting-Endpoints', &quot;csp='https:\/\/rapor.example.com\/reports'&quot;);\n        $response-&gt;headers-&gt;set('Content-Security-Policy', $policy);\n\n        return $response;\n    }\n}\n<\/code><\/pre>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/\/ app\/Providers\/AppServiceProvider.php\nuse IlluminateSupportFacadesVite;\n\npublic function boot()\n{\n    if (function_exists('csp_nonce')) {\n        Vite::useCspNonce(csp_nonce());\n    }\n}\n<\/code><\/pre>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/\/ app\/helpers.php (\u00f6rnek yard\u0131mc\u0131)\nif (! function_exists('csp_nonce')) {\n    function csp_nonce(): string\n    {\n        return app('csp_nonce') ?? '';\n    }\n}\n<\/code><\/pre>\n<p>Art\u0131k Blade\u2019de nonce kullanmak kolay:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">&lt;script nonce='{{ csp_nonce() }}'&gt;window.appReady = true;&lt;\/script&gt;\n<\/code><\/pre>\n<h3><span id=\"Vite_Livewire_Alpine_ve_arkadaslari\">Vite, Livewire, Alpine ve arkada\u015flar\u0131<\/span><\/h3>\n<p>Vite kulland\u0131\u011f\u0131nda, Laravel\u2019in <em>Vite::useCspNonce()<\/em> deste\u011fi i\u015fini ciddi kolayla\u015ft\u0131r\u0131r. \u00dcretti\u011fin nonce otomatik script etiketine ta\u015f\u0131n\u0131r. Livewire\/Alpine taraf\u0131nda, inline event\u2019leri m\u00fcmk\u00fcn oldu\u011funca terk edip, komponentlerin kendi ya\u015fam d\u00f6ng\u00fcs\u00fcnde <em>addEventListener<\/em> ile ba\u011flanmak i\u015fleri p\u00fcr\u00fczs\u00fcz yapar. E\u011fer Livewire s\u00fcr\u00fcm\u00fcnde nonce ta\u015f\u0131ma deste\u011fi zay\u0131fsa, inline yerine <em>defer<\/em> y\u00fckl\u00fc harici bir JS dosyas\u0131yla davran\u0131\u015f\u0131 d\u0131\u015far\u0131 almay\u0131 d\u00fc\u015f\u00fcn. Genelde bir iki d\u00fczenleme ile b\u00fct\u00fcn komponentler CSP ile bar\u0131\u015f\u0131yor.<\/p>\n<h3><span id=\"Hashler_nerede_isimize_yarar\">Hash\u2019ler nerede i\u015fimize yarar?<\/span><\/h3>\n<p>Laravel projesinde hi\u00e7 de\u011fi\u015fmeyen bir iki minik inline kod varsa, build a\u015famas\u0131nda hash \u00fcretip politika i\u00e7ine g\u00f6mmek ferahlat\u0131c\u0131d\u0131r. Mesela bir Blade par\u00e7as\u0131nda 20 karakterlik bir helper scriptin varsa, onu bir sabit gibi d\u00fc\u015f\u00fcn, hash\u2019le, CSP\u2019ye ekle. B\u00f6ylece hem \u201cunsafe-inline\u201da bula\u015fmazs\u0131n, hem de deployment s\u0131ras\u0131nda s\u00fcrpriz ya\u015famazs\u0131n.<\/p>\n<h2 id='section-6'><span id=\"Raporlama_report-to_report-uri_ve_Ihlalleri_Sakin_Sakin_Izlemek\">Raporlama: report-to, report-uri ve \u0130hlalleri Sakin Sakin \u0130zlemek<\/span><\/h2>\n<p>CSP\u2019nin gizli kahraman\u0131 raporlama. Bir \u015fey blokland\u0131\u011f\u0131nda taray\u0131c\u0131 bir rapor yollar; sen de nerede tak\u0131ld\u0131\u011f\u0131n\u0131 g\u00f6r\u00fcrs\u00fcn. Burada iki yol var: <strong>report-uri<\/strong> ve <strong>report-to<\/strong>. Bir\u00e7ok taray\u0131c\u0131 h\u00e2l\u00e2 <em>report-uri<\/em>\u2019yi destekliyor, baz\u0131lar\u0131 ise yeni <em>report-to<\/em> yakla\u015f\u0131m\u0131na kap\u0131 a\u00e7\u0131yor. Pratikte ikisini birden koymak, ge\u00e7i\u015f d\u00f6nemlerinde huzur veriyor.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/\/ \u00d6rnek header par\u00e7alar\u0131\nContent-Security-Policy: ...; report-uri https:\/\/rapor.example.com\/csp; report-to csp\nReporting-Endpoints: csp='https:\/\/rapor.example.com\/reports'\n<\/code><\/pre>\n<p>Report endpoint i\u015fi i\u00e7in ister kendi ufak bir endpoint\u2019ini yaz, ister bir hizmet kullan. Ben bazen test a\u015famas\u0131nda h\u0131zl\u0131ca <a href=\"https:\/\/report-uri.com\/\" rel=\"nofollow noopener\" target=\"_blank\">rapor toplama hizmetleri<\/a> ile ba\u015flar, sonra \u00fcretimde kendi basit endpoint\u2019ime ge\u00e7erim. B\u00f6ylece \u00fc\u00e7\u00fcnc\u00fc partiye ba\u011f\u0131ml\u0131l\u0131k azal\u0131r. Raporlar\u0131n s\u0131k gelece\u011fini unutma; log rotasyon, basit bir filtreleme ve \u201c\u015fu domainleri zaten biliyoruz\u201d t\u00fcr\u00fc beyaz liste ufkunu geni\u015fletir.<\/p>\n<p>CSP direktiflerinin detaylar\u0131na tak\u0131ld\u0131\u011f\u0131nda, k\u0131sa ve net anlat\u0131mlar\u0131 i\u00e7in <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/CSP\" rel=\"nofollow noopener\" target=\"_blank\">MDN\u2019nin CSP sayfas\u0131<\/a> ger\u00e7ekten nefes ald\u0131r\u0131r. Ayr\u0131ca <a href=\"https:\/\/web.dev\/articles\/csp\" rel=\"nofollow noopener\" target=\"_blank\">web.dev \u00fczerinde CSP rehberi<\/a> pratik notlarla iyi bir tamamlay\u0131c\u0131.<\/p>\n<h2 id='section-7'><span id=\"Sunucu_Basliklari_CDN_ve_Dagitim_Rutinleri_Is_Sahada_Bitiyor\">Sunucu Ba\u015fl\u0131klar\u0131, CDN ve Da\u011f\u0131t\u0131m Rutinleri: \u0130\u015f Sahada Bitiyor<\/span><\/h2>\n<h3><span id=\"NginxApacheProxy_Basligi_nerede_set_edecegiz\">Nginx\/Apache\/Proxy: Ba\u015fl\u0131\u011f\u0131 nerede set edece\u011fiz?<\/span><\/h3>\n<p>Benim rutinim \u015fu: Geli\u015ftirme a\u015famas\u0131nda framework ile CSP\u2019yi set ederim (WordPress\u2019te PHP, Laravel\u2019de middleware). \u00dcretimde ise \u00f6n\u00fcndeki Nginx\/Apache katman\u0131na da bir \u201cminimum garanti\u201d politikas\u0131 koyar\u0131m. \u00d6rne\u011fin maintenance sayfas\u0131 veya framework\u2019e u\u011framadan d\u00f6nen statik bir hata sayfas\u0131 bile en temel CSP\u2019ye sahip olsun. B\u00f6ylece ola\u011fan\u00fcst\u00fc durumlarda bile \u00e7\u0131plak kalmam.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Nginx \u00f6rne\u011fi (temel politika)\nadd_header Content-Security-Policy &quot;default-src 'self'; object-src 'none'; base-uri 'self'&quot; always;\n<\/code><\/pre>\n<p>CDN kullan\u0131yorsan, header\u2019lar\u0131n cache\u2019lenme davran\u0131\u015f\u0131n\u0131 unutma. Baz\u0131 CDN\u2019ler yan\u0131t ba\u015fl\u0131klar\u0131n\u0131 farkl\u0131 \u015fekillerde normalize edebilir. Bir de \u201cHTML sadece bu sunucudan gelir\u201d diyip, JS\/CSS\u2019yi CDN\u2019den \u00e7ekiyorsan, <em>script-src<\/em> ve <em>style-src<\/em> i\u00e7in ilgili domainleri mutlaka ekleme listesinde tut. G\u00fcvenli ve sade.<\/p>\n<h3><span id=\"Guvenlik_katmanlarini_yan_yana_dizmek\">G\u00fcvenlik katmanlar\u0131n\u0131 yan yana dizmek<\/span><\/h3>\n<p>CSP, tek ba\u015f\u0131na her derdin ilac\u0131 de\u011fil. Ben genelde onu, TLS\u2019in do\u011fru ayarland\u0131\u011f\u0131, kaynak sunucunun kimli\u011finin ger\u00e7ekten do\u011fruland\u0131\u011f\u0131 bir dizinin par\u00e7as\u0131 yap\u0131yorum. Mesela <a href=\"https:\/\/www.dchost.com\/blog\/origini-korumak-cloudflare-authenticated-origin-pulls-ve-mtls-ile-gercek-kaynak-dogrulamasi\/\">kayna\u011f\u0131 ger\u00e7ekten korumak i\u00e7in mTLS ve origin do\u011frulamas\u0131<\/a> gibi pratikler yan\u0131nda CSP de oturdu mu, trafik hatlar\u0131n\u0131 sa\u011flamla\u015ft\u0131rm\u0131\u015f oluyorsun. Katmanl\u0131 g\u00fcvenlik, k\u00fc\u00e7\u00fck aksiliklerde bile sistemin ayakta kalmas\u0131n\u0131 sa\u011fl\u0131yor.<\/p>\n<h2 id='section-8'><span id=\"Kucuk_Pratikler_Inlinei_Azalt_Davranisi_Tasi_Ihlali_Izle\">K\u00fc\u00e7\u00fck Pratikler: Inline\u2019\u0131 Azalt, Davran\u0131\u015f\u0131 Ta\u015f\u0131, \u0130hlali \u0130zle<\/span><\/h2>\n<p>Bir projeyi CSP\u2019ye ge\u00e7irmek, bazen tek bir ak\u015famda y\u00f6netilebilir. Ben ufak bir yol haritas\u0131 izliyorum. \u00d6nce sitede inline event\u2019leri ay\u0131kl\u0131yorum. K\u00fc\u00e7\u00fck script\u2019leri dosyalara ta\u015f\u0131yorum. CSS i\u00e7inde inline stil patlam\u0131\u015fsa, kritik olanlar\u0131 bir dosyaya \u00e7ekiyorum. Bu ad\u0131mlar tek ba\u015f\u0131na politikay\u0131 sadele\u015ftiriyor.<\/p>\n<p>Sonra raporlama ile k\u00fc\u00e7\u00fck yamalar\u0131 yap\u0131yorum. \u201c\u015eu domain connect-src\u2019ye eklenmeli, bu avatar URL\u2019si img-src\u2019de data: gerekiyor, \u015fu font i\u00e7in font-src self + data: yeter\u201d gibi. \u00dc\u00e7\u00fcnc\u00fc parti servisleri kontroll\u00fc eklemek, \u201cbir kerelik\u201d denilen snippet\u2019lerin kal\u0131c\u0131 davranmad\u0131\u011f\u0131n\u0131 da g\u00f6rmeye yar\u0131yor. Ge\u00e7ici i\u015f i\u00e7in ge\u00e7ici izin; kal\u0131c\u0131 olan i\u00e7in kal\u0131c\u0131 kural.<\/p>\n<p>Bir de ekip ileti\u015fimi. CSP devredeyken herkes ufak bir fark\u0131ndal\u0131\u011fa al\u0131\u015f\u0131yor. Tasar\u0131mc\u0131 inline stil yazaca\u011f\u0131n\u0131 bildi\u011finde, bir dosyaya koymay\u0131 art\u0131k refleks h\u00e2line getiriyor. Geli\u015ftirici onclick yerine event listener\u2019\u0131 tercih ediyor. \u0130\u015fte o zaman CSP g\u00f6r\u00fcnmez bir yard\u0131mc\u0131 oluyor; g\u00f6r\u00fcn\u00fcr oldu\u011funda genelde bir \u015fey bozulur \u00e7\u00fcnk\u00fc.<\/p>\n<h2 id='section-9'><span id=\"Ornek_Politikalar_Baslangic_Icin_Tatli_Bir_Taban\">\u00d6rnek Politikalar: Ba\u015flang\u0131\u00e7 \u0130\u00e7in Tatl\u0131 Bir Taban<\/span><\/h2>\n<p>Ba\u015flang\u0131\u00e7ta i\u015f g\u00f6recek, sonra projeye g\u00f6re k\u0131v\u0131rabilece\u011fin bir politika \u015f\u00f6yle durabilir. Bunu birebir al\u0131p kullanmak yerine, kendi domain\u2019lerini ve ihtiya\u00e7lar\u0131n\u0131 i\u015fleyerek ilerle:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">Content-Security-Policy:\n  default-src 'self';\n  base-uri 'self';\n  object-src 'none';\n  frame-ancestors 'self';\n  img-src 'self' data: blob:;\n  font-src 'self' data:;\n  connect-src 'self';\n  style-src 'self' 'nonce-...';\n  script-src 'self' 'nonce-...' 'strict-dynamic';\n  report-uri https:\/\/rapor.example.com\/csp;\n  report-to csp\n\nReporting-Endpoints:\n  csp='https:\/\/rapor.example.com\/reports'\n<\/code><\/pre>\n<p>Buradaki <em>strict-dynamic<\/em>, nonce\u2019l\u0131 bir script\u2019in dinamik olarak y\u00fckledi\u011fi di\u011fer script\u2019lere de g\u00fcven dairesini a\u00e7ar. Her zaman gerekli de\u011fil, ama baz\u0131 SPA d\u00fczenlerinde i\u015fleri azalt\u0131r. Yine de, \u201cgereksiz yere kap\u0131 a\u00e7t\u0131m m\u0131?\u201d diye bir d\u00f6n\u00fcp bakmakta fayda var.<\/p>\n<h2 id='section-10'><span id=\"Kapanis_CSPyi_Gundelik_Hayata_Katmak\">Kapan\u0131\u015f: CSP\u2019yi G\u00fcndelik Hayata Katmak<\/span><\/h2>\n<p>\u00d6zetle, CSP ilk bak\u0131\u015fta \u00fcrk\u00fctebilir. Ama sakin bir planla yakla\u015f\u0131nca, g\u00fcn\u00fcn sonunda kontrol\u00fcn sende oldu\u011fu, s\u00fcrprizlerin azald\u0131\u011f\u0131 bir d\u00fczen kuruyorsun. WordPress taraf\u0131nda enqueue akl\u0131n\u0131 ve <em>wp_print_inline_script_tag<\/em>\u2019i kullan\u0131p request ba\u015f\u0131na nonce \u00fcretmek, en s\u0131k kar\u015f\u0131la\u015ft\u0131\u011f\u0131m dertlerin \u00e7o\u011funu \u00e7\u00f6z\u00fcyor. Laravel\u2019de middleware ile merkezi bir politika, Blade\u2019de nonce, Vite i\u00e7in <em>Vite::useCspNonce<\/em> gibi mekanizmalarla i\u015f ray\u0131na oturuyor.<\/p>\n<p>Pratik tavsiyem \u015fu: \u00d6nce en s\u0131k\u0131 m\u00fcmk\u00fcn tabloyla ba\u015fla, raporlamay\u0131 a\u00e7, sonra ihtiyaca g\u00f6re gev\u015fet. Inline\u2019lar\u0131 olabildi\u011fince dosyalara ta\u015f\u0131, mecburi kalanlar i\u00e7in nonce veya hash kullan. \u00dc\u00e7\u00fcnc\u00fc parti servisleri tek tek d\u00fc\u015f\u00fcn; hepsi ger\u00e7ekten gerekli mi? Raporlar\u0131 izlerken sab\u0131rl\u0131 ol; ilk g\u00fcnler biraz g\u00fcr\u00fclt\u00fc olur, sonra sessizlik g\u00fczelle\u015fir.<\/p>\n<p>Umar\u0131m bu yaz\u0131 elini rahatlatt\u0131. Bir dahaki deploy\u2019da konsolda k\u0131rm\u0131z\u0131 uyar\u0131 yerine sakin bir \u201cAll good\u201d g\u00f6rmek isterim. Akl\u0131na tak\u0131lan bir durum olursa, bir sonraki yaz\u0131da ya da mesaj kutusunda g\u00f6r\u00fc\u015f\u00fcr\u00fcz. G\u00fcvenli\u011fi katmanl\u0131 kurarken, CSP\u2019yi do\u011fru yerle\u015ftirmek m\u00fcthi\u015f bir fark yarat\u0131yor. Bu arada g\u00fcvenlik katmanlar\u0131n\u0131 derinle\u015ftirmek istersen, <a href=\"https:\/\/www.dchost.com\/blog\/origini-korumak-cloudflare-authenticated-origin-pulls-ve-mtls-ile-gercek-kaynak-dogrulamasi\/\">origin do\u011frulamas\u0131 ile kayna\u011f\u0131 ger\u00e7ekten korumaya<\/a> da g\u00f6z atabilirsin. G\u00fczel bir tamamlay\u0131c\u0131.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>\u0130&ccedil;indekiler1 Giri\u015f: Bir Script, Bir Kahve ve K\u00fc\u00e7\u00fck Bir Panik2 CSP Neyi \u00c7\u00f6zer, Neyi Bozar? Zihinde Do\u011fru \u00c7er\u00e7eveyi Kurmak3 Nonce mi Hash mi? Inline Script\u2019lerle Uyumlu Ya\u015faman\u0131n Yollar\u01314 WordPress\u2019te CSP: Enqueue D\u00fcnyas\u0131nda Nonce, Hash ve Ufak Tuzaklar4.1 Temel yakla\u015f\u0131m: Her istekte nonce \u00fcret, script\/style etiketlerine ili\u015ftir4.2 Inline ba\u011f\u0131ml\u0131l\u0131klar: onclick\u2019ten addEventListener\u2019a minik g\u00f6\u00e74.3 Emoji, oEmbed ve [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1996,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-1995","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-teknoloji"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts\/1995","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/comments?post=1995"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts\/1995\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/media\/1996"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/media?parent=1995"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/categories?post=1995"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/tags?post=1995"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}