Dokumentacija

Dodajte varnostne glave

Dodajte varnostne glave

Nekaj glav v odgovoru brskalniku pove, kako naj zaščiti vaše obiskovalce: katere skripte sme zagnati, ali sme ugibati vrsto datoteke, ali sme druga stran vašo stran naložiti v okvir in koliko naslova posreduje naprej, ko nekdo klikne povezavo. Brez njih ena sama podtaknjena skripta ali skrit okvir na tuji strani (clickjacking) proti vašim obiskovalcem deluje točno tako, kot je napadalec načrtoval.

Pošiljanje glav ne stane nič in nihče jih ne opazi, dokler ena od njih ne ustavi napada. Kontrolni seznam strani preveri štiri osnovne.

Kaj kontrolni seznam preveri

Glava Varna vrednost za začetek Kaj naredi
Content-Security-Policy frame-ancestors 'self'; base-uri 'self'; object-src 'none' Omeji, kaj sme stran naložiti in kdo jo sme prikazati v okviru
X-Content-Type-Options nosniff Brskalnik besedilne datoteke ne sme obravnavati kot skripte
X-Frame-Options SAMEORIGIN Stran v okviru sme prikazati samo vaša lastna stran
Referrer-Policy strict-origin-when-cross-origin Druge strani vidijo samo vašo domeno, ne celotnega naslova

X-Frame-Options šteje kot prisotna tudi, kadar Content-Security-Policy vsebuje frame-ancestors, ki je njena sodobna zamenjava. Če pošljete obe, ne škodi.

Content-Security-Policy začnite majhno

Celoten Content-Security-Policy našteje vse domene, s katerih sme stran nalagati skripte, sloge, pisave in slike. Če se zmotite, brskalnik tiho blokira Google Tag Manager, analitiko, pasico za piškotke, klepetalnike ali plačilne obrazce. Zato je vrednost v zgornji tabeli namenoma majhna: nadzoruje okvirje, oznako <base> in stare vtičnike (<object>), skript pa se ne dotika. GTM-ja ne more pokvariti.

Če želite pravilnik, ki nadzoruje tudi skripte, ga zgradite v dveh korakih:

  1. Najprej ga pošljite kot Content-Security-Policy-Report-Only, poleg majhne glave, ki velja. Brskalnik ne blokira ničesar, vsaka kršitev pa se pokaže v razvijalski konzoli (F12 → Console).
  2. Nekaj dni brskajte po strani, tudi po blagajni, obrazcih in straneh z vdelano vsebino, in vsako domeno, ki jo vidite, dodajte v pravilnik. Najtežji del je GTM: vsaka oznaka, ki jo dodate v GTM, lahko nalaga z nove domene, zato je treba strog pravilnik posodobiti ob vsaki novi oznaki.

Šele nato ime glave zamenjajte s Content-Security-Policy. Kontrolni seznam šteje samo glavo, ki velja; sam Report-Only ostane rumen.

Opozorilo: Strogega CSP-ja ne kopirajte z druge spletne strani. Njen seznam dovoljenih domen ni vaš, in prvo, kar pokvari, sta običajno analitika ali plačila, kamor nihče ne pogleda, dokler številke ne padejo.

Preverite sami

Namesto example.com vpišite svojo stran:

curl -sI https://example.com | grep -iE '^(content-security-policy|x-content-type-options|x-frame-options|referrer-policy):'

Videti morate vse štiri vrstice (ali tri, če Content-Security-Policy vsebuje frame-ancestors). Glava, ki se pojavi dvakrat z različnima vrednostma, običajno pomeni, da je nastavljena na dveh mestih, na primer na strežniku in v vtičniku. Obdržite eno.

Kako popraviti

Izberite mesto, do katerega imate dostop. Glave, nastavljene na spletnem strežniku ali CDN-ju, pokrijejo vse strani in vse datoteke, tudi strani iz predpomnilnika, zato imajo prednost pred CMS-jem.

WordPress

WordPress za te glave nima nastavitve. Dodajte jih z brezplačnim vtičnikom Code Snippets (Snippets → Add New, izvajanje povsod) ali na konec datoteke functions.php v podrejeni temi (child theme):

add_action('send_headers', function () {
    header("Content-Security-Policy: frame-ancestors 'self'; base-uri 'self'; object-src 'none'");
    header('X-Content-Type-Options: nosniff');
    header('X-Frame-Options: SAMEORIGIN');
    header('Referrer-Policy: strict-origin-when-cross-origin');
});

To se izvede samo, kadar odgovor sestavi WordPress sam. Vtičniki za predpomnjenje, kot sta WP Rocket ali LiteSpeed Cache, pogosto postrežejo shranjeno kopijo strani, ne da bi zagnali PHP, in ta kopija gre ven brez glav. Če preverjanje glave po tem, ko počistite predpomnilnik, še vedno pogreša, jih nastavite na strežniku ali v Cloudflaru (glejte ta zavihka).

cPanel

cPanel nima zaslona za glave odgovora. Dodajte jih na vrh datoteke .htaccess v korenski mapi strani (File Manager, z vklopljenim Show Hidden Files):

<IfModule mod_headers.c>
    Header always set Content-Security-Policy "frame-ancestors 'self'; base-uri 'self'; object-src 'none'"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>

To deluje na Apachu in na LiteSpeedu, ki .htaccess bere enako. Shranite in poženite preverjanje. Če se ni nič spremenilo, ima gostitelj mod_headers izklopljen; podporo prosite, naj ga vklopi.

Plesk

Websites & Domains → example.com → Apache & nginx Settings, v Additional nginx directives dodajte:

add_header Content-Security-Policy "frame-ancestors 'self'; base-uri 'self'; object-src 'none'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Kliknite OK; Plesk preveri sintakso in znova naloži nginx. Če katero od teh glav že pošilja aplikacija na strani (vtičnik WordPressa, ogrodje), jo bo odgovor vseboval dvakrat. Odstranite jo na enem od obeh mest.

nginx

Glave dodajte v blok server { … } strani: na Debianu in Ubuntuju v /etc/nginx/sites-available/example.com, na Rocky, Alma in CentOS v /etc/nginx/conf.d/example.com.conf:

server {
    # …
    add_header Content-Security-Policy "frame-ancestors 'self'; base-uri 'self'; object-src 'none'" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}

always jih doda tudi stranem z napako in preusmeritvam. Pazite na eno past nginxa: blok location z lastnim add_header (na primer za glave predpomnjenja) za datoteke, ki jih zajame, zavrže vse glave z ravni server. V takem bloku štiri vrstice ponovite ali jih hranite v ločeni datoteki in jo z include vključite na obeh mestih.

sudo nginx -t && sudo systemctl reload nginx

Apache in LiteSpeed

Z dostopom do strežnika (Apache). Vklopite mod_headers (na Debianu in Ubuntuju: sudo a2enmod headers) in glave dodajte v <VirtualHost *:443> strani: na Debianu in Ubuntuju v /etc/apache2/sites-available/example.com-le-ssl.conf ali podobno, na Rocky, Alma in CentOS v /etc/httpd/conf.d/:

Header always set Content-Security-Policy "frame-ancestors 'self'; base-uri 'self'; object-src 'none'"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
sudo apachectl configtest && sudo systemctl reload apache2

(Na Rocky, Alma in CentOS httpd namesto apache2.)

Brez dostopa do strežnika (deljeno gostovanje, LiteSpeed). Iste štiri vrstice dodajte v .htaccess v korenu strani, ovite v <IfModule mod_headers.c> … </IfModule> kot v zavihku cPanel.

Cloudflare

Če stran teče za Cloudflarom (oranžen oblak), lahko Cloudflare glave doda tudi na brezplačnem paketu, za vse strani in datoteke, ne glede na to, kaj pošlje izvorni strežnik:

  1. Odprite domeno in pojdite na Rules → Transform Rules → Modify Response Header.
  2. Create rule, poimenujte ga Security headers in ga uporabite za All incoming requests.
  3. Dodajte štiri vnose s Set static: ime glave in vrednost kot v zgornji tabeli (na primer X-Content-Type-Options in nosniff), nato kliknite Deploy.

Cloudflare ima tudi upravljano transformacijo Add security headers. Ta nastavi X-Content-Type-Options, X-Frame-Options in Referrer-Policy, ne pa Content-Security-Policy, zato za to glavo pravilo še vedno potrebujete.

Node.js in Next.js

Next.js: v next.config.js:

const securityHeaders = [
    { key: 'Content-Security-Policy', value: "frame-ancestors 'self'; base-uri 'self'; object-src 'none'" },
    { key: 'X-Content-Type-Options', value: 'nosniff' },
    { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
    { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
];

module.exports = {
    async headers() {
        return [{ source: '/:path*', headers: securityHeaders }];
    },
};

Express: majhen middleware pred vašimi potmi:

app.use((req, res, next) => {
    res.set({
        'Content-Security-Policy': "frame-ancestors 'self'; base-uri 'self'; object-src 'none'",
        'X-Content-Type-Options': 'nosniff',
        'X-Frame-Options': 'SAMEORIGIN',
        'Referrer-Policy': 'strict-origin-when-cross-origin',
    });
    next();
});

Priljubljeni paket helmet te in še druge glave nastavi v eni vrstici, vendar je njegov privzeti Content-Security-Policy strog in blokira skripte z drugih domen, tudi Google Tag Manager. Preden se nanj zanesete, nastavite njegovo možnost contentSecurityPolicy.

Laravel

Ustvarite middleware, na primer app/Http/Middleware/SecurityHeaders.php:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class SecurityHeaders
{
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        $response->headers->set('Content-Security-Policy', "frame-ancestors 'self'; base-uri 'self'; object-src 'none'");
        $response->headers->set('X-Content-Type-Options', 'nosniff');
        $response->headers->set('X-Frame-Options', 'SAMEORIGIN');
        $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');

        return $response;
    }
}

Registrirajte ga za vse zahtevke v bootstrap/app.php (Laravel 11 in novejši):

->withMiddleware(function (Middleware $middleware) {
    $middleware->append(\App\Http\Middleware\SecurityHeaders::class);
})

Datoteke v public/ (CSS, JavaScript, slike) streže spletni strežnik brez Laravela, zato teh glav ne dobijo. Za kontrolni seznam je to v redu: ta pogleda stran.

IIS in ASP.NET

V datoteki web.config strani:

<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Content-Security-Policy" value="frame-ancestors 'self'; base-uri 'self'; object-src 'none'" />
        <add name="X-Content-Type-Options" value="nosniff" />
        <add name="X-Frame-Options" value="SAMEORIGIN" />
        <add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

Če katero od njih nastavi tudi aplikacija v kodi, IIS pošlje obe vrednosti. Obdržite eno.

Gostovane platforme

Na Shopifyju, Wixu, Squarespaceu in Webflowu glave odgovora pošilja platforma in svojih ne morete dodati. Če kontrolni seznam tam poroča, da glava manjka, na vaši strani ni kaj spremeniti; postavka ostane opozorilo in na nič drugega ne vpliva.

Ko naj bo stran prikazana v okviru

SAMEORIGIN in frame-ancestors 'self' vsem drugim stranem preprečita, da bi vašo stran prikazale v okviru. Če jo partnerska stran, gradnik za rezervacije ali vaša druga domena vdela namenoma, jo naštejte: frame-ancestors 'self' https://example.org. Nato odstranite X-Frame-Options: drugih domen ne zna našteti, starejši brskalniki, ki berejo samo njo, pa bi vdelavo blokirali.

Potrdite popravek

Znova poženite ukaz curl iz razdelka Preverite sami, nato v PulseKeeperju odprite tarčo in na zavihku Kontrolni seznam kliknite Preveri zdaj. Postavka se v nekaj minutah obarva OK, ne šele ob naslednjem dnevnem preverjanju. V brskalniku z odprto konzolo (F12) odprite nekaj strani in se prepričajte, da ni nič blokirano.