Як реалізувати захищені заголовки за допомогою Cloudflare Workers?

Керівництво зі встановлення безпечних HTTP-заголовків за допомогою Cloudflare Workers

Застосування HTTP-заголовків відповіді є важливим кроком для посилення безпеки веб-сайтів. Це допомагає захистити їх від поширених загроз, таких як XSS-атаки, клікджекінг, MIME-сніфінг та інші види міжсайтового впровадження. OWASP, провідна організація з питань веб-безпеки, настійно рекомендує цю практику.

Традиційно, налаштування заголовків HTTP виконувалося на рівні веб-сервера (наприклад, Apache, Nginx, IIS). Однак, якщо ваш сайт використовує Cloudflare для захисту і кешування, можна скористатися потужністю Cloudflare Workers для керування HTTP-заголовками відповіді.

Cloudflare Workers – це безсерверна платформа, яка дозволяє виконувати код JavaScript, C, C++ або Rust безпосередньо в мережі Cloudflare. Код розгортається у понад 200 центрах обробки даних по всьому світу, що забезпечує швидке виконання та мінімальну затримку.

Процес налаштування є простим і гнучким. Ви можете застосувати заголовки до всього веб-сайту, піддоменів або конкретних URI, використовуючи маршрутизацію з підтримкою регулярних виразів.

У цьому посібнику буде використано готовий код, наданий Скоттом Хелме, як відправну точку.

Давайте розпочнемо налаштування!

  • Увійдіть у свій обліковий запис Cloudflare і перейдіть до розділу Workers (можете скористатись прямим посиланням).

  • Скопіюйте вміст файлу worker.js з GitHub і вставте його в редактор 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)));
  

Поки що не зберігайте код, оскільки вам необхідно буде налаштувати заголовки відповідно до ваших потреб.

Content-Security-Policy: Якщо ви бажаєте налаштувати власну політику безпеки, зробіть це тут. Наприклад, якщо потрібно дозволити вбудовування контенту через iFrame з кількох джерел, використовуйте директиву frame-ancestors, як показано нижче:

  "Content-Security-Policy" : "frame-ancestors 'self' gf.dev techukraine.net.com",
  

Цей приклад дозволить відображення контенту з gf.dev, techukraine.net.com та вашого власного веб-сайту.

X-Frame-Options: Якщо ви плануєте відображати контент сайту в iFrame на інших сторінках того ж сайту, змініть значення на SAMEORIGIN.

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

Server: Цей заголовок можна використовувати для очищення або маскування інформації про ваш веб-сервер. Замініть його на бажане значення.

"Server" : "techukraine.net Server",

RemoveHeaders: Якщо потрібно видалити певні заголовки (наприклад, з метою приховати версії програмного забезпечення та зменшити витік інформації), перелічіть їх тут.

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

Додавання нових заголовків: Щоб додати власні заголовки, просто додайте їх у розділ securityHeaders, як у прикладі:

let securityHeaders = {
	"Content-Security-Policy" : "frame-ancestors 'self' gf.dev techukraine.net.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",
}
  

Після завершення налаштування всіх необхідних заголовків, надайте вашому Worker ім’я та натисніть “Зберегти та розгорнути”.

Чудово! Ваш Worker готовий. Тепер потрібно додати його до сайту, де ви бажаєте застосувати заголовки. Я застосую це до свого тестового сайту.

  • Перейдіть до панелі управління Cloudflare та виберіть свій веб-сайт.
  • Перейдіть до розділу Workers >> Add route.
  • Вкажіть URL-адресу, для якої потрібно застосувати Worker (можна використовувати регулярні вирази).
  • Виберіть створеного раніше Worker і збережіть налаштування.

Готово! За кілька секунд ви побачите, що заголовки реалізовано на вашому сайті.

Ось приклад того, як це виглядає в Chrome Dev Tools. Ви також можете перевірити заголовки за допомогою спеціалізованих HTTP-інструментів.

Я не впевнений, чому заголовок Server не відображається. Можливо, Cloudflare його приховує.

Загалом, процес впровадження займає приблизно 15 хвилин і не потребує простою або перезавантаження, як у випадку з Apache або Nginx. Якщо ви плануєте застосувати це в робочому середовищі, рекомендується спочатку протестувати на нижчому середовищі або за допомогою маршруту застосувати на тестових сторінках, щоб перевірити результати. Після перевірки можна застосувати зміни до продакшн.

Це дійсно зручний та ефективний спосіб!

Дякуємо Скотту за наданий код.