Как изменить http заголовок

Компании, продающие "системы показателей безопасности", сейчас на подъеме, их влияние в сфере корпоративных продаж растет. К тому же есть те, кого низкий рейтин...

Компании, продающие «системы показателей безопасности», сейчас на подъеме, их влияние в сфере корпоративных продаж растет. К тому же есть те, кого низкий рейтинг безопасности у продавцов смущает, и те, кто хотя бы однажды, глядя на рейтинг, отказался от покупки, — я с такими людьми общался.

Я посмотрел, как эти компании вычисляют показатели безопасности других компаний. Оказалось, они смотрят на сочетание использования НТТР-заголовка для безопасности и репутации IP-адресов.

Репутация IP-адреса основывается на данных черных списков и списков спамеров в сочетании с данными о владельце общедоступного IP-адреса. Она, в принципе, должна быть чистой, если ваша компания не рассылает спам и в состоянии быстро определить и остановить вредоносное внедрение. Использование заголовка безопасности НТТР вычисляется аналогично тому, как работает Observatory от Mozilla.

Таким образом, рейтинг большинства компаний, в основном, определяется заголовками, включенными на общедоступных веб-сайтах для безопасности.

Настроить заголовок правильно — это недолго (серьезной проверки не потребуется), но это улучшит безопасность сайта и поможет не растерять покупателей, для которых безопасность — не пустой звук

В ценности упомянутой методики проверки я сомневаюсь, к том же ценник за услугу выставлен заоблачный. Вряд ли компании-поставщики этой услуги способны определить безопасность ресурса с заявленной точностью. Впрочем, ситуация лишний раз подчеркивает, как важно сесть и уделить время тому, чтобы включить и настроить правильные заголовки.

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

Важные заголовки для безопасности

Content-Security-Policy

CSP применяется, чтобы предотвращать межсайтовый скриптинг — путем определения, какие ресурсы могут быть загружены. Из всего списка этот заголовок отнимет больше остальных времени на создание и правильную поддержку, а еще больше других подвержен рискам. Разрабатывая CSP, тщательно его проверяйте — если вдруг заблокируете используемый вами же источник, то нарушите функциональность собственного сайта.

Для предварительной версии можно использовать замечательный инструмент — расширение для браузера Mozilla, Laboratory CSP. Установите его в браузере, тщательно изучите сайт, для которого хотите создать CSP, а после используйте сгенерированную CSP на своем сайте. В идеале, нужно еще переработать JavaScript, так что можно удалить директиву «unsafe inline».

CSP может показаться сложной и сбить с толку, поэтому, если хотите углубиться в тему, посетите официальный сайт.

Предварительно можно настроить CSP так (на боевом сайте она, скорее всего, потребует множества модификаций). Добавьте в каждый раздел вашего сайта домены.

# Default to only allow content from the current site
# Allow images from current site and imgur.com
# Don't allow objects such as Flash and Java
# Only allow scripts from the current site
# Only allow styles from the current site
# Only allow frames from the current site
# Restrict URL's in the <base> tag to current site
# Allow forms to submit only to the current site
Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';

Strict-Transport-Security

Этот заголовок сообщает браузеру, что на сайт заходить можно только по протоколу HTTPS — всегда включайте его, если на вашем сайта активирован HTTPS. Включите его на всех используемых субдоменах, если таковые имеются.

Strict-Transport-Security: max-age=3600; includeSubDomains

X-Content-Type-Options

Благодаря этому заголовку браузеры придерживаются типов MIME, установленных приложением, что помогает предотвратить часть атак с межсайтовым скриптингом.

Также он снижает риск неожиданного поведения приложения, когда браузер неверно «угадывает» тип контента на сайте — например, если разработчик обозначает страницу «HTML», а браузер видит JavaScript и пытается отрисовать страницу соответственно. Также благодаря этому заголовку браузер всегда держится установленных сервером MIME-типов.

X-Content-Type-Options: nosniff

Cache-Control

Этот будет позаковыристее прочих, потому что для разных типов контента вам наверняка нужны разные политики кэширования.

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

Впрочем, кэшировать можно и нужно те страницы, которые обновляются редко, например статические ресурсы (картинки, файлы CSS и JS). Кэширование можно настроить на постраничной основе, или используя regex в настройках сервера.

# Don’t cache by default
Header set Cache-Control no-cache

# Cache static assets for 1 day
<filesMatch ".(css|jpg|jpeg|png|gif|js|ico)$">
    Header set Cache-Control "max-age=86400, public"
</filesMatch>

Expires

Этот заголовок устанавливает время, на которое текущий запрос сохраняется в кэше. Он игнорируется, если включен заголовок Cache-Control max-age, так что мы включаем его только на случай, если его проверяет простенький сканер — без учета контроля кэширования.

Мы предполагаем, что в целях безопасности браузер не кэширует ничего, так что дата в заголовке всегда будет в прошлом.

Expires: 0

X-Frame-Options

Этот заголовок разрешает отображение сайта в iFrame.

Поместив ваш веб-сайт в iFrame, вредоносный ресурс получает возможность произвести кликджекинг атаку — запустив некий JavaScript, который обманом вынудит пользователя кликнуть по iFrame, а после начнет взаимодействовать с ресурсом от его, пользователя, имени (то есть человек кликнет по вредоносной ссылке или кнопке, даже не подозревая об этом!).

Этот заголовок всегда надо настраивать на отказ, исключение — если вы намеренно используете фреймы. Тогда заголовок нужно настраивать на тот же источник. Если вы по умолчанию используете фреймы с другим сайтом, занесите сторонний домен в белый список.

Следует также отметить, что этот заголовок замещается директивой CSP frame-ancestors. Я его рекомендую пока включать, но только для того, чтобы заткнуть инструменты для проверки заголовков, в будущем от него скорее всего избавятся.

X-Frame-Options: deny

Access-Control-Allow-Origin

Этот заголовок сообщает браузеру, внешний код каких посторонних сайтов имеет право делать запросы к определенной странице. Настройки по умолчанию обычно правильные, но если надо — можно и поменять.

Например, сайт А содержит некий JavaScript, который хочет сделать запрос к сайту В. Сайт В должен ответить на этот запрос — если заголовок разрешает сайту А сделать запрос. Если нужно настроить множество источников, подробности на странице на MDN.

Тут можно слегка запутаться, поэтому я составил схему — проиллюстрировать, как работает этот заголовок:


Поток данных с Access-Control-Allow-Origin

Access-Control-Allow-Origin: http://www.one.site.com

Set-Cookie

Убедитесь, что ваши cookies устанавливаются только через протокол HTTPS (с шифрованием), и что к ним нет доступа через JavaScript. Эти файлы можно посылать, только если ваш сайт тоже поддерживает HTTPS, как и должно быть. Всегда нужно выставлять вот такие флаги:

  • Secure
  • HTTPOnly

Пример определения Cookie:

Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly

Подробнее — в отличной документации по cookies от Mozilla.

X-XSS-Protection

Этот заголовок приказывает браузеру прервать выполнение обнаруженных атак межсайтового скриптинга. Включая его, вы не сильно рискуете, но перед запуском в производственную среду все равно протестируйте.

X-XSS-Protection: 1; mode=block

Пример настроек веб-сервера

Вообще, в настройках сервера лучше всего добавлять заголовки на весь сайт. Исключение — файлы cookie, поскольку они определяются в самом приложении.

Советую, прежде чем добавить на сайт заголовки, сперва свериться с Observatory или вручную заглянуть в заголовки — проверить, какие уже установлены. Некоторые движки сайтов и сервера самостоятельно все установят, поэтому просто реализуйте нужные вам заголовки или измените те, которые в этом нуждаются.

Конфигурация Apache

Пример настройки Apache в .htaccess:

<IfModule mod_headers.c>
    ## CSP
    Header set Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';

    ## General Security Headers
    Header set X-XSS-Protection: 1; mode=block
    Header set Access-Control-Allow-Origin: http://www.one.site.com
    Header set X-Frame-Options: deny
    Header set X-Content-Type-Options: nosniff
    Header set Strict-Transport-Security: max-age=3600; includeSubDomains

    ## Caching rules
    # Don’t cache by default
    Header set Cache-Control no-cache
    Header set Expires: 0

    # Cache static assets for 1 day
    <filesMatch ".(ico|css|js|gif|jpeg|jpg|png|svg|woff|ttf|eot)$">
        Header set Cache-Control "max-age=86400, public"
    </filesMatch>

</IfModule>

Конфигурация Nginx

## CSP
add_header Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';

## General Security Headers
add_header X-XSS-Protection: 1; mode=block;
add_header Access-Control-Allow-Origin: http://www.one.site.com;
add_header X-Frame-Options: deny;
add_header X-Content-Type-Options: nosniff;
add_header Strict-Transport-Security: max-age=3600; includeSubDomains;

## Caching rules
# Don’t cache by default
add_header Cache-Control no-cache;
add_header Expires: 0;

# Cache static assets for 1 day
location ~* .(?:ico|css|js|gif|jpe?g|png|svg|woff|ttf|eot)$ {
    try_files $uri @rewriteapp;
    add_header Cache-Control "max-age=86400, public";
}

Настройка заголовка уровня приложения

Если у вас нет доступа к веб-серверу или требования к настройке заголовков сложные, то вам наверняка придется настроить их в самом приложении. Обычно для всего сайта это осуществляется с помощью промежуточного ПО, или на основе однократной установки заголовков при каждом запросе.

Для краткости в каждый пример я включил только по одному заголовку. Вы же добавляйте по тому же способу все, которые нужны.

Node и express:

Добавьте global mount path:

app.use(function(req, res, next) {
    res.header('X-XSS-Protection', 1; mode=block);    
    next();
});

Java и Spring

У меня мало опыта работы со Spring, но у Baeldung есть отличное руководство по настройке заголовков в Spring.

PHP

Я не знаком с разнообразными средами PHP. Ищите промежуточное ПО для запросов. Для единичного запроса все просто.

header("X-XSS-Protection: 1; mode=block");

Python / Django

Django включает настраиваемое промежуточное ПО для обеспечения безопасности, которое выполнит за вас все эти настройки. Активируйте сначала их.

Ответы некоторых страниц можно трактовать как словарь. В Django есть особый способ работы с кэшированием, и если хотите настроить заголовки кэширования таким образом, с ним надо ознакомиться.

response = HttpResponse()
response["X-XSS-Protection"] = "1; mode=block"

Выводы

Настройка заголовков — процесс относительно простой и быстрый, зато дает прирост уровня безопасности сайта — в плане защиты данных, от межсайтового скриптинга и кликджекинга.

В будущем вы оградите себя от срыва сделок, потому что ваш рейтинг безопасности останется на уровне. Практика его оценки на основе рассмотренных мной параметров набирает обороты, и мне кажется, ее роль в ближайшие годы в сфере продаж только усилится.

Дайте знать, если я упустил какой-то важный заголовок!

{«id»:13853,»url»:»/distributions/13853/click?bit=1&hash=cd75b99357eb9e426e1df4dbb81791da6b0a32378bd0abc2b7558d58679b0b3e»,»title»:»u0411u0438u0437u043du0435u0441u043eu043c u043cu043eu0433u0443u0442 u0441u0442u0430u0442u044c u0434u0430u0436u0435 u043fu043eu0434u0443u0448u0435u0447u043au0438 u0441 u0441u0435u043du043eu043c»,»buttonText»:»u041au0430u043a u044du0442u043e?»,»imageUuid»:»fa7bcd4d-f8e2-5af8-b94d-db7136204a56″,»isPaidAndBannersEnabled»:false}

HTTP Headers транслируют браузеру и компьютеру пользователя, насколько безопасным является веб-ресурс. Наличие таких настроенных HTTP заголовков повышает безопасность и повышает траст сайта в глазах ПС.

Как правило, стандартная ситуация после анализа HTTP Headers неудовлетворительная для 90% ресурсов в ру сегменте. И выглядит она примерно так:

Все заголовки не настроены, либо настроен только HSTS

Итак, пойдём от основного

1. Должен быть настроен HSTS. Т.е. подключение к вашему сайту и передача данных осуществляется только по безопасному протоколу. Настройка данного заголовка полностью избавляет нас от возможных подключений через http.

«Strict-Transport-Security: max-age=31536000; includeSubDomains»

2. Пропишите CSP (Content-Security-Policy). Настроенный CSP поможет предотвратить определенные типы атак, включая XSS атаки и атаки с распространением вредоносных данных и вирусных программ.

Здесь вам нужно перечислить допускаемые ресурсы к загрузке данных на сервер, все остальные же будут отсечены, как небезопасные

Стандартные значения для выполнения условий:

«Content-Security-Policy: script-src ‘self’»

или *Content-Security-Policy: upgrade-insecure-requests

3. X-XSS-Protection. Защита от XSS (cross site scripting) атак

«X-XSS-Protection: 1; mode=block»

4. X-Frame-Options. Нужен, чтобы не предоставлять доступ злоумышленникам к демонстрации по средствам iframe, но при установлении заголовка не забывайте, что есть и полезные программы, которые используют ваши iframe.

Здесь я советую устанавливать значение заголовку «X-Frame-Options: SAMEORIGIN» и добавлять исключения. Ниже пример для исключения Яндекс.Метрики.

location / {
set $frame_options »;
if ($http_referer !~ ‘^https?://([^/]+.)?(yourdomain.com|webvisor.com|metri[ck]a.yandex.(com|ru|com.tr))/’){
set $frame_options ‘SAMEORIGIN’;
}
add_header X-Frame-Options $frame_options;

}

5. X-Content-Type-Options. Не до конца понимаю, кому и как нужно изменять и интерпретировать данные на сайтах. Однако, понятно, что это может привести к «поломке» сайта. Если хотите обезопасить себя от демонстрации пустого экрана вашим пользователям, то установите

X-Content-Type-Options: nosniff

6. Referrer-Policy.

«Referrer-Policy: no-referrer-when-downgrade»

7. Определите значения для Cookies

Set-Cookie: <cookie-name>=<cookie-value> | Expires=<date>
| Max-Age=<non-zero-digit> | Domain=<domain-value>
| Path=<path-value> | SameSite=Strict|Lax|none

Какие бы значения для Cookie вы не присваивали и хранили, не забывайте в конце «HTTPOnly; Secure».

Приведённых значений вам хватит, чтобы получить высшую оценку и соответствовать, всем требования ПС в части безопасности.

Если вы захотите ещё поработать с безопасностью сайта, то дальше обратите своё внимание на такие заголовки как:

  • Public Key Pinning
  • Feature-Policy
  • Access-Control-Allow

P.S. Есть ресурс, где все значения для HTTP Headers прописаны со значениями их важности для сайтов. И при аудите вы видите, сколько процентов, а главное каких заголовков, вам не хватает, чтобы ваш сайт был безопасным. Знаете такой ресурс?

Как изменить HTTP заголовки в админке WordPress

Если вам понадобилось по каким-то причинам модифицировать HTTP заголовки в WordPress админке, то сделать это довольно проблематично. Однако далее, я поделюсь секретом, как это можно обойти…

В WordPress есть  wp_headers фильтр и хук действия send_headers для добавления и изменения HTTP- запросов. Для внешних страниц страниц сайта это идеальные «зацепки», которые следует использовать при любой возможности. К сожалению, однако, ни один хук не работает на всех страницах в области администрирования WordPress. После некоторых экспериментов я нашел простое решение для изменения заголовков HTTP на любой / всех страницах в административной области.

Самый простой способ добавить или изменить заголовок для ЛЮБЫХ / ВСЕХ сгенерированных WP страниц, включая все страницы в административной области и внешнем интерфейсе WordPress, — это вызвать функцию PHP headers() с помощью init хука WP . Вот несколько основных примеров, показывающих, как это делается.

Примечание:  примеры далее ограничивают изменение заголовка только страницами администратора. Чтобы изменить заголовки для запросов во внешней части сайта, рекомендуется использовать wp_headers или send_headers.

Добавляем заголовки

Чтобы добавить, скажем, XSS заголовок в административной области и во внешнем интерфейсе (т.е везде), мы можем добавить следующий код в файл functions.php.

function shapeSpace_add_header() {
  if (is_admin()) header('X-XSS-Protection: 0');	
}
add_action('init', 'shapeSpace_add_header');

Вот так просто. Этот метод использует функцию WordPress is_admin(), чтобы проверить, есть ли запрос для какой-либо страницы в области администрирования WP . Если это так, XSS заголовок добавляется через headers() функцию. Дополнительная условная логика может применяться для таргетинга только на определенные страницы.

Изменяем заголовки

По умолчанию headers() функция заменяет любой существующий заголовок с тем же именем. Рассмотрим этот пример:

function shapeSpace_modify_header() {	
  if (is_admin()) header('Example-Header: Value');	
}
add_action('init', 'shapeSpace_modify_header');

Если Example-Header заголовок уже существует, его значение будет заменено на Value. Таким образом, этот метод может быть использован для добавления нового заголовка (если он еще не существует) или для изменения заголовка (если он уже существует).

Добавляем несколько заголовков

Чтобы добавить несколько заголовков с одинаковым именем, мы можем передать второй аргумент headers() функции следующим образом:

function shapeSpace_add_headers() {
  if (is_admin()) {
    header('Header-Example: Value 1', false);
    header('Header-Example: Value 2', false);
    header('Header-Example: Value 3', false);
  }
}
add_action('init', 'shapeSpace_add_headers');

Обратите внимание, что здесь мы передаем false в качестве аргумента параметр функции replace. Таким образом, в этом примере будут добавлены три новых заголовка (и не будут заменены никакие заголовки), каждый со своим собственным значением. Кстати, для получения дополнительной информации можете ознакомиться с документацией по header() функции.

Удаляем заголовки

Последний пример, если вы хотите удалить заголовок, используйте функцию header_remove() :

function shapeSpace_remove_header() {
  if (is_admin()) header_remove('Header-Example');
}
add_action('init', 'shapeSpace_remove_header');

Этот метод удалит любые заголовки Header-Example. Опять же, как и в предыдущих примерах, мы используем, is_admin() чтобы убедиться, что затрагиваются только страницы админ панели.

Безопасность

В целях безопасности, изменяйте HTTP заголовки (особенно в области админки), только если вы на 100% знаете, что делаете. Если есть сомнения, не меняйте заголовки. Если вы работаете над внешними страницами, используйте основные хуки WordPress, wp_headers и send_headers , а не вышеописанную headers() технику PHP.

Ненужные заголовки

Посмотреть заголовки веб-сервера можно командой: curl -I https://yandex.ru/ или вы можете протестировать на сайте https://http.itsoft.ru
Давайте для начала посмотрим на заголовки Яндекс и Google.

[igor@new html]$ curl -I https://yandex.ru/
HTTP/1.1 200 Ok
Accept-CH: Viewport-Width, DPR, Device-Memory, RTT, Downlink, ECT
Accept-CH-Lifetime: 31536000
Cache-Control: no-cache,no-store,max-age=0,must-revalidate
Content-Length: 178283
Content-Security-Policy: report-uri https://csp.yandex.net/csp?project=morda&from=morda.big.ru&showid=1587028014.80097.85411.54444&h=stable-morda-man-yp-628&csp=new&date=20200416&yandexuid=4225126811587028014;script-src 'self' 'unsafe-inline' https://an.yandex.ru https://yastatic.net https://yandex.ru https://mc.yandex.ru;img-src https://yabs.yandex.ru https://favicon.yandex.net https://*.strm.yandex.net https://auto.ru https://an.yandex.ru https://strm.yandex.ru https://www.maximonline.ru 'self' https://thequestion.ru https://www.kinopoisk.ru https://yastatic.net https://awaps.yandex.net https://avatars.mds.yandex.net https://*.verify.yandex.ru https://mc.yandex.ru https://leonardo.edadeal.io data: https://resize.yandex.net https://yandex.ru https://mc.admetrica.ru;frame-src 'self' https://mc.yandex.ru https://yandex.ru https://yastatic.net https://st.yandexadexchange.net https://yandexadexchange.net;font-src data: https://an.yandex.ru https://yastatic.net;object-src https://avatars.mds.yandex.net;connect-src https://mc.yandex.ru https://*.cdn.ngenix.net https://games.yandex.ru https://mc.admetrica.ru https://yandex.ru https://portal-xiva.yandex.net https://auto.ru https://*.strm.yandex.net https://strm.yandex.ru https://an.yandex.ru https://mobile.yandex.net https://frontend.vh.yandex.ru https://yabs.yandex.ru https://thequestion.ru https://yastat.net https://api.market.yandex.ru 'self' https://www.kinopoisk.ru https://yastatic.net https://zen.yandex.ru https://www.maximonline.ru wss://portal-xiva.yandex.net;style-src 'unsafe-inline' https://yastatic.net;media-src https://*.strm.yandex.net https://*.cdn.ngenix.net blob:;default-src https://yastatic.net https://yastat.net
Content-Type: text/html; charset=UTF-8
Date: Thu, 16 Apr 2020 09:06:54 GMT
Expires: Thu, 16 Apr 2020 09:06:55 GMT
Last-Modified: Thu, 16 Apr 2020 09:06:55 GMT
P3P: policyref="/w3c/p3p.xml", CP="NON DSP ADM DEV PSD IVDo OUR IND STP PHY PRE NAV UNI"
Set-Cookie: yp=1589620015.ygu.1; Expires=Sun, 14-Apr-2030 09:06:54 GMT; Domain=.yandex.ru; Path=/
Set-Cookie: mda=0; Expires=Fri, 14-Aug-2020 09:06:54 GMT; Domain=.yandex.ru; Path=/
Set-Cookie: yandex_gid=213; Expires=Sat, 16-May-2020 09:06:54 GMT; Domain=.yandex.ru; Path=/
Set-Cookie: yandexuid=4225126811587028014; Expires=Sun, 14-Apr-2030 09:06:54 GMT; Domain=.yandex.ru; Path=/
Set-Cookie: i=8UHqdTah3NgMTINJMRGysflDelT4++ntHkOo85SGs6jvHhQQwro524Vs41lApmiL/8bGRA1ZejVwI0VKHneCfAPOMrg=; Expires=Sun, 14-Apr-2030 09:06:54 GMT; Domain=.yandex.ru; Path=/; Secure; HttpOnly
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Yandex-Sdch-Disable: 1


[igor@new html]$ curl -I https://google.com/
HTTP/1.1 301 Moved Permanently
Location: https://www.google.com/
Content-Type: text/html; charset=UTF-8
Date: Thu, 16 Apr 2020 09:08:18 GMT
Expires: Sat, 16 May 2020 09:08:18 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 220
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Alt-Svc: quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,h3-T050=":443"; ma=2592000

[igor@new html]$ curl -I https://www.google.com/
HTTP/1.1 200 OK
Date: Thu, 16 Apr 2020 09:08:35 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2020-04-16-09; expires=Sat, 16-May-2020 09:08:35 GMT; path=/; domain=.google.com; Secure
Set-Cookie: NID=202=QkgyPv5FrpwHWbJGnSC83K1Sw4wysE4IMVNbd3z83iNOheMyVdbxmJJJE0AFbs9eNH9_iKGAzqdSv6iUqfr-erOlOIap7MmRMOkqQr87iS2y_FyII7AlV5Jx-K4JC2_b8F9xyJYxPpOL2hP-81Msp_HndCCDtGSi33l4gYZ3oXU; expires=Fri, 16-Oct-2020 09:08:35 GMT; path=/; domain=.google.com; HttpOnly
Transfer-Encoding: chunked
Alt-Svc: quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,h3-T050=":443"; ma=2592000
Accept-Ranges: none
Vary: Accept-Encoding

Также вам может пригодиться утилита telnet для просмотра заголовков локального сервера, если при обращении через доменное имя отвечает прокси-сервер nginx.

[igor@new html]$ telnet 192.168.29.35 80
Trying 192.168.29.35...
Connected to 192.168.29.35.
Escape character is '^]'.
HEAD / HTTP/1.1
HOST: itsoft.ru

HTTP/1.1 200 OK
Date: Tue, 05 May 2020 07:37:23 GMT
Server: Apache/2.4.6 (CentOS)
Cache-Control: max-age=604800, public
Last-Modified: Mon, 27 Apr 2020 12:28:01 GMT
Etag: 273b847f0f077f7680a9e0d54a43c8a6
Set-Cookie: a=1144943031; expires=Wed, 06-May-2020 07:37:34 GMT; path=/
X-Robots-Tag: noindex
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block; report=/feedback/http-csp-report.php
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Referrer-Policy: strict-origin
Feature-Policy: autoplay 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; usb 'none'; vibrate 'none';
Content-Security-Policy-Report-Only: default-src 'self' data: *.googletagmanager.com *.google.com *.google-analytics.com  *.googleapis.com *.gstatic.com *.doubleclick.net mc.yandex.ru api-maps.yandex.ru yastatic.net webvisor.com *.calltouch.ru *.usedesk.ru *.youtube.com *.ytimg.com 'nonce-counters' 'report-sample'; img-src https: data: blob: ; report-uri /feedback/http-csp-report.php
Content-Type: text/html; charset=utf-8

Connection closed by foreign host.

Что мы видим?! Нет у Яндекс никаких Server: ***, X-Powered-By: PHP/5.4.16
У Google есть Server. И у Гугла есть бесполезный редирект на домен третьего уровня www, который в России давно умер. Приятно, что здесь в России больше логики, чем на Западе.
Никакого смысла сообщать какой у вас сервер и какое ПО (программное обеспечение) на нём используется нет. Наоборот, это вредно, т.к. если на сайте используется устаревшее ПО, то хакерам,
автоматическим сканерам это только поможет во взломе вашего сайта. К таким заголовкам относится ещё Via, который могут добавлять прокси-сервера.

Заголовок Server в Apache можно заменить перекомпилировав исходный код. Заголовок находится в файле include/ap_release.h. Но это сложно.
Можно сократить информацию до просто Apache с помощью настройки ServerTokens Prod.
Можно с помощью mod_security добавить в конфигурацию строку:
SecServerSignature «ITSOFT»

Чтобы убрать X-Powered-By в
php.ini установите set expose_php = Off
или в самом php-файле вызовите header_remove(«X-Powered-By»);

Expires: — лишён давно смысла, т.к. в RFC2616 page-127 записано: «Note: if a response includes a Cache-Control field with the max-
age directive (see section 14.9.3), that directive overrides the
Expires field.» Cache-Control: max-age=0 переопределяет Expires. О кешировании мы поговорим отдельно ниже.

Если expires отключён, то браузер отправляет «if-modified-since» и веб-сервер сможет ответить 304 Not Modified.


ExpiresActive Off в .htaccess отключает заголовок Expires.’

Сжатие контента

Не все пользователи Интернет сидят на широполосных каналах. Может барахлить связь за счёт удаления от сотовой вышки, перегрузки каналов, большого расстояние, поэтому необходимо включить сжатие текстовых файлов.
Картинки сжимать смысла нет, они и так уже сжаты.

 <ifModule mod_deflate.c>
	AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/css text/javascript application/javascript application/x-javascript
</ifModule>

Заголовки для безопасности

В настройки VirtualHost полезно добавить:
Header set X-Frame-Options DENY
Этот заголовок указывает браузеру, что сайт запрещено загружать в <frame>, <iframe>, <embed> or <object>.
Это должно защитить пользователя от Clickjacking-атак.

В настройки VirtualHost полезно ещё добавить:
Header set X-Content-Type-Options nosniff
Этот заголовок указывает браузеру, что не нужно пытаться понять какой контент пришёл и исполнить его. Например, не нужно выполнять javascript, который пришёл как plaintext.
Подробнее см. тут.

Следующая опция включит в браузере защиту и блокировку от XSS-атак.
Header set X-XSS-Protection «1; mode=block»
X-XSS-Protection: 1; report=https://itsoft.ru/r.php можно задать URL куда браузер отправит отчёт в случае обнаружения атаки.

Очень важная настройка запрещает браузеру коннектиться к сайту по HTTP, т.е. обязывает использоваться только HTTPS. О важности SSL было рассказано в статье Зачем нужны SSL-сертификаты.
Header set Strict-Transport-Security «max-age=63072000; includeSubDomains; preload»

  • max-age указывает, что браузер должен запомнить данный заголовок на два года.
  • includeSubDomains говорит, что это правило распространяется и на поддомены.
  • preload — это гугловская фишка, в спецификации отсутствует, домен попадёт в базу, которую используют Chrome, Firefox и Safari.

Опция Referrer-Policy указывает браузеру как отправлять HTTP_REFERER. Позволяет скрыть данные QUERY_STRING. Может принимать следующие значения:

  • no-referrer — referer передаваться не будет, наверное, это для интравертов и каких-то секретных закрытых сайтов.
  • no-referrer-when-downgrade — так браузер ведёт по-умолчанию. Полный URL с QUERY_STRING посылается в случаях перехода с HTTP→HTTP, HTTPS→HTTPS, HTTP→HTTPS. И не посылается при переходы из HTTPS→HTTP.
  • origin — посылается только доменное имя.
  • origin-when-cross-origin — посылается полностью при переходе по внутренним ссылкам, в прочих случаях посылается — только доменное имя.
  • same-origin — посылается полностью при переходе по внутренним ссылкам, в прочих случаях не посылается.
  • strict-origin — посылается только доменное имя, но только когда одинаковые протоколы HTTP→HTTP, HTTPS→HTTPS.
  • strict-origin-when-cross-origin — посылается полностью при переходе по внутренним ссылкам, посылается только доменное имя, но только когда одинаковые протоколы HTTP→HTTP, HTTPS→HTTPS.

Если в нет никакой секретной информации в QUERY_STRING и вам важно, чтобы другие могли перейти на страницу с параметрами, то пойдёт и значение по-умолчанию.

Заголовок Feature-Policy указывает браузеру какими возможностями будет пользоваться сайт. К сожалению, некоторые значения можно переопределить в коде сайта.
Например, так <iframe src=»https://site.com» allow=»vibrate»>. Но заголовок сам по себе очень правильный.
Мы все испытываем боль с приложениями на смартфоне, которые запрашивают привилегий доступа сильно больше, чем им реально нужно.
Боль вызывают и сайты, которые хотят слать нотификации, спрашивают геолокацию, издают звуки и т.п., что нас раздражает.
Сайт как и приложение смартфона должен заранее честно предупредить о том, какую информацию он собирается запрашивать, какую точно не будет запрашивать.

Заголовок имеет следующий синтакис: Feature-Policy: <directive> <allowlist>
allowlist может принимать одно или несколько из следующих значений разделённых пробелом:

  • * — разрешено на данной странице и во всех iframe независимо оттого, какой сайт будет загружен в этих ифреймах;
  • ‘self’ — разрешено на данной странице и во всех iframe, если в iframe загружена страница с нашего сайта;
  • ‘src’ — только для iframe, только если в iframe загружена страница с нашего сайта;
  • ‘none’ — запрещено, наиболее разумное значение для многих опций :), сайт должен по-минимуму раздражать посетителя;
  • <origin(s)> — разрешает directive для определённого сайта или сайтов, сайты разделяются пробелами.

Ниже идёт список возможных настроек:

  • accelerometer — разрешено ли использовать документу Accelerometer интерфейс;
  • ambient-light-sensor — может ли документ собирать информацию об освещённости AmbientLightSensor интерфейс$
  • autoplay — разрешено и автопроигрывание через HTMLMediaElement;
  • battery — Navigator.getBattery();
  • camera — можно ли использовать камеру;
  • display-capture — можно ли использовать getDisplayMedia();
  • document-domain — можно ли установить document.domain;
  • encrypted-media — можно ли использовать Encrypted Media Extensions API (EME), Navigator.requestMediaKeySystemAccess();
  • execution-while-not-rendered — можно ли исполнять задачи в когда iframe невидим или display: none;
  • execution-while-out-of-viewport — выполнять ли задачи для элементов за пределами отображаемой области;
  • fullscreen — разрешено ли использовать Element.requestFullScreen();
  • geolocation — разрешено ли запрашивать геолокацию getCurrentPosition();
  • gyroscope — можно ли запрашивать положение устройства (смартфона);
  • layout-animations — можно ли отображать послойную анимацию;
  • legacy-image-formats — разрешено ли отображать изображения в устаревших форматах;
  • magnetometer — Magnetometer интерфейс;
  • microphone — микрофон;
  • midi — Web MIDI API, воспроизведение музыки;
  • navigation-override — https://www.w3.org/TR/css-nav/
  • oversized-images — можно ли отображать большие изображения, данная опция полезна на стадии отладки и тестирования сайта;
  • payment — Payment Request API;
  • picture-in-picture — можно ли проигрывать видео в режиме Picture-in-Picture;
  • publickey-credentials — можно ли использовать Web Authentication API;
  • sync-xhr — можно ли делать XMLHttpRequest requests;
  • unoptimized-lossy-images — отображать ли неоптимизированные изображения;
  • unsized-media — изображения, видео должны иметь размеры;
  • usb — WebUSB API;
  • vibrate — не поддерживается в браузерах;
  • vr — WebVR API, но на смену ему уже идёт WebXR;
  • wake-lock — можно ли использовать Wake Lock API, должно ли устройство переходить в режим энергосбережения
  • xr-spatial-tracking — WebXR Device API.

Некоторые возможности (accelerometer, ambient-light-sensor, battery, display-capture, encrypted-media, execution-while-not-rendered, execution-while-out-of-viewport,
fullscreen, gyroscope, layout-animations, magnetometer, navigation-override, picture-in-picture, publickey-credentials, vr, wake-lock, xr-spatial-tracking
) вообще непонятно зачем ограничивать.

Следующие опции полезно отключить, чтобы показать, что мы не вторгаемся в личное пространство посетителя и ничего не навязываем ему: autoplay, camera, geolocation, gyroscope,
magnetometer, microphone, midi, payment, usb, vibrate.

Header set Feature-Policy «autoplay ‘none’; camera ‘none’; geolocation ‘none’; gyroscope ‘none’; magnetometer ‘none’; microphone ‘none’; midi ‘none’; payment ‘none’; usb ‘none’; vibrate ‘none’;»

Для отладки и тестирования сайта полезными могут быть следующие опции: legacy-image-formats, oversized-images, unoptimized-lossy-images, unsized-media.
Но на продакшене их не стоит использовать.

Header set Feature-Policy «unsized-media ‘none’; oversized-images ‘none’; unoptimized-lossy-images ‘none’; unoptimized-lossless-images ‘none’;»

Заголовок Content Security Policy (CSP) это дополнительный уровень безопасности, который помогает обнаруживать и смягчать некоторые типы атак, включая межсайтовый скриптинг (XSS) и data injection атак.
Данный заголовок на самом деле не только защищает от исполнения встроенного JS-кода хакерами, но главным образом дисциплинирует разработчиков не разбрасывать JS-код где попало по тексту HTML-документа,
не встраивать его в
HTML-теги, не использовать eval(), а хранить javascript упорядоченно в подключаемых библиотеках JS-файлов. Тем самым реализуется полное разделение HTML и javascript, и мы жёстко запрещаем
плохие практики разработки. Также мы уменьшаем зависимость нашего сайта от контента на других сайтах.
Неприятно же когда на странице на отображается картинка, не исполняется JS, не отображаются шрифты, по причине того, что они была подгружены с другого сайта, а теперь их там удалили.

Далее рассмотрим примеры возможных настроек.

Content-Security-Policy: default-src ‘self’ — подгрузка файлов только с домена самого сайта, даже с поддоменов нельзя.

Content-Security-Policy: default-src ‘self’ *.trusted-site.ru — подгрузка файлов только с домена самого сайта и с поддоменов указанного сайта.

Content-Security-Policy: default-src ‘self’; img-src *; media-src mysite.ru mysite.org; script-src trusted-lib.com — подгрузка файлов с домена самого сайта,
картинок с любых сайтов (это уже плохая практика), картинок и видео с сайтов mysite.ru mysite.org, скрипты можно загружать с сайта trusted-lib.com.

Content-Security-Policy: default-src https://itsoft.ru — подгрузка файлов только с указанного домена и обязательно по протоколу https.

Content-Security-Policy: default-src ‘self’ *.oursite.ru; img-src * — подгрузка файлов только с домена самого сайта и поддменов *.oursite.ru, картинок откуда угодно.

Content-Security-Policy: default-src ‘self’; report-uri https://itsoft.ru/report-csp.php — указывается скрипт, куда браузер будет отправлять отчёты о нарушении правил.
Отчёт будет отправлен методом POST в формате JSON. В нашем скрипте можно просто перенаправить этот отчёт в почту или Slack разработчикам.
На первое время можно задать правила в заголовке Content-Security-Policy-Report-Only, чтобы получать только отчеты.
Content-Security-Policy-Report-Only: default-src ‘self’; report-uri https://itsoft.ru/report-csp.php

Список возможных директив:

  • default-src
  • script-src
  • object-src
  • style-src
  • img-src
  • media-src
  • frame-src
  • font-src
  • connect-src

Чтобы запретить использование объектов нужно добавить object-src ‘none’. Для script-src можно использовать значение unsafe-inline и unsafe-eval.
Это разрешит использование встроенных скриптов, ухудшит дисциплину разработчиков, гарантирует бардак в коде.
Для style-src можно использовать unsafe-inline. Лучше эти значения не использовать для новых проектов.

Content-Security-Policy: upgrade-insecure-requests — это аналог Strict-Transport-Security.

Заголовки Last-Modified и Content-Length

Заголовки Last-Modified и Content-Length сообщаю когда документ был изменён последний раз и его размер. Поисковые роботы и браузеры отправляют в запросе заголовок If-Modified-Since, на который веб-сервер
может либо выдать новую страницу либо 304 Not Modified.
Для статических файлов эти параметры определяются легко.

Content-Type: image/png
Content-Length: 5922
Last-Modified: Mon, 27 Jan 2020 10:48:16 GMT

Сложнее с динамическими файлами, например с php. ETag взаимосвязан с датой последней модификации и размером содержимого. Поэтому всё же определять эти значения придётся.
Во всех инструкциях по настройке кеширования сайта, которые нам удалось прочитать, этому вопросу не уделялось внимание. Предполагалось, что дата последней модификации известна.
Однако это не так. И это очень непростой вопрос.
Проблема в том, что дата последней моификации файла зависит от всех подключаемых php-файлов, от данных в базе данных, от заголовков запроса браузера, кук, IP-адреса посетителя,
курсов валют, времени, сторонних сервисов.

Для php можно использовать следующий код, который выдаст дату последней модификации всех подключаемых файлов:


<?php
function getLastModified() {
$all = get_included_files();
$all = array_filter($all, "is_file");
$lms = array_map('filemtime', $all);
$lm = max($lms);

return $lm;
}
?>

Может изменяться сам код php-файла, а данные и html-код которые он выдаёт могут не измениться. В этом случае неправильно говорить, что Last-Modified изменился.
Но для простоты можно считать, что любое изменение файла ведёт к изменению Last-Modified.
Для данных мы должны ориентироваться на дату изменения данных в строке таблицы. Эта задача может быть нетривиальной для страниц, где отображается множество данных из разных таблиц.
Но если страница отображает одну сущность, например, конкретную новость, статью, счёт, платёж, то там дата последней модификации известна. Для страниц,
где собирается множество данных из разных таблиц нужно иметь таблицу в которой lastmodified соответствующей строки будет обновляться триггером.

Можно ориентироваться на хеш от выдаваемых данных. Если хеш md5 изменился, то меняем Last-Modified. Эту задачу лучше всего поручить проксирующему серверу Nginx.

Для проверки ответов веб-сервер вы можете испоьзовать следующие команды:

  • curl -I —header ‘If-Modified-Since: Mon, 30 Apr 2029 18:13:12 GMT’ https://itsoft.ru
  • curl -I —header ‘If-None-Match: «a49f2da878be351c6c73a1ec0524d8ea»‘ https://itsoft.ru
  • curl -I —header ‘Accept-Encoding: gzip’ https://itsoft.ru

Заголовки для кеширования

Когда веб-сервер отдаёт какой-нибудь файл: картинку, css, js или контент страницы, то он должен сказать сколько можно хранить эти данные в кеше.
Картинки можно хранить там вечно, они никогда не изменяются. Многие любят выдавать запрет на кеширование в виде заголовков:

Cache-Control: no-cache,no-store,max-age=0,must-revalidate
Expires: -1
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Pragma: no-cache

На самом деле, смысла в этом никакого нет для большинства данных, только нагрузка на сервер. И не надо бояться сказать, что файл или страницу сайта можно закешировать.

Во-первых, потому что браузер при следующем обращении к этому контенту при условии, что время хранения кеша просрочено спросит: «а не изменился ли ресурс с момента последнего моего запроса».
И если не изменился, то веб-сервер должен вернуть заголовок 304 Not Modified и не отправлять запрашиваемый файл.
Во-вторых, пользователь всегда может нажать обновить страницу и принудительно послать запрос к серверу не уточняя изменился ресурс или нет.

Важно только правильно определить время хранения кеша. В решение этого вопроса можно исходить из того как часто обновляются данные и насколько это важные данные.
Что случится, если посетитель увидит обновление с опозданием. Какое это разумное опоздание? Подавляющее большинство страниц в интернете чаще умирает, чем обновляется.
Обновляются ленты новостей, а страница с конкретной новостью живёт вечно. Поэтому для подобных страниц можно смело выставить время жизни веша сутки или неделю, т.е. то
разумное время в которое посетитель может вернуться на эту страницу или ваш сайт.

Итак, давайте рассмотрим как браузер спросит не изменился ли запрашиваемый ресурс. Для этого есть два варианта.
Первый — отправить в запросе If-Modified-Since с датой предыдущего запроса.
Второй — отправить в запросе If-None-Match с меткой ETag, которую он получил при предыдущем обращении.

При ответе веб-серве посылает следующие заголовки:

ETag: "1722-59d1cd83fc41f"
Cache-Control: max-age=31536000, public

ETag — является уникальной меткой, а Cache-Control сообщает можно ли хранить кеш на промежуточных прокси-сервера и сколько его можно хранить.

Итак, самый последний вопрос в который мы упёрлись — это сколько можно хранить кеш. На этот вопрос мы должны ответить в зависимости от контента и конкретных страниц нашего сайта.
Для статических файлов max-age=31536000 в один год представляется вполне разумным. При этом сами файлы нужно либо подключать с параметром времени последней модификации либо изменять их имя после модификации.
Для вывода параметра последней модификации файла можете использовать функцию:


function printFilenameWithTimestamp($filename)
{
print "$filename?t=" . date('U', filemtime($_SERVER['DOCUMENT_ROOT'] . $filename));
}

В .htaccess укажите:

    Header set Cache-Control "max-age=31536000, public"

В заголовой php-скрипта добавьте следующий код если он не обращается к базе и не зависит от других сервисов.


$last_modified = gmdate('D, d M Y H:i:s', getlastmod());

$etag = md5($last_modified);
if($_SERVER['REQUEST_METHOD']=='GET')
{
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && ($_SERVER['HTTP_IF_NONE_MATCH'] == $etag))
{
header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
exit();
}

if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime(substr($_SERVER['HTTP_IF_MODIFIED_SINCE'], 5))>=strtotime("$last_modified GMT"))
{
header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
exit;
}
}

header('Cache-Control: max-age=604800, public');
header("Last-Modified: $last_modified GMT");
header("Etag: $etag");

Vary: Accept-Encoding

Vary: Accept-Encoding по сути обязательный заголовок, т.к. сейчас все веб-серверы поддерживают свжатие контента. Способ сжатия зависит от поддерживаемых браузером способов, которые браузер
передаёт в заголовке Accept-Encoding. Но скорее всегого сервер добавит этот заголовок автоматически получив в запросе Accept-Encoding: gzip, deflate, br.

Итог

[root@localhost ~]# curl -I https://itsoft.ru
HTTP/1.1 200 OK
Server: nginx/1.16.0
Date: Tue, 05 May 2020 05:57:34 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Keep-Alive: timeout=200
Cache-Control: max-age=604800, public
Last-Modified: Wed, 01 Apr 2020 18:49:15 GMT
Etag: a49f2da878be351c6c73a1ec0524d8ea
Set-Cookie: a=1961012078; expires=Wed, 06-May-2020 05:57:34 GMT; path=/; secure; HttpOnly
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block; report=/feedback/http-csp-report.php
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Referrer-Policy: same-origin
Feature-Policy: autoplay 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; usb 'none'; vibrate 'none';
Content-Security-Policy-Report-Only: default-src 'self' data: *.googletagmanager.com *.google.com *.google-analytics.com  *.googleapis.com *.gstatic.com *.doubleclick.net mc.yandex.ru api-maps.yandex.ru yastatic.net webvisor.com *.calltouch.ru *.usedesk.ru *.youtube.com *.ytimg.com 'nonce-counters' 'report-sample'; img-src https: data: blob: ; report-uri /feedback/http-csp-report.php
X-Frame-Options: SAMEORIGIN
  • Программирование
    >
  • php
    >
  • Коды ответа сервера
  • Как изменить код ответа сервера
  • Если требуется перенаправить на другой url
  • Заголовки кодировки и языка
  • Модификация заголовков для управления контентом
  • Как влиять на СЕО

При серьезной разработке сайта возникает необходимость выдавать корректные http заголовки php средствами.
Вы спросите — зачем? Затем, что корректность HTTP-заголовков влияет на то, как будут понимать поисковые роботы получаемую с вашего сайта информацию, что напрямую влияет на продвижение сайта, т.е. на «СЕО».

ВАЖНО ПОМНИТЬ!
мордифицировать HTTP header с помощью языка php возможно только если директива header выводится на клиента до формировании страницы, то есть до вывода любой иной инофрмации.
В противном случае назначение нового статуса HTTP заголовку / header выдает ошибку.

Как изменить код ответа сервера.

В большинстве случаев заголовки изменяются непосредственно в ваших php функциях (методах).

<?php
function checkUrl( $url )
{
   if( preg_match( «/^http.*/i», $url ) == false )
       header( ‘Location: http://www.ru/404.html’ );
}

?>

Рассмотрим несколько примеров модификации HTTP заголовков.

Страница выполнена корректно

header( ‘HTTP/1.1 200 OK’ );

Запрашиваемая страница не найдена

header( ‘HTTP/1.1 404 Not Found’ );

Доступ запрещен:

header( ‘HTTP/1.1 403 Forbidden’ );

Страница перемещена навсегда.

Используется для корректировки урлов поисковых серверов.

header( ‘HTTP/1.1 301 Moved Permanently’ );

Сервер выполнил скрипт с ошибкой

header( ‘HTTP/1.1 500 Internal Server Error’ );

Если требуется перенаправить на другой url

Перенаправление на указанный адресу

header( ‘Location: http://www.ru/’ );

Перенаправление на указанный адрес с задержкой в 5 секунд

в принципе это калька HTML тега
<meta http-equiv=»refresh» content=»5;http://www.ru/ />

header( ‘Refresh: 5; url=http://www.ru/’ );

Заголовки кодировки и языка

Содержимое страницы использует язык:

header( ‘Content-language: en’ ); // en = English

Как поменять кодировку

header(‘Content-Type: text/html; charset=utf-8’);

Модификация заголовков для управления контентом

header( ‘Content-Type: application/octet-stream’ );
header( ‘Content-Disposition: attachment; filename=»example.zip»‘ );
header( ‘Content-Transfer-Encoding: binary’ );

Установка content type

header(‘Content-Type: text/plain’); // plain text file
header(‘Content-Type: image/jpeg’); // JPG picture
header(‘Content-Type: audio/mpeg’); // Audio MPEG (MP3,…) file
header(‘Content-Type: application/x-shockwave-flash’); // Flash animation

Иные манипуляции с заголовками

как средствами php изменять header для поисковых роботов

Содержимое страницы последний раз изменялось

header( ‘Last-Modified: ‘.gmdate( ‘D, d M Y H:i:s’, ( time() — 60 ) ).’ GMT’ );

Длинна содержимого страницы

header( ‘Content-Length: 2048’ );

Отключение кеширования страницы:

header( ‘Cache-Control: no-cache, no-store, max-age=0, must-revalidate’ );
header( ‘Expires: Mon, 1 Apr 2001 01:02:03 GMT’ );
header( ‘Pragma: no-cache’ );

  • Программирование
    >
  • php
    >
  • Коды ответа сервера

Понравилась статья? Поделить с друзьями:
  • Как изменить html через php
  • Как изменить homepath
  • Как изменить html файл на телефоне
  • Как изменить html файл на сервере
  • Как изменить html файл python