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

в 10:23, , рубрики: CDN, Fastly, http-заголовки, Разработка веб-сайтов, Серверная оптимизация

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

Большинство разработчиков знают о важных и нужных HTTP-заголовках. Самые известные — Content-Type и Content-Length, это почти универсальные хедеры. Но в последнее время для повышения безопасности начали использоваться заголовки вроде Content-Security-Policy и Strict-Transport-Security, а для повышения производительности — Link rel=preload. Несмотря на широкую поддержку в браузерах, лишь немногие их используют.

В то же время есть много чрезвычайно популярных заголовков, которые вообще не новые и не очень полезные. Мы можем это доказать с помощью HTTP Archive, проекта под управлением Google и спонсируемого Fastly, который каждый месяц при помощи WebPageTest скачивает 500 000 сайтов и выкладывает результаты в BigQuery.

Вот 30 самых популярных заголовков ответов по данным HTTP Archive (на основе количества доменов в архиве, которые выдают каждый заголовок), и примерная оценка полезности каждого из них:

Заголовок Запросов Доменов Статус
date 48779277 535621 Требуется по протоколу
content-type 47185627 533636 Обычно требуется браузером
server 43057807 519663 Необязателен
content-length 42388435 519118 Полезен
last-modified 34424562 480294 Полезен
cache-control 36490878 412943 Полезен
etag 23620444 412370 Полезен
content-encoding 16194121 409159 Требуется для сжатого контента
expires 29869228 360311 Необязателен
x-powered-by 4883204 211409 Необязателен
pragma 7641647 188784 Необязателен
x-frame-options 3670032 105846 Необязателен
access-control-allow-origin 11335681 103596 Полезен
x-content-type-options 11071560 94590 Полезен
link 1212329 87475 Полезен
age 7401415 59242 Полезен
x-cache 5275343 56889 Необязателен
x-xss-protection 9773906 51810 Полезен
strict-transport-security 4259121 51283 Полезен
via 4020117 47102 Необязателен
p3p 8282840 44308 Необязателен
expect-ct 2685280 40465 Полезен
content-language 334081 37927 Спорно
x-aspnet-version 676128 33473 Необязателен
access-control-allow-credentials 2804382 30346 Полезен
x-robots-tag 179177 24911 Не имеет значения для браузеров
x-ua-compatible 489056 24811 Необязателен
access-control-allow-methods 1626129 20791 Полезен
access-control-allow-headers 1205735 19120 Полезен

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

Тщеславие (server, x-powered-by, via)

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

Server: apache
X-Powered-By: PHP/5.1.1
Via: 1.1 varnish, 1.1 squid

RFC7231 позволяет включать в ответ сервера заголовок Server, указывая конкретный софт на сервере, который используется для выдачи контента. Чаще всего это строка вроде "apache" или "nginx". Хотя заголовок разрешён, он не обязательный и не особо ценный для разработчиков или конечных пользователей. Тем не менее, сегодня это третий по популярности серверный HTTP-заголовок в интернете.

X-Powered-By — самый популярный заголовок из тех, что не определены никаким стандартом, и у него похожая цель: обычно он указывает платформу приложений, на которой работает сервер. Самые популярные ответы включают в себя "ASP.net", "PHP" и "Express". Опять же, это не несёт никакой ощутимой пользы и просто занимает место.

Возможно, более спорным можно считать Via. Его обязан (по RFC7230) добавлять в запрос каждый прокси, через который проходит запрос — для идентификации прокси. Это может быть имя хоста прокси, но чаще общий идентификатор вроде "vegur", "varnish" или "squid". Удаление (или не добавление) такого заголовка может привести к циклу переадресации прокси. Но интересно, что он также добавляется в ответ на обратном пути к браузеру — и здесь выполняет просто информационную функцию: никакие браузеры ничего не с ним делают, поэтому достаточно безопасно избавиться от него, если хотите.

Устаревшие стандарты (P3P, Expires, X-Frame-Options, X-UA-Compatible)

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

P3P: cp="this is not a p3p policy"
Expires: Thu, 01 Dec 1994 16:00:00 GMT
X-Frame-Options: SAMEORIGIN
X-UA-Compatible: IE=edge

P3P — забавная штучка. Я понятия не имел, что это такое. Ещё забавнее, что одно из самых распространённых содержаний заголовка P3P — «Это не правило P3P». Ну так это оно или нет?

Тут история восходит к попытке стандартизировать машиночитаемые правила приватности. Были разногласия по поводу того, как отображать данные в браузерах, и только один браузер реализовал поддержку этого заголовка — Internet Explorer. Но даже в нём P3P не имел никакого визуального эффекта для пользователя; он просто должен был присутствовать, чтобы разрешить доступ к сторонним кукам во фреймах. Некоторые сайты даже установили правила несоблюдения P3P, как в примере выше, хотя делать так весьма сомнительно.

Нечего и говорить, что чтение сторонних куков вообще обычно плохая идея, так что если вы этого не делаете, то вам и не нужно устанавливать заголовок P3P!

Expires просто невероятно популярен с учётом того, что Cache-Control имеет преимущество перед Expires уже в течение 20 лет. Если заголовок Cache-Control содержит директиву max-age, то любой заголовок Expires в том же ответе игнорируется. Но огромное количество сайтов устанавливает оба этих заголовка, а Expires чаще всего ставят на дату Thu, 01 Dec 1994 16: 00: 00 GMT, чтобы контент не кэшировался. Конечно, ведь проще всего копипастнуть дату из спецификаций.

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

Но просто незачем это делать. Если у вас заголовок Expires с датой из прошлого, просто замените его на:

Cache-Control: no-store, private

(no-store — слишком строгая директива не записывать контент в постоянное хранилище, так что вы можете предпочесть no-cache ради лучшей производительности, например, для навигации назад/вперёд или возобновления «спящих» вкладок в браузере)

Некоторые инструменты проверки сайтов посоветуют добавить заголовок X-Frame-Options со значением 'SAMEORIGIN'. Он говорит браузерам, что вы отказываетесь отдавать контент во фрейм на другом сайте: как правило, это хорошая защита от кликджекинга. Но того же эффекта можно достигнуть другим заголовком с более последовательной поддержкой и более надёжным поведением:

Content-Security-Policy: frame-ancestors 'self'

Здесь есть дополнительная выгода, потому что заголовок CSP вы всё равно должны отдавать по иным причинам (о них позже). Вероятно, в наше время можно обойтись без X-Frame-Options.

Наконец, ещё в IE9 компания Microsoft представила «режим совместимости», который отображал страницу с помощью движка IE8 или IE7. Даже в нормальном режиме браузер думал, что для правильного рендеринга может понадобиться более ранняя версия движка. Эти эвристики не всегда работали корректно, и разработчики могли переопределить их, используя заголовок или метатег X-UA-Compatible. Фактически, это стало стандартной частью многих фреймворков вроде Bootstrap. Сейчас этот заголовок практически бесполезен: очень мала доля браузеров, которые понимают его. И если вы активно поддерживаете сайт, то очень маловероятно, что на нём используются технологии, которые запустят режим совместимости.

Данные для отладки (X-ASPNet-Version, X-Cache)

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

X-Cache: HIT
X-Request-ID: 45a336c7-1bd5-4a06-9647-c5aab6d5facf
X-ASPNet-Version: 3.2.32
X-AMZN-RequestID: 0d6e39e2-4ecb-11e8-9c2d-fa7ae01bbebc

На самом деле, эти «неизвестные» заголовки не выдумали разработчики. Обычно это артефакты использования определённых серверных фреймворков, софта или сервисов конкретных поставщиков (например, последний заголовок типичен для AWS).

Заголовок X-Cache добавляет Fastly (и другие CDN), вместе с другими специфичными хедерами, такими как X-Cache-Hits и X-Served-By. Когда отладка включена, то добавляется ещё больше, например, Fastly-Debug-Path и Fastly-Debug-TTL.

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

Недоразумения (Pragma)

Не ожидал, что в 2018 году придётся упоминать заголовок Pragma, но согласно HTTP Archive он по-прежнему в топе (11-е место). Его не только объявили устаревшим ещё в 1997 году, но он вообще никогда не задумывался как заголовок ответа, а только как часть запроса.

Pragma: no-cache

Тем не менее его настолько широко используют в качестве заголовка ответа, что некоторые браузеры даже распознают его и в этом контексте. Но сегодня практически нулевая вероятность, что кто-то понимает Pragma в контексте ответа, но не понимает Cache-Control. Если хотите запретить кэширование, всё что вам нужно — это Cache-Control: no-store, private.

Не-браузеры (X-Robots-Tag)

Один заголовок в нашем топ-30 не является заголовком для браузера. X-Robots-Tag предназначен для краулеров, таких как боты Google или Bing. Поскольку для браузера он бесполезен, то можете установить такой ответ только на запросы краулеров. Или вы решите, что это затрудняет тестирование или нарушает условия использования поисковой системы.

Баги

Наконец, стоит закончить почётном упоминанием простых ошибок. Заголовок Host имеет смысл в запросе, но если он встречается в ответе, то вероятно ваш сервер неправильно настроен (и я хотел бы знать, как именно). Тем не менее 68 доменов в HTTP Archive возвращают заголовок Host в своих ответах.

Удаление заголовков на edge-сервере CDN

К счастью, если ваш сайт работает у нас на Fastly, то удалить заголовки довольно просто с помощью VCL. Если хотите сохранить команде разработчиков действительно полезные данные для отладки, но скрыть их от общей публики, то это легко делается по куки или входящему заголовку HTTP:

unset resp.http.Server;
unset resp.http.X-Powered-By;
unset resp.http.X-Generator;

if (!req.http.Cookie:debug && !req.http.Debug) {
unset resp.http.X-Amzn-RequestID;
unset resp.http.X-Cache;
}

В следующей статье я расскажу о лучших практиках для действительно нужных заголовков и как активировать их на edge-сервере CDN.

Автор: m1rko

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js