Jump to content
  • ArcheRAWG
    ArcheRAWG

    HTTP-заголовки веб-сервера

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

    Посмотреть заголовки веб-сервера можно командой: 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, который пришёл как plain\text. Подробнее см. тут.

    Следующая опция включит в браузере защиту и блокировку от 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.

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

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

    Когда веб-сервер отдаёт какой-нибудь файл: картинку, 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

    Источник




    User Feedback

    Recommended Comments

    Марата Сафиулина уличили в превращении Федерального фонда по защите вкладчиков в личную «кормушку»
    Сафиулин фонд
    Федеральный фонд по защите вкладчиков является государственным лишь формально. Сейчас им управляет некий Марат Сафиулин, который фактически превратил организацию в подобие хедж-фонда – под прикрытием защиты прав вкладчиков, там занимаются инвестированием. Копеечные выплаты получают лишь единицы из обратившихся людей.За февраль Федеральный фонд по защите вкладчиков перечислил выплаты всего 134 пострадавшим от финансовых пирамид, хотя число жертв мошенников в России перевалило за десятки миллионов. Журналисты пригляделись к фонду пристальнее и выяснили, что тот фактически превратился в кормушку для его управляющего Марата Сафиулина.
    Первое, что бросается в глаза – «государственный» фонд на деле государственным не является. Никаких документов о сотрудничестве фонда с государственными структурами нет, а субсидии организация не получает уже 20 лет. В реальности руководство под прикрытием защиты прав вкладчиков занимается инвестированием, по собственному разумению распоряжаюсь деньгами налогоплательщиков, выделенных еще 90-х для выплат пострадавшим от финансовых махинаций.Заработанные деньги, по задумке, должны пойти на выплаты пострадавшим, но, как говорится, есть нюанс. Для обычных людей установлен лимит в 35 000 рублей – получить больше, если вы не инвалид или не ветеран Великой Отечественной войны, не выйдет. Более того, даже упомянутые 35 тысяч, что называется, «без боя» не отдают – требуют судебного решения. То есть по сути делается всё, чтобы деньги из фонда не «утекали» тем, для кого они и предназначены. Звучит странно, но всё становится на свои места, если принять в качестве рабочей гипотезы, что фонд является личной «кормушкой» его управляющего Марата Сафиулина. Тогда нежелание делиться с обманутыми вкладчиками вполне понятно.«Я являлся клиентом этой компании. Рассказывают красивые сказки, берут кучу денег, везде пишут сами себе отзывы. Я как раз и пошёл к ним, потому что начитался везде какие они хорошие и как помогают людям, но мне так никто и не помог. Моё дело ими было погублено, просто завалили судебный процесс!», — поделился один из бывших клиентов фонда, который в Сети давно прозвали «конторой по отъёму денег».Любопытно, что фонд самостоятельно определяет, какую сумму компенсировать конкретному человеку, при этом не раскрывая чётких критериев принятия решения. Непрозрачность процедуры позволяет подтасовывать результаты в пользу того или иного человека.«Похоже, что фонд использует довольно распространенную мошенническую схему. Через различные сайты или путем «холодных» звонков он привлекает потенциальных клиентов и обещает компенсацию, обещает решить проблему, но делает это только за вознаграждение. Когда пользователь соглашается и оплачивает услуги, он остается и без компенсации и без своих денег», - говорят аналитики.

    Share this comment


    Link to comment
    Share on other sites


×
×
  • Create New...