Памятка и туториал по HTTP-заголовкам, связанным с безопасностью веб-приложений
В этой статье я хочу поделиться с вами результатами небольшого исследования, посвященного HTTP-заголовкам, которые связаны с безопасностью веб-приложений (далее — просто заголовки).
Сначала мы с вами кратко разберем основные виды уязвимостей веб-приложений, а также основные виды атак, основанные на этих уязвимостях. Далее мы рассмотрим все современные заголовки, каждый — по отдельности. Это в теоретической части статьи.
В практической части мы реализуем простое Express-приложение, развернем его на Heroku и оценим безопасность с помощью WebPageTest и Security Headers . Также, учитывая большую популярность сервисов для генерации статических сайтов, мы настроим и развернем приложение с аналогичным функционалом на Netlify .
Исходный код приложений находится здесь.
Демо Heroku-приложения можно посмотреть здесь, а Netlify-приложения — здесь.
Основными источниками истины при подготовке настоящей статьи для меня послужили следующие ресурсы:
Заголовки безопасности
Все заголовки условно можно разделить на три группы.
Заголовки для сайтов, на которых обрабатываются чувствительные (sensitive) данные пользователей
- Content Security Policy (CSP) ;
- Trusted Types .
Заголовки для всех сайтов
- X-Content-Type-Options ;
- X-Frame-Options ;
- Cross-Origin Resource Policy (CORP) ;
- Cross-Origin Opener Policy (COOP) ;
- HTTP Strict Transport Security (HSTS) .
Заголовки для сайтов с продвинутыми возможностями
Под продвинутыми возможностями в данном случае понимается возможность использования ресурсов сайта другими источниками (origins) или возможность встраивания или внедрения (embedding) сайта в другие приложения. Первое относится к сервисам вроде CDN (Content Delivery Network — сеть доставки и дистрибуции содержимого), второе к сервисам вроде песочниц — специально выделенные (изолированные) среды для выполнения кода. Под источником понимается протокол, хост, домен и порт.
- Cross-Origin Resource Sharing (CORS) ;
- Cross-Origin Embedder Policy (COEP) .
Угрозы безопасности, существующие в вебе
Защита сайта от внедрения кода (injection vulnerabilities)
Угрозы, связанные с возможностью внедрения кода, возникают, когда непроверенные данные, обрабатываемые приложением, могут оказывать влияние на поведение приложения. В частности, это может привести к выполнению скриптов, управляемых атакующим (принадлежащих ему). Наиболее распространенным видом атаки, связанной с внедрением кода, является межсайтовый скриптинг (Cross-Site Scripting, XSS; к слову, сокращение XSS было выбрано во избежание путаницы с CSS ) в различных формах, включая отраженные или непостоянные XSS (reflected XSS), хранимые или постоянные XSS (stored XSS), XSS , основанные на DOM (DOM XSS) и т.д.
XSS может предоставить атакующему полный доступ к пользовательским данным, которые обрабатываются приложением, и к другой информации в пределах источника.
Традиционными способами защиты от XSS являются: автоматическое экранирование шаблонов HTML с помощью специальных инструментов, отказ от использования небезопасных JavaScript API (например, eval() или innerHTML ), хранение данных пользователей в другом источнике и обезвреживание или обеззараживание (sanitizing) данных, поступающих от пользователей, например, через заполнение ими полей формы.
- используйте CSP для определения того, какие скрипты могут выполняться в вашем приложении;
- используйте Trusted Types для обезвреживания данных, передаваемых в небезопасные API ;
- используйте X-Content-Type-Options для предотвращения неправильной интерпретации браузером MIME-типов загружаемых ресурсов.
Изоляция сайта
Открытость веба позволяет сайтам взаимодействовать друг с другом способами, которые могут привести к нарушениям безопасности. Это включает в себя отправку «неожиданных» запросов на аутентификацию или загрузку данных из приложения в документ атакующего, что позволяет последнему читать или даже модифицировать эти данные.
Наиболее распространенными уязвимостями, связанными с общей доступностью приложения, являются кликджекинг (clickjacking), межсайтовая подделка запросов (Cross-Site Request Forgery, XSRF), межсайтовое добавление или включение скриптов (Cross-Site Script Inclusion, XSSI) и различные утечки информации между источниками.
- используйте X-Frame-Options для предотвращения встраивания вашего документа в другие приложения;
- используйте CORP для предотвращения возможности использования ресурсов вашего сайта другими источниками;
- используйте COOP для защиты окон (windows) вашего приложения от взаимодействия с другими приложениями;
- используйте CORS для управления доступом к ресурсам вашего сайта из других источников.
Безопасность сайтов со сложным функционалом
Spectre делает любые данные, загруженные в одну и ту же группу контекста просмотра (browsing context group), потенциально общедоступными, несмотря на правило ограничения домена. Браузеры ограничивают возможности, которые могут привести к нарушению безопасности с помощью среды выполнения кода под названием «межсайтовая изоляция» (Cross-Origin Isolation). Это, в частности, позволяет безопасно использовать такие мощные возможности, как SharedArrayBuffer .
- используйте COEP совместно с COOP для обеспечения межсайтовой изоляции вашего приложения.
Шифрование исходящего трафика
Недостаточное шифрование передаваемых данных может привести к тому, что атакующий, в случае перехвата этих данных, получит информацию о взаимодействии пользователей с приложением.
Неэффективное шифрование может быть обусловлено следующим:
- использование HTTP вместо HTTPS ;
- смешанный контент (когда одни ресурсы загружаются по HTTPS , а другие — по HTTP );
- куки без атрибута Secure или соответствующего префикса (также имеет смысл определять настройку HttpOnly );
- слабая политика CORS .
- используйте HSTS для обслуживания всего контента вашего приложения через HTTPS .
Перейдем к рассмотрению заголовков.
Content Security Policy (CSP)
XSS — это атака, когда уязвимость, существующая на сайте, позволяет атакующему внедрять и выполнять свои скрипты. CSP предоставляет дополнительный слой для отражения таких атак посредством ограничения скриптов, которые могут выполняться на странице.
Инженеры из Google рекомендуют использовать строгий режим CSP . Это можно сделать одним из двух способов:
- если HTML-страницы рендерятся на сервере, следует использовать основанный на случайном значении (nonce-based) CSP ;
- если разметка является статической или доставляется из кеша, например, в случае, когда приложение является одностраничным ( SPA ), следует использовать основанный на хеше (hash-based) CSP .
Пример использования nonce-based CSP:
Использование CSP
Обратите внимание: CSP является дополнительной защитой от XSS-атак, основная защита состоит в обезвреживании данных, вводимых пользователем.
1. Nonce-based CSP
nonce — это случайное число, которое используется только один раз. Если у вас нет возможности генерировать такое число для каждого ответа, тогда лучше использовать hash-based CSP.
Генерируем nonce на сервере для скрипта в ответ на каждый запрос и устанавливаем следующий заголовок:
Затем в разметке устанавливаем каждому тегу script атрибут nonce со значением строки
Хорошим примером использования nonce-based CSP является сервис Google Фото .
В данном случае можно использовать только встроенные скрипты, поскольку большинство браузеров в настоящее время не поддерживает хеширование внешних скриптов.
CSP Evaluator — отличный инструмент для оценки CSP .
- https: — это резервный вариант для Firefox , а unsafe-inline — для очень старых браузеров;
- директива frame-ancestors защищает сайт от кликджекинга, запрещая другим сайтам использовать контент вашего приложения. X-Frame-Options является более простым решением, но frame-ancestors позволяет выполнять тонкую настройку разрешенных источников;
- CSP можно использовать для обеспечения загрузки всех ресурсов по HTTPS . Это не слишком актуально, поскольку в настоящее время большинство браузеров блокирует смешанный контент;
- CSP можно использовать в режиме только для чтения (report-only mode);
- CSP может быть установлен в разметке как мета-тег.
В рассматриваемом заголовке можно использовать следующие директивы:
| Директива | Описание |
|---|---|
| base-uri | Определяет базовый URI для относительных |
| default-src | Определяет политику загрузки ресурсов всех типов при отсутствии специальной директивы (политику по умолчанию) |
| script-src | Определяет скрипты, которые могут выполняться на странице |
| object-src | Определяет, откуда могут загружаться ресурсы — плагины |
| style-src | Определяет стили, которые могут применяться на странице |
| img-src | Определяет, откуда могут загружаться изображения |
| media-src | Определяет, откуда могут загружаться аудио и видеофайлы |
| child-src | Определяет, откуда могут загружаться фреймы |
| frame-ancestors | Определяет, где (в каких источниках) ресурс может загружаться во фреймы |
| font-src | Определяет, откуда могут загружаться шрифты |
| connect-src | Определяет разрешенные URI |
| manifest-src | Определяет, откуда могут загружаться файлы манифеста |
| form-action | Определяет, какие URI могут использоваться для отправки форм (в атрибуте action ) |
| sandbox | Определяет политику песочницы (sandbox policy) HTML , которую агент пользователя применяет к защищенному ресурсу |
| script-nonce | Определяет, что для выполнения скрипта требуется наличие уникального значения |
| plugin-types | Определяет набор плагинов, которые могут вызываться защищенным ресурсом посредством ограничения типов встраиваемых ресурсов |
| reflected-xss | Используется для активации/деактивации эвристических методов браузера для фильтрации или блокировки отраженных XSS-атак |
| block-all-mixed-content | Запрещает загрузку смешанного контента |
| upgrade-insecure-requests | Определяет, что небезопасные ресурсы (загружаемые по HTTP ) должны загружаться по HTTPS |
| report-to | Определяет группу (указанную в заголовке Report-To ), в которую отправляются отчеты о нарушениях политики |
Возможные значения директив для нестрогого режима CSP :
- ‘self’ — ресурсы могут загружаться только из данного источника;
- ‘none’ — запрет на загрузку ресурсов;
- * — ресурсы могут загружаться из любого источника;
- example.com — ресурсы могут загружаться только из example.com .
В данном случае изображения могут быть загружены из любого источника, другие медиафайлы — только с media1.com и media2.com (исключая их поддомены), скрипты — только с example.com .
Trusted Types
XSS , основанный на DOM — это атака, когда вредоносный код передается в приемник, который поддерживает динамическое выполнение кода, такой как eval() или innerHTML .
Trusted Types предоставляет инструменты для создания, модификации и поддержки приложений, полностью защищенных от DOM XSS . Этот режим может быть включен через CSP . Он делает JavaScript-код безопасным по умолчанию посредством ограничения значений, принимаемых небезопасными API , специальным объектом — Trusted Type .
Для создания таких объектов можно определить политики, которые проверяют соблюдение правил безопасности (таких как экранирование и обезвреживание) перед записью данных в DOM . Затем эти политики помещаются в код, который может представлять интерес для DOM XSS .
Включаем Trusted Types для опасных приемников DOM :
В настоящее время единственным доступным значением директивы require-trusted-types-for является script .
Разумеется, Trusted Types можно комбинировать с другими директивами CSP :
C помощью директивы trusted-types можно ограничить пространство имен для политик Trusted Types , например, trusted-types myPolicy .
Директива require-trusted-types-for ‘script’ делает использование доверенного типа обязательным. Любая попытка использовать строку в небезопасном API завершится ошибкой.
Подробнее о Trusted Types можно почитать здесь.
X-Content-Type-Options
Когда вредоносный HTML-документ обслуживается вашим доменом (например, когда изображение, загружаемое в сервис хранения фотографий, содержит валидную разметку), некоторые браузеры могут посчитать его активным документом и разрешить ему выполнять скрипты в контексте приложения.
X-Content-Type-Options: nosniff заставляет браузер проверять корректность MIME-типа в заголовке полученного ответа Content-Type . Рекомендуется устанавливать такой заголовок для всех загружаемых ресурсов.
X-Frame-Options
Если вредоносный сайт будет иметь возможность встраивать ваше приложение как iframe , это может предоставить атакующему возможность вызывать непреднамеренные действия пользователей через кликджекинг. В некоторых случаях это также позволяет атакующему изучать содержимое документа.
X-Frame-Options является индикатором того, должен ли ваш сайт рендериться в <frame>, <iframe> , <embed> или <object> .
Для того, чтобы разрешить встраивание только определенных страниц сайта, используется директива frame-ancestors заголовка CSP .
Полностью запрещаем внедрение:
Разрешаем создание фреймов только на собственном сайте:
Обратите внимание: по умолчанию все документы являются встраиваемыми.
Cross-Origin-Resource-Policy (CORP)
Атакующий может внедрить ресурсы вашего сайта в свое приложение с целью получения информации о вашем сайте.
CORP определяет, какие сайты могут внедрять ресурсы вашего приложения. Данный заголовок принимает 1 из 3 возможных значений: same-origin , same-site и cross-origin .
Для сервисов вроде CDN рекомендуется использовать значение cross-origin , если для них не определен соответствующий заголовок CORS .
same-origin разрешает внедрение ресурсов страницами, принадлежащими к одному источнику. Данное значение применяется в отношении чувствительной информации о пользователях или ответов от API , которые рассчитаны на использование в пределах данного источника.
Обратите внимание: ресурсы все равно будут доступны для загрузки, поскольку CORP ограничивает только внедрение этих ресурсов в другие источники.
same-site предназначен для ресурсов, которые используются не только доменом (как в случае с same-origin ), но и его поддоменами.
Cross-Origin-Opener-Policy (COOP)
Если сайт атакующего может открывать другой сайт в поп-апе (всплывающем окне), то у атакующего появляется возможность для поиска межсайтовых источников утечки информации. В некоторых случаях это также позволяет реализовать атаку с использованием побочных каналов, описанную в Spectre .
Заголовок Cross-Origin-Opener-Policy позволяет запретить открытие сайта с помощью метода window.open() или ссылки target=»_blank» без rel=»noopener» . Как результат, у того, кто попытается открыть сайт такими способами, не будет ссылки на сайт, и он не сможет с ним взаимодействовать.
Значение same-origin рассматриваемого заголовка позволяет полностью запретить открытие сайта в других источниках.
Значение same-origin-allow-popups также защищает документ от открытия в поп-апах других источников, но позволяет приложению взаимодействовать с собственными попапами.
unsafe-none является значением по умолчанию, оно разрешает открытие сайта в виде поп-апа в других источниках.
Мы можем получать отчеты от COOP :
COOP также поддерживает режим report-only , позволяющий получать отчеты о нарушениях без их блокировки.
Cross-Origin Resource Sharing (CORS)
CORS — это не заголовок, а механизм, используемый браузером для предоставления доступа к ресурсам приложения.
По умолчанию браузеры используют политику одного источника или общего происхождения, которая запрещает доступ к таким ресурсам из других источников. Например, при загрузке изображения из другого источника, даже несмотря на его отображение на странице, JavaScript-код не будет иметь к нему доступа. Провайдер ресурса может предоставить такой доступ через настройку CORS с помощью двух заголовков:
Использование CORS
Начнем с того, что существует два типа HTTP-запросов. В зависимости от деталей запроса он может быть классифицирован как простой или сложный (запрос, требующий отправки предварительного запроса).
Критериями простого запроса является следующее:
- методом запроса является GET , HEAD или POST ;
- кастомными заголовками могут быть только Accept , Accept-Language , Content-Language и Content-Type ;
- значением заголовка Content-Type может быть только application/x-www-form-urlencoded , multipart/form-data или text/plain .
Все остальные запросы считаются сложными.
В данном случае браузер отправляет запрос к другому источнику с заголовком Origin , значением которого является источник запроса:
- Access-Control-Allow-Origin: https://example.com означает, что https://example.com имеет доступ к содержимому ответа. Если значением данного заголовка является * , ресурсы будут доступны любому сайту. В этом случае полномочия (credentials) не требуются;
- Access-Control-Allow-Credentials: true означает, что запрос на получение ресурсов должен содержать полномочия (куки). При отсутствии полномочий в запросе, даже при наличии источника в заголовке Access-Control-Allow-Origin , запрос будет отклонен.
Перед сложным запросом выполняется предварительный. Он выполняется методом OPTIONS для определения того, может ли быть отправлен основной запрос:
- Access-Control-Request-Method: POST — последующий запрос будет отправлен методом POST ;
- Access-Control-Request-Headers: X-PINGOTHER, Content-Type — последующий запрос будет отправлен с заголовками X-PINGOTHER и Content-Type .
- Access-Control-Allow-Methods: POST, GET, OPTIONS — последующий запрос может выполняться указанными методами;
- Access-Control-Allow-Headers: X-PINGOTHER, Content-Type — последующий запрос может содержать указанные заголовки;
- Access-Control-Max-Age: 86400 — результат сложного запроса будет записан в кеш и будет там храниться на протяжении 86400 секунд.
Cross-Origin-Embedder-Policy (COEP)
Для предотвращения кражи ресурсов из других источников с помощью атак, описанных в Spectre , такие возможности, как SharedArrayBuffer , performance.measureUserAgentSpecificMemory() или JS Self Profiling API , по умолчанию отключены.
Cross-Origin-Embedder-Policy: require-corp запрещает документам и воркерам (workers) загружать изображения, скрипты, стили, фреймы и другие ресурсы до тех пор, пока доступ к ним не разрешен с помощью заголовков CORS или CORP . COEP может использоваться совместно с COOP для настройки межсайтовой изоляции документа.
На данный момент require-corp является единственным доступным значением рассматриваемого заголовка, кроме unsafe-none , которое является значением по умолчанию.
Полная межсайтовая изоляция приложения
Изоляция с отчетами о блокировках
HTTP Strict Transport Security (HSTS)
Данные, передаваемые по HTTP , не шифруются, что делает их доступными для перехватчиков на уровне сети.
Заголовок Strict-Transport-Security запрещает использование HTTP . При наличии данного заголовка браузер будет использовать HTTPS без перенаправления на HTTP (при отсутствии ресурса по HTTPS ) в течение указанного времени ( max-age ).
- max-age — время в секундах, в течение которого браузер должен «помнить», что сайт доступен только по HTTPS ;
- includeSubDomains — распространяет политику на поддомены.
Другие заголовки
Referrer-Policy
Заголовок Referrer-Policy определяет содержание информации о реферере, указываемой в заголовке Referer . Заголовок Referer содержит адрес запроса, например, адрес предыдущей страницы, или адрес загруженного изображения, или другого ресурса. Он используется для аналитики, логирования, оптимизации кеша и т.д. Однако он также может использоваться для слежения или кражи информации, выполнения побочных эффектов, приводящих к утечке чувствительных пользовательских данных и т.д.
| Значение | Описание |
|---|---|
| no-referrer | Заголовок Referer не включается в запрос |
| no-referrer-when-downgrade | Значение по умолчанию. Реферер указывается при выполнении запроса между HTTPS и HTTPS , но не указывается при выполнении запроса между HTTPS и HTTP |
| origin | Указывается только источник запроса (например, реферером документа https://example.com/page.html будет https://example.com ) |
| origin-when-cross-origin | При выполнении запроса в пределах одного источника указывается полный URL , иначе указывается только источник (как в предыдущем примере) |
| same-origin | При выполнении запроса в пределах одного источника указывается источник, в противном случае, реферер не указывается |
| strict-origin | Похоже на no-referrer-when-downgrade , но указывается только источник |
| strict-origin-when-cross-origin | Сочетание strict-origin и origin-when-cross-origin |
| unsafe-url | Всегда указывается полный URL |
Обратите внимание: данный заголовок не поддерживается мобильным Safari .
Clear-Site-Data
Заголовок Clear-Site-Data запускает очистку хранящихся в браузере данных (куки, хранилище, кеш), связанных с источником. Это предоставляет разработчикам контроль над данными, локально хранящимися в браузере пользователя. Данный заголовок может использоваться, например, в процессе выхода пользователя из приложения (logout) для очистки данных, хранящихся на стороне клиента.
| Значение | Описание |
|---|---|
| «cache» | Сообщает браузеру, что сервер хочет очистить локально кешированные данные для источника ответа на запрос |
| «cookies» | Сообщает браузеру, что сервер хочет удалить все куки для источника. Данные для аутентификации также будут очищены. Это влияет как на сам домен, так и на его поддомены |
| «storage» | Сообщает браузеру, что сервер хочет очистить все хранилища браузера ( localStorage , sessionStorage , IndexedDB , регистрация сервис-воркеров — для каждого зарегистрированного СВ вызывается метод unregister() , AppCache , WebSQL , данные FileSystem API , данные плагинов) |
| «executionContexts» | Сообщает браузеру, что сервер хочет перезагрузить все контексты браузера (в настоящее время почти не поддерживается) |
| «*» | Сообщает браузеру, что сервер хочет удалить все данные |
Обратите внимание: данный заголовок не поддерживается Safari .
Permissions-Policy
Данный заголовок является заменой заголовка Feature-Policy и предназначен для управления доступом к некоторым продвинутым возможностям.
В данном случае мы полностью запрещаем доступ к камере (видеовходу) устройства, разрешаем доступ к методу requestFullScreen() (для включения полноэкранного режима воспроизведения видео) для всех, а к информации о местонахождении устройства — только для источников example.com и another.example.com .
| Директива | Описание |
|---|---|
| accelerometer | Управляет тем, может ли текущий документ собирать информацию об акселерации (проекции кажущегося ускорения) устройства с помощью интерфейса Accelerometer |
| ambient-light-sensor | Управляет тем, может ли текущий документ собирать информацию о количестве света в окружающей устройство среде с помощью интерфейса AmbientLightSensor |
| autoplay | Управляет тем, может ли текущий документ автоматически воспроизводить медиа, запрошенное через интерфейс HTMLMediaElement |
| battery | Определяет возможность использования Battery Status API |
| camera | Определяет возможность использования видеовхода устройства |
| display-capture | Определяет возможность захвата экрана с помощью метода getDisplayMedia() |
| document-domain | Определяет возможность установки document.domain |
| encrypted-media | Определяет возможность использования Encrypted Media Extensions API (EME) |
| execution-while-not-rendered | Определяет возможность выполнения задач во фреймах без их рендеринга (например, когда они скрыты или их свойство diplay имеет значение none ) |
| execution-while-out-of-viewport | Определяет возможность выполнения задач во фреймах, находящихся за пределами области просмотра |
| fullscreen | Определяет возможность использования метода requestFullScreen() |
| geolocation | Определяет возможность использования Geolocation API |
| gyroscope | Управляет тем, может ли текущий документ собирать информацию об ориентации устройства с помощью Gyroscope API |
| layout-animations | Определяет возможность показа анимации |
| legacy-image-formats | Определяет возможность отображения изображений устаревших форматов |
| magnetometer | Управляет тем, может ли текущий документ собирать информацию об ориентации устройства с помощью Magnetometer API |
| microphone | Определяет возможность использования аудиовхода устройства |
| midi | Определяет возможность использования Web MIDI API |
| navigation-override | Определяет возможность управления пространственной навигацией (spatial navigation) механизмами, разработанными автором приложения |
| oversized-images | Определяет возможность загрузки и отображения больших изображений |
| payment | Определяет возможность использования Payment Request API |
| picture-in-picture | Определяет возможность воспроизведения видео в режиме «картинка в картинке» |
| publickey-credentials-get | Определяет возможность использования Web Authentication API для извлечения публичных ключей, например, через navigator.credentials.get() |
| sync-xhr | Определяет возможность использования WebUSB API |
| vr | Определяет возможность использования WebVR API |
| wake-lock | Определяет возможность использования Wake Lock API для запрета переключения устройства в режим сохранения энергии |
| screen-wake-lock | Определяет возможность использования Screen Wake Lock API для запрета блокировки экрана устройства |
| web-share | Определяет возможность использования Web Share API для передачи текста, ссылок, изображений и другого контента |
| xr-spatial-tracking | Определяет возможность использования WebXR Device API для взаимодействия с сессией WebXR |
- =() — полный запрет;
- =* — полный доступ;
- (self «https://example.com») — предоставление разрешения только указанному источнику.
Спецификация рассматриваемого заголовка находится в статусе рабочего черновика, поэтому его поддержка оставляет желать лучшего:
Перейдем к практической части.
Разработка Express-приложения
Создаем директорию для проекта, переходим в нее и инициализируем проект:
Формируем структуру проекта:
Иконку можно найти здесь.
Набросаем какой-нибудь незамысловатый код.
В public/index.html мы подключаем иконку, стили, скрипт, Google-шрифты, Bootstrap и Boostrap Icons через CDN , создаем элементы для заголовка, даты, времени и кнопок:
Добавляем стили в public/style.css
В public/script.js мы делаем следующее:
- определяем политику доверенных типов;
- создаем утилиты для получения ссылки на DOM-элемент, форматирования даты и времени и регистрации обработчика (по умолчанию одноразового и запускающего колбэк при возникновении события click );
- получаем ссылки на DOM-элементы;
- определяем настройки для форматирования даты и времени;
- добавляем дату и время в качестве текстового содержимого соответствующих элементов;
- определяем колбэки для обработчиков: для остановки таймера, добавления HTML-шаблона с потенциально вредоносным кодом и получения HTTP-заголовков;
- регистрируем обработчики.
-
— Node.js-фреймворк, упрощающий разработку сервера; — утилита для запуска сервера для разработки и его автоматического перезапуска при обновлении соответствующего файла; — утилита для автоматического открытия вкладки браузера по указанному адресу.
Определяем в package.json команды для запуска серверов:
Приступаем к реализации сервера.
Справедливости ради следует отметить, что в экосистеме Node.js имеется специальная утилита для установки HTTP-заголовков, связанных с безопасностью веб-приложений — Helmet . Шпаргалку по работе с этой утилитой вы найдете здесь.
Также существует специальная утилита для работы с CORS — Cors . Шпаргалку по работе с этой утилитой вы найдете здесь.
Большинство заголовков можно определить сразу:
Также добавим заголовок Expect-CT :
Блокируем доступ к камере, микрофону, информации о местонахождении и Payment Request API :
Директивы для CSP :
Обратите внимание: все директивы должны быть указаны в одну строку без переносов. Мы не определяем директивы для стилей и шрифтов, поскольку они загружаются из других источников.
Также обратите внимание, что мы не используем nonce для скриптов, поскольку мы не рендерим разметку на стороне сервера, но я приведу соответствующий код.
Выполняем команду yarn dev или npm run dev (разумеется, на вашей машине должен быть установлен Node.js ). Данная команда запускает сервер для разработки и открывает вкладку браузера по адресу http://localhost:3000 .
Отлично! Теперь развернем приложение на Heroku и проверим его безопасность с помощью Security Headers и WebPageTest .
Деплой Express-приложения на Heroku
Создаем аккаунт на Heroku .
Находясь в корневой директории проекта, инициализируем Git-репозиторий (разумеется, на вашей машине должен быть установлен git ), добавляем и фиксируем изменения (не забудьте добавить node_modules в .gitignore ):
Создаем удаленный репозиторий на Heroku :
Инструкцию по развертыванию приложения на Heroku можно найти здесь.
После выполнения этой команды, в терминале появится URL вашего приложения, развернутого на Heroku , например, https://tranquil-meadow-01695.herokuapp.com/ .
Перейдите по указанному адресу и проверьте работоспособность приложения.
Заходим на Security Headers , вставляем URL приложения в поле enter address here и нажимаем на кнопку Scan :
Получаем рейтинг приложения:
В Supported By читаем Вау, отличная оценка. .
Заходим на WebPageTest , вставляем URL приложения в поле Enter a website URL. и нажимаем на кнопку Start Test -> :
Получаем результаты оценки приложения (нас интересует первая оценка — Security score ):
Похоже, мы все сделали правильно. Круто!
Деплой приложения на Netlify
Переносим файлы favicon.png , index.html , script.js и style.css из папки public в отдельную директорию, например, netlify .
Для настройки сервера Netlify используется файл netlify.toml . Создаем данный файл в директории проекта. Нас интересует только раздел [[headers]] :
- for = «/*» означает для всех запросов;
- [header.values] — заголовки и их значения (просто переносим их из Express-сервера с учетом особенностей синтаксиса).
Можно запустить сервер для разработки (это необязательно):
Данная команда запускает приложение и открывает вкладку браузера по адресу http://localhost:8888 .
Разворачиваем приложение в тестовом режиме:
Выбираем Create & configure a new site , свою команду (например, Igor Agapov’s team ), оставляем Site name пустым и выбираем директорию со сборкой приложения (у нас такой директории нет, поэтому оставляем значение по умолчанию — . ):
Получаем URL черновика веб-сайта ( Website Draft URL ), например, https://60f3e6013d0afb2ce71a5623—infallible-pasteur-d015e7.netlify.app . Можно перейти по указанному адресу и проверить работоспособность приложения.
Разворачиваем приложение в продакшен-режиме:
- -p или —prod означает производственный режим.
Получаем URL приложения ( Website URL ), например, https://infallible-pasteur-d015e7.netlify.app/ . Опять же, можно перейти по указанному адресу и проверить работоспособность приложения.
Инструкцию по развертыванию приложения на Netlify можно найти здесь.
Возвращаемся на Security Headers и WebPageTest и проверяем, насколько безопасным является наше Netlify-приложение:
Кажется, у нас все получилось!
Заключение
Подведем итоги. Мы с вами вкратце изучили все HTTP-заголовки, связанные с безопасностью веб-приложений, разработали серверное и бессерверное приложения с аналогичным функционалом и получили лучшие оценки безопасности для данных приложений на Security Headers и WebPageTest . По-моему, очень неплохо для одной статьи.
Надеюсь, что вы не зря потратили время. Благодарю за внимание и хорошего дня!
Send и Return
Что такое send и return на канале микшерного пульта?
Надеюсь, ты помнишь из школьного курса физики, что в электрическую цепь приборы могут подключаться как последовательно, так и параллельно. Так вот, с аудиосигналами может быть также, и роль параллельно подключенного прибора в маршрутизации (роутинге) аудиосигналов как раз выполняют эффекты, расположенные в return-каналах. Думаю, это понятно, теперь назовём вещи своими именами:
Return (или возврат) — специальный канал микшера, предназначенный не для инструментов, а для эффектов, которые должны применяться к нескольким инструментам микса параллельно. При этом результат работы return-канала не заменяет обрабатываемый звук, а лишь подмешивается к нему. По умолчанию обработанная эффектами возврата копия сигнала возвращается в мастер-канал микшерного пульта.
Как говорится, лучше один раз услышать. Оба семпла ниже обработаны ревербератором с одинаковыми настройками, только в первом случае он подключен последовательно (в insert), а во втором — параллельно (в return):
А, в свою очередь, send (или посыл) — это параметр, который отвечает за количество посылаемого на конкретный return сигнала. Таким образом, классическая схема работы каналов возврата выглядит следующим образом:

Режимы работы return-канала: pre-fader и post-fader
Микшерные пульты современных DAW имеют возможность выбора нужного режима работы каналов возврата. Здесь тоже предельно просто:
- Режим pre-fader означает, что посыл на return-канал производится ДО регулятора уровня громкости канала с инструментом;
- В режиме post-fader, наоборот, посыл производится ПОСЛЕ регулятора громкости.
То есть, если ты в pre-fader-ном режиме уберёшь громкость канала, то на return-канал звук всё равно будет поступать.
Преимущества использования каналов возврата
Уверен, ты уже и сам видишь плюсы от активного использования в работе return-ов, но тем не менее:
- При переносе наиболее используемых аудиоэффектов на каналы возврата значительно освобождаются ресурсы процессора. Ну это логично: вместо использования, например, 5 требовательных к ресурсам _ревербераторов_ — используется только один;
- Использование каналов возврата делает звук более насыщенным;
- Обработка нескольких каналов одним набором эффектов делает микс более цельным.
Ну что, убедил в том, что возраты не только можно использовать в работе, но и нужно? Добавлю лишь, что хрестоматийный пример использования return-ов — 3-4 канала, в которых расположено по ревербератору с разными настройками для реализации так называемых планов.
Но это лишь малая часть потенциала возвратов. Не ограничивай себя ни количеством каналов, ни набором эффектов в них, ни количеством эффектов в каждом return-канале. Это такая же творческая вещь как и всё остальное в саундпродакшне. Экспериментируй!
Ну а я сейчас на примере Ableton Live покажу как работать с return-каналами.
Использование return-каналов в Ableton Live
По умолчанию в Live 2 return-канала1, в режиме сессии они расположены справа рядом с мастер-каналом. Итак, как их заставить работать? Да всё максимально просто, смотри гифку:
Кстати, сигнал с возврата можно направить не на мастер-канал, как указано по умолчанию, а на аудио-канал с последующей его обработкой. Но _о маршрутизации в Live_ я расскажу чуть позже, а пока запускай свою DAW и начинай экспериментировать. Удачи!
1 добавить return-каналы в Ableton Live можно комбинацией горячих клавиш CTRL+ALT+T или клик правой кнопкой мыши по свободному от каналов месту в полосе где располагаются названия каналов и выбрать пункт «Insert Return Track».
Комментарии:
Звук не подмешивается, а прибавляется, ты устанавливаешь количество сигнала не отправляемого на канал возврата, а копируемого на канал возврата, то есть в итоге сигнал от одного инструмента становится громче, это нарушает баланс микса. И я уже несколько дней пытаюсь найти решение этого недоразумения. Мне нужно, чтобы он именно ПОДМЕШИВАЛСЯ
разъясните про Pre/Post Fader (1 онлайн
Поискал на форуме. Нашел информацию, но она очень размыта и не понятна )) :tongue:
Кое что я понял из статей на форуме.
Вот что конкретно:
рассмотрю случай с посылом реверба на трек Snare
В случае с Pre Fader, обработанный сигнал будет копироваться непосредственно из самого звукового файла,
минуя всякие эффекты в Insert‘e?
А в случае с Post Fader сигнал (отражение) будет копироваться и вставляться в хвост основного звука после всех эффектов в Insert‘e?
разъясните, желательно в картинках
Alex_HS
Super Moderator
Pavlik
New Member
New Member
supersonic
Well-Known Member
New Member
Vadim_K
Well-Known Member
New Member
я может чего то понял неправильно, но если мне нужно например верб повесить на канал (сенд) а у меня там дилей в инсерте уже есть, то сенд только с дилеем будет чтоли? при том что у меня на 7-8 каналах уже динамика висит, да и автоматизация например на громкости прописана.
з.ы. вопрос чисто познавательный т.к. всёравно в другом хосте работаю и там маршрутизация сендов по другому происходит.
Vadim_K
Well-Known Member
New Member
тоже лишний гемор
з.ы. короче что то смотрю через жопу тут как то всё, сейчас сам нуенду поставлю и посмотрю что и как,
Vadim_K
Well-Known Member
После первых 6-ти и EQ.
Насчёт гемора не согласен вобщем, имхо всё нормально и просто.
З.Ы.
А какая схема в Сонаре ?:gigi:
New Member
как и вположено, инсерт является инсертом в шину, а сенд является сендом с шины. т.е. инсерты вставляются в разрыв шины, а на все сенды идёт чистый сигнал с шины, до инсертов. :tongue:
з.ы. я к чему этот вопрос поднял, у меня такое ощущение что рисунок не совсем соответствует реальному положению дел, я на нуенде иногда работаю но таких хитрых путей там не замечал.
Vadim_K
Well-Known Member
Не, рисунок соответствует. Всё так и есть. Может это и может показаться "через жопу" конечно по началу, если к другом хосту привык, но на самом деле всё удобно и нормально: группу создать для чего либо не проблема, автоматизировать уровень сенда на ревер (если он Pre-Fader) в случае если громкость на канале автоматизирована (как в твоём примере выше) тоже не проблема: найти огибающую автоматизации громкости и скопировать этот участок на огибающую уровня посыла на сенд, "опустив или подняв" эту огибающую до нужного уровня, сохранив её "форму", и всё будет.
Единственная проблема, что не нравится, так это с группами — то что с одной группы на другую можно сендить тока слева направо в микшере (из которой левей, в те которые правее неё), ну об этом уже много писали здесь. То есть вот будет проблематично, если уже все группы созданы, и если понадобилась группа для дилэя новая например, и нужно чтобы сигнал дилэя посылался на группу с ревером, которая до этого была создана — вот это вот реализовать будет геморно. Не понятно почему до сих пор не сделали, чтобы из любой группы, можно было бы сендить в любую другую, независимо от того правее она или левее, то есть позже создана или раньше (хотя Rustami писал, что это как-то связано с компенсацией задержек, если я не ошибаюсь, что иначе было бы сложнее её реализация). Точнее, если работать с группами, и предполагается, что возможна такая ситуация, то порекомендовать можно такой же метод, как и в случаях, когда спрашивают почему инсёрты местами поменять нельзя 🙂 В этом случае рекомендуется оставлять свободным первый слот например, и навешивать их со второго, и также с группами похоже можно — сделать одну-две пустые группы слева вначале, и пусть они будут на всякий случай. А на остальное по поводу роутинга микшера кубейса/нуэнды претензий нет.