Jak zaimplementować bezpieczne nagłówki przy użyciu Cloudflare Workers?

Wdrażanie bezpiecznych nagłówków HTTP za pomocą Cloudflare Workers: Przewodnik krok po kroku

Zabezpieczenie witryny internetowej przed powszechnymi zagrożeniami, takimi jak XSS (Cross-Site Scripting), clickjacking, ataki typu MIMI (Man-in-the-Middle), czy wstrzykiwanie kodu, wymaga starannej implementacji nagłówków odpowiedzi HTTP. To powszechna praktyka, którą zaleca między innymi OWASP.

Wcześniej omawiałem sposoby wdrażania tych nagłówków na serwerach takich jak Apache, Nginx czy IIS. Jednak, jeśli korzystasz z Cloudflare, masz dodatkową możliwość. Platforma Cloudflare Workers umożliwia manipulowanie nagłówkami odpowiedzi HTTP bezpośrednio na serwerach brzegowych Cloudflare.

Cloudflare Workers to bezserwerowa platforma, na której można uruchamiać kod JavaScript, C, C++ czy Rust. Jej globalna sieć obejmuje ponad 200 centrów danych, co zapewnia szybkie i responsywne działanie.

Proces implementacji jest prosty i elastyczny. Możesz stosować nagłówki globalnie dla całej witryny, w obrębie subdomen, lub dla wybranych adresów URI, wykorzystując dopasowywanie wzorców z użyciem wyrażeń regularnych.

W tym poradniku wykorzystam kod udostępniony przez Scotta Helme’a.

Zaczynamy! 👨‍💻

  • Zaloguj się do Cloudflare i wybierz opcję Pracownicy (dostępny bezpośredni link).

  • Skopiuj zawartość pliku worker.js z serwisu GitHub i wklej go do edytora skryptów Cloudflare Workers.
const securityHeaders = {
        "Content-Security-Policy": "upgrade-insecure-requests",
        "Strict-Transport-Security": "max-age=1000",
        "X-Xss-Protection": "1; mode=block",
        "X-Frame-Options": "DENY",
        "X-Content-Type-Options": "nosniff",
        "Referrer-Policy": "strict-origin-when-cross-origin"
    },
    sanitiseHeaders = {
        Server: ""
    },
    removeHeaders = [
        "Public-Key-Pins",
        "X-Powered-By",
        "X-AspNet-Version"
    ];

async function addHeaders(req) {
    const response = await fetch(req),
        newHeaders = new Headers(response.headers),
        setHeaders = Object.assign({}, securityHeaders, sanitiseHeaders);

    if (newHeaders.has("Content-Type") && !newHeaders.get("Content-Type").includes("text/html")) {
        return new Response(response.body, {
            status: response.status,
            statusText: response.statusText,
            headers: newHeaders
        });
    }

    Object.keys(setHeaders).forEach(name => newHeaders.set(name, setHeaders[name]));

    removeHeaders.forEach(name => newHeaders.delete(name));

    return new Response(response.body, {
        status: response.status,
        statusText: response.statusText,
        headers: newHeaders
    });
}

addEventListener("fetch", event => event.respondWith(addHeaders(event.request)));

Zatrzymaj się na chwilę przed zapisaniem. Możesz dostosować poniższe nagłówki do swoich potrzeb.

Content-Security-Policy: Tutaj możesz zdefiniować politykę bezpieczeństwa treści dla swojej aplikacji.

Przykładowo, jeśli chcesz umożliwić osadzanie treści w ramkach iframe z różnych adresów URL, skorzystaj z dyrektywy frame-ancestors:

"Content-Security-Policy" : "frame-ancestors 'self' gf.dev newsblog.pl.com",

Powyższy przykład pozwoli na ładowanie treści z adresów gf.dev, newsblog.pl.com oraz z samej witryny.

X-Frame-Options: Jeśli planujesz umieszczać zawartość swojej witryny w iframe na tej samej domenie, zmień wartość na SAMEORIGIN.

"X-Frame-Options": "SAMEORIGIN",

Server: W tym miejscu możesz usunąć nagłówek informujący o typie serwera. Wpisz tutaj dowolną wartość.

"Server" : "newsblog.pl Server",

RemoveHeaders: Chcesz usunąć niektóre nagłówki w celu ukrycia wersji oprogramowania i zminimalizowania ryzyka wycieku informacji? Możesz to zrobić właśnie tutaj.

let removeHeaders = [
	"Public-Key-Pins",
	"X-Powered-By",
	"X-AspNet-Version",
]

Dodawanie nowych nagłówków: Jeśli potrzebujesz przekazać własne nagłówki, dodaj je w sekcji securityHeaders, jak w przykładzie poniżej.

let securityHeaders = {
	"Content-Security-Policy" : "frame-ancestors 'self' gf.dev newsblog.pl.com",
	"Strict-Transport-Security" : "max-age=1000",
	"X-Xss-Protection" : "1; mode=block",
	"X-Frame-Options" : "SAMEORIGIN",
	"X-Content-Type-Options" : "nosniff",
	"Referrer-Policy" : "strict-origin-when-cross-origin",
        "Custom-Header"  : "Success",
}

Po dostosowaniu wszystkich nagłówków, nadaj nazwę workerowi i kliknij „Zapisz i wdróż”.

Świetnie! Twój worker jest gotowy. Teraz musisz go przypisać do witryny, na której chcesz zastosować te nagłówki. W moim przykładzie użyję mojego środowiska testowego.

  • Przejdź do panelu Cloudflare i wybierz swoją witrynę.
  • W sekcji Pracownicy, kliknij „Dodaj trasę”.
  • W polu „Trasa” wprowadź adres URL, do którego ma być przypisany worker. Możesz użyć wyrażeń regularnych.
  • Wybierz nowo utworzonego workera i zapisz zmiany.

To wszystko. W ciągu kilku sekund zobaczysz, że wszystkie nagłówki zostały poprawnie zaimplementowane na Twojej stronie.

Tak to wygląda w Chrome Dev Tools. Możesz również przetestować nagłówki za pomocą innych narzędzi.

Z jakiegoś powodu nagłówek serwera nie jest widoczny, prawdopodobnie jest zastępowany przez Cloudflare.

Jak widzisz, cała implementacja zajmuje około 15 minut i nie wymaga żadnych przestojów, czy ponownych uruchomień serwera, jak w przypadku Apache lub Nginx. Jeśli planujesz wprowadzić zmiany w środowisku produkcyjnym, zalecam przetestowanie ich w niższym środowisku, lub na stronach testowych. Po uzyskaniu pewności, że wszystko działa poprawnie, możesz przenieść zmiany do produkcji.

To naprawdę świetne rozwiązanie!

Dziękuję Scottowi za udostępniony kod.