Экзотичные заголовки HTTP

https://peteris.rocks/blog/exotic-http-headers/
  • Перевод

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

X-XSS-Protection


Атака XSS (межсайтовый скриптинг) это тип атаки, при котором вредоносный код может быть внедрён в атакуемую страницу.

Например вот так:

<h1>Hello, <script>alert('hacked')</script></h1>

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

И заголовок X-XSS-Protection управляет этим поведением браузера.

Принимаемые значения:

  • 0 фильтр выключен
  • 1 фильтр включен. Если атака обнаружена, то браузер удалит вредоносный код.
  • 1; mode=block. Фильтр включен, но если атака обнаружится, страница не будет загружена браузером.
  • 1; report=http://domain/url. фильтр включен и браузер очистит страницу от вредоносного кода, при этом сообщив о попытке атаки. Тут используется функция Chromium для отправки отчёта о нарушении политика защиты контента (CSP) на определённый адрес.

Создадим веб сервер-песочницу на node.js, чтобы посмотреть как это работает.

var express = require('express')
var app = express()

app.use((req, res) => {
  if (req.query.xss) res.setHeader('X-XSS-Protection', req.query.xss)
  res.send(`<h1>Hello, ${req.query.user || 'anonymous'}</h1>`)
})

app.listen(1234)

Буду использовать Google Chrome 55.

Без заголовка


http://localhost:1234/?user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E

Ничего не произойдёт, браузер успешно заблокирует атаку. Chrome, по умолчанию, блокирует угрозу и сообщает об этом в консоли.



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



X-XSS-Protection: 0


http://localhost:1234/?user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E&xss=0

О нет!



X-XSS-Protection: 1


http://localhost:1234/?user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E&xss=1

Страница была очищена из-за явного указания заголовка.



X-XSS-Protection: 1; mode=block


http://localhost:1234/?user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E&xss=1;%20mode=block

В этом случае атака будет предотвращена путём блокирования загрузки страницы.



X-XSS-Protection: 1; report=http://localhost:1234/report


http://localhost:1234/?user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E&xss=1;%20report=http://localhost:1234/report

Атака предотвращена и сообщение об этом отправлено по соответствующему адресу.



X-Frame-Options


При помощи данного заголовка можно защититься от так называемого Кликджекинга [Clickjacking].

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

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

Продемонстрируем это.

Сперва нужно установить расширение для игнорирования данного заголовка.

Создадим простую страницу.

<style>
button { background: red; color: white; padding: 10px 20px; border: none; cursor: pointer; }
iframe { opacity: 0.8; z-index: 1; position: absolute; top: -570px; left: -80px; width: 500px; height: 650px; }
</style>

<button>Do not click his button!</button>
<iframe src="https://youtu.be/dQw4w9WgXcQ?t=3m33s"></iframe>



Как можно заметить, я разместил фрейм с подпиской прям над кнопкой (z-index: 1) и поэтому если попытаться на неё нажать, то на самом деле нажмётся фрейм. В этом примере фрейм не полностью прозрачен, но это исправляется значением opacity: 0.

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

Для предотвращения страницы быть использованной во фрейме нужно использовать заголовок X-Frame-Options.

Принимаемые значения:

  • deny не загружать страницу вообще.
  • sameorigin не загружать, если источник не совпадает.
  • allow-from: ДОМЕН можно указать домен, с которого страница может быть загружена во фрейме.

Нам понадобится веб сервер для демонстрации

var express = require('express')

for (let port of [1234, 4321]) {
  var app = express()
  app.use('/iframe', (req, res) => res.send(`<h1>iframe</h1><iframe src="//localhost:1234?h=${req.query.h || ''}"></iframe>`))
  app.use((req, res) => {
    if (req.query.h) res.setHeader('X-Frame-Options', req.query.h)
    res.send('<h1>Website</h1>')
  })
  app.listen(port)
}

Без заголовка


Все смогут встроить наш сайт по адресу localhost:1234 во фрейм.



X-Frame-Options: deny


Страницу вообще нельзя использовать во фрейме.



X-Frame-Options: sameorigin


Только страницы с одинаковым источником смогут встраивать во фрейм. Источники совпадают, если домен, порт и протокол одинаковые.



X-Frame-Options: allow-from localhost:4321


Похоже, что Chrome игнорирует такую опцию, т.к. существует заголовок Content-Security-Policy (о ней будет рассказано ниже). Не работает это и в Microsoft Edge.

Ниже Mozilla Firefox.



X-Content-Type-Options


Данный заголовок предотвращает атаки с подменой типов MIME (<script src=«script.txt»>) или несанкционированного хотлинка (<script src=«https://raw.githubusercontent.com/user/repo/branch/file.js»>)

var express = require('express')
var app = express()

app.use('/script.txt', (req, res) => {
  if (req.query.h) res.header('X-Content-Type-Options', req.query.h)
  res.header('content-type', 'text/plain')
  res.send('alert("hacked")')
})

app.use((req, res) => {
  res.send(`<h1>Website</h1><script src="/script.txt?h=${req.query.h || ''}"></script>`)
})

app.listen(1234)

Без заголовка


http://localhost:1234/

Хоть script.txt и является текстовым файлом с типом text/plain, он будет запущен как скрипт.



X-Content-Type-Options: nosniff


http://localhost:1234/?h=nosniff

На этот раз типы не совпадают и файл не будет исполнен.



Content-Security-Policy


Это относительно молодой заголовок и помогает уменьшить риски атаки XSS в современных браузерах путём указания в заголовке какие именно ресурсы могут подргружаться на странице.

Например, можно попросить браузер не исполнять inline-скрпиты и загружать файлы только с одного домена. Inline-скрпиты могут выглядеть не только как <script>...</script>, но и как <h1 onclick="...">.

Посмотрим как это работает.

var request = require('request')
var express = require('express')

for (let port of [1234, 4321]) {
  var app = express()
  app.use('/script.js', (req, res) => {
    res.send(`document.querySelector('#${req.query.id}').innerHTML = 'изменено ${req.query.id}-скриптом'`)
  })
  app.use((req, res) => {
    var csp = req.query.csp
    if (csp) res.header('Content-Security-Policy', csp)
    res.send(`
      <html>
      <body>
        <h1>Hello, ${req.query.user || 'anonymous'}</h1>
        <p id="inline">это будет изменено inline-скриптом?</p>
        <p id="origin">это будет изменено origin-скриптом?</p>
        <p id="remote">это будет изменено remote-скриптом?</p>
        <script>document.querySelector('#inline').innerHTML = 'изменено inline-скриптом'</script>
        <script src="/script.js?id=origin"></script>
        <script src="//localhost:1234/script.js?id=remote"></script>
      </body>
      </html>
      `)
  })
  app.listen(port)
}

Без заголовка


Это работает так, как вы и ожидали



Content-Security-Policy: default-src 'none'


http://localhost:4321/?csp=default-src%20%27none%27&user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E

default-src применяет правило для всех ресурсов (картинки, скрипты, фреймы и т.д.), значение 'none' блокирует всё. Ниже продемонстрировано что происходит и ошибки, показываемые в браузере.



Chrome отказался запускать любые скрипты. В таком случае не получится даже загрузить favicon.ico.

Content-Security-Policy: default-src 'self'


http://localhost:4321/?csp=default-src%20%27self%27&user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E

Теперь можно использовать ресурсы с одного источника, но по прежнему нельзя запускать внешние и inline-скрипты.



Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'


http://localhost:4321/?csp=default-src%20%27self%27;%20script-src%20%27self%27%20%27unsafe-inline%27&user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E

На этот раз мы разрешили исполнение и inline-скриптов. Обратите внимание, что XSS атака в запросе тоже была заблокирована. Но этого не произойдёт, если одновременно поставить и unsafe-inline, и X-XSS-Protection: 0.



Другие значения


На сайте content-security-policy.com красиво показаны множество примеров.

  • default-src 'self' разрешит ресурсы только с одного источника
  • script-src 'self' www.google-analytics.com ajax.googleapis.com разрешит Google Analytics, Google AJAX CDN и ресурсы с одного источника.
  • default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self'; разрешит изображения, скрипты, AJAX и CSS с одного источника и запретит загрузгу любых других ресурсов. Для большинства сайтов это хорошая начальная настройка.

Я этого не проверял, но я думаю, что следующие заголовки эквиваленты:

  • frame-ancestors 'none' и X-Frame-Options: deny
  • frame-ancestors 'self' и X-Frame-Options: sameorigin
  • frame-ancestors localhost:4321 и X-Frame-Options: allow-from localhost:4321
  • script-src 'self' без 'unsafe-inline' и X-XSS-Protection: 1

Если взглянуть на заголовки facebook.com или twitter.com, то можно заметить, что эти сайты используют много CSP.

Strict-Transport-Security


HTTP Strict Transport Security (HSTS) это механизм политики безопасности, который позволяет защитить сайт от попытки небезопасного соединения.

Допустим, что мы хотим подключиться к facebook.com. Если не набрать перед запросом https://, то протокол, по умолчанию, будет выбран HTTP и поэтому запрос будет выглядеть как http://facebook.com.

$ curl -I facebook.com
HTTP/1.1 301 Moved Permanently
Location: https://facebook.com/

После этого мы будем перенаправлены на защищённую версию Facebook.

Если подключиться к публичной WiFi точке, которая принадлежит злоумышленнику, то запрос может быть перехвачен и вместо facebook.com злоумышленник может подставить похожую страницу, чтобы узнать логин и пароль.

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

$ curl -I https://www.facebook.com/
HTTP/1.1 200 OK
Strict-Transport-Security: max-age=15552000; preload

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

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

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

Можно отправить свой домен по этому адресу. Там также можно узнать правильно ли используется заголовок.

Принимаемые значения:

  • max-age=15552000 время, в секундах, которое браузер должен помнить о заголовке.
  • includeSubDomains Если указать это опциональное значение, то заголовок распространяется и на все поддомены.
  • preload если владелец сайта хочет, чтобы домен попал в предопределённый список, поддерживаемый Chrome (и используемый Firefox и Safari).

А если потребуется переключиться на HTTP перед сроком истечения max-age или если установлен preload? Можно поставить значение max-age=0 и тогда правило перехода на https версию работать перестанет.

Public-Key-Pins


HTTP Public Key Pinning (HPKP) это механизм политики безопасности, который позволяет HTTPS сайтам защититься от использования злоумышленниками поддельных или обманных сертификатов.

Принимаемые значения:

  • pin-sha256="<sha256>" в кавычках находится закодированный с помощью Base64 отпечаток Subject Public Key Information (SPKI). Можно указать несколько пинов для различных открытых ключей. Некоторые браузеры в будущем могут использовать и другие алгоритмы хеширования, помимо SHA-256.
  • max-age=<seconds> время, в секундах, которое браузер запоминает что для доступа к сайту нужно использовать только перечисленные ключи.
  • includeSubDomains если указать этот необязательный параметр, то заголовок действует и на все поддомены.
  • report-uri="<URL>" если указать URL, то при ошибке проверки ключа, соответствующее сообщение отправится по указанному адресу.

Вместо заголовка Public-Key-Pins можно использовать Public-Key-Pins-Report-Only, в таком случае будут отправляться только сообщения об ошибках совпадения ключей, но браузер всё равно будет загружать страницу.

Так делает Facebook:

$ curl -I https://www.facebook.com/
HTTP/1.1 200 OK
...
Public-Key-Pins-Report-Only: 
      max-age=500; 
      pin-sha256="WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18="; 
      pin-sha256="r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E="; 
      pin-sha256="q4PO2G2cbkZhZ82+JgmRUyGMoAeozA+BSXVXQWB8XWQ="; 
      report-uri="http://reports.fb.com/hpkp/"

Зачем это нужно? Не достаточно ли доверенных центров сертификации (CA)?

Злоумышленник может создать свой сертификат для facebook.com и путём обмана заставить пользователя добавить его в своё хранилище доверенных сертификатов, либо он может быть администратором.

Попробуем создать сертификат для facebook.

sudo mkdir /etc/certs
echo -e 'US\nCA\nSF\nFB\nXX\nwww.facebook.com\nno@spam.org' | \
  sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout /etc/certs/facebook.key \
    -out /etc/certs/facebook.crt

И сделать его доверенным в локальной системе.

# curl
sudo cp /etc/certs/*.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
# Google Chrome
sudo apt install libnss3-tools -y
certutil -A -t "C,," -n "FB" -d sql:$HOME/.pki/nssdb -i /etc/certs/facebook.crt
# Mozilla Firefox
#certutil -A -t "CP,," -n "FB" -d sql:`ls -1d $HOME/.mozilla/firefox/*.default | head -n 1` -i /etc/certs/facebook.crt

А теперь запустим веб сервер, использующий этот сертификат.

var fs = require('fs')
var https = require('https')
var express = require('express')

var options = {
  key: fs.readFileSync(`/etc/certs/${process.argv[2]}.key`),
  cert: fs.readFileSync(`/etc/certs/${process.argv[2]}.crt`)
}

var app = express()
app.use((req, res) => res.send(`<h1>hacked</h1>`))
https.createServer(options, app).listen(443)

Переключимся на сервер

echo 127.0.0.1 www.facebook.com | sudo tee -a /etc/hosts
sudo node server.js facebook

Посмотрим что получилось

$ curl https://www.facebook.com
<h1>hacked</h1>

Отлично. curl подтверждает сертификат.

Так как я уже заходил на Facebook и Google Chrome видел его заголовки, то он должен сообщить об атаке но разрешить страницу, так?



Неа. Ключи не проверялись из-за локального корневого сертификата [Public-key pinning bypassed]. Это интересно…

Хорошо, а что насчёт www.google.com?

echo -e 'US\nCA\nSF\nGoogle\nXX\nwww.google.com\nno@spam.org' | \
  sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout /etc/certs/google.key \
    -out /etc/certs/google.crt
sudo cp /etc/certs/*.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
certutil -A -t "C,," -n "Google" -d sql:$HOME/.pki/nssdb -i /etc/certs/google.crt
echo 127.0.0.1 www.google.com | sudo tee -a /etc/hosts
sudo node server.js google

Тот же результат. Думаю это фича.

Но в любом случае, если не добавлять эти сертификаты в локальное хранилище, открыть сайты не получится, потому что опции продолжить небезопасное соединение в Chrome или добавить исключение в Firefox не будет.





Content-Encoding: br


Данные сжаты при помощи Brotli.

Алгоритм обещает лучшее сжатие чем gzip и сравнимую скорость разархивирования. Поддерживается Google Chrome.

Разумеется, для него есть модуль в node.js.

var shrinkRay = require('shrink-ray')
var request = require('request')
var express = require('express')

request('https://www.gutenberg.org/files/1342/1342-0.txt', (err, res, text) => {
  if (err) throw new Error(err)
  var app = express()
  app.use(shrinkRay())
  app.use((req, res) => res.header('content-type', 'text/plain').send(text))
  app.listen(1234)
})

Исходный размер: 700 Кб
Brotli: 204 Кб
Gzip: 241 Кб





Timing-Allow-Origin


С помощью Resource Timing API можно узнать сколько времени заняла обработка ресурсов на странице.

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

<script>
setTimeout(function() {
  console.log(window.performance.getEntriesByType('resource'))
}, 1000)
</script>

<img src="http://placehold.it/350x150">
<img src="/local.gif">

Похоже, если не указать Timing-Allow-Origin, то получить детальную информацию о времени операций (поиска домена, например) можно только для ресурсов с одним источником.



Использовать можно так:

  • Timing-Allow-Origin: *
  • Timing-Allow-Origin: http://foo.com http://bar.com

Alt-Svc


Альтернативные Сервисы [Alternative Services] позволяют ресурсам находиться в различных частях сети и доступ к ним можно получить с помощью разных конфигураций протокола.

Такой используется в Google:

  • alt-svc: quic=":443"; ma=2592000; v=«36,35,34»

Это означает, что браузер, если захочет, может использовать QUIC, это HTTP над UDP, через порт 443 следующие 30 дней (ma = 2592000 секунд, или 720 часов, т.е 30 дней). Понятия не имею что означает параметр v, версия?

P3P


Ниже несколько P3P заголовков, которые я встречал:


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

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

Я не стал слишком углубляться, но видимо заголовок нужен для IE8 чтобы принимать cookies третьих лиц.

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

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

Какие из перечисленных HTTP заголовков Вы используете в проектах?
Поделиться публикацией
Комментарии 35
    0
    видимо заголовок нужен для IE8 чтобы принимать cookies третьих лиц.

    Да, именно для этого однажды его использовал.
      –4
      Благодарю, очень познавательно!
      Интересно, а есть возможность внедрять на серверы антивирусы, и каждый сайт таким образом может быть в доверенной зоне для пользователя (например логотип антивируса внизу страницы, означающий, что текущий сайт безопасен)
        +3
        и что помешает НЕбезопасному сайту отдать такой же логотип?
          0
          Смысл конечно же не в логотипе. Функциональность его очевидно будет в том, что он будет кликабельным — и приведёт в список доверенных сайтов по версии какого-нибудь антивирусного пакета «Dr.Internet». Далее суть остаётся в следующей выжимке: существует некий антивирусный пакет, который устанавливается на сеервер и работает со всем прочим софтом. Он круглосуточно занимается мониторингом кода на сервере, и при обнаружении опасности действует типично для антивируса. Для пользователя же данная система будет неким залогом надёжности сайта. Таким образом — хостер становится клиентом, покупающим софт у разработчика антивируса, а разработчик антивируса лицензирует данный сервер. Пользователи сайта же больше привлекаются к лицензированным сайтам.
          Когда, я читаю идеи некоторых людей в постах — мне интересно поучаствовать в их развитии, почему бы нет, зачем сразу кидаться, что это не работает :)
          0
          Теоретически есть такая фигня, как WOT…
            +7
            боюсь что уже нет
              0
              Ожидаемо бывает…
              +2
              Они себя дискредитировали.
                0
                Жизнь — боль… ;))
            +7
            И что в этих заголовках экзотического? Они есть на многих сайтах.
              +1
              Думаю было бы не плохо в конце статьи собрать в список все рассмотренные запросы и рекомендуемые для них значения. А статья информативная получилась, жаль кармы не хватает для того чтобы плюсануть её.
                +3
                Всё зависит от ресурса, какие требования и ограничения на нём должны быть. Для большинства сайтов хватит и одного:
                Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self'; frame-ancestors 'none'
                С Content-Encoding и с сжатием, поддерживаемым браузером, который можно узнать, прочитав заголовок запроса Accept-Encoding

                Если планируется, что сайт должен быть вставлен как фрейм или допустим embed, то frame-ancestors 'none' нужно исключить.

                А если используется https, то тут нужен обязательно Strict-Transport-Security и желательно Public-Key-Pins

                  +1
                  Спасибо, будем пробовать )
                    +1

                    PKP это, вообще, плохая идея для "желательно". С PKP можно достаточно легко накосячить так что вы навсегда потеряете домен. Я бы советовал очень хорошо перед этим подумать, и потестить конфигурацию где-то вдалеке от продакшена.

                      0
                      Большинство сайтов перестанут нормально работать без unsafe-inline в script-src, а с ним CSP теряет 99% профита. Но это сложная тема.
                    0
                    А на производительность в браузере никак не сказывается?
                      0
                      думаю, загрузка одного изображения больше нагрузит браузер, чем все перечисленные заголовки вместе взятые. К тому же когда речь идёт о безопасности, как правило, ресурсов не жалеют.
                      0
                      Есть ли в природе информация как эти заголовки могут влиять на seo?
                        0
                        Непонятен смысл Public-Key-Pins. Если уж злоумышленник заставил пользователя занести свой сертификат в доверенные, что ему мешает после этого устроить MitM, изменяя в отдаваемых пользователю страницах этот заголовок на отпечаток своего сертификата, или вообще их выкидывая? Или это от чего-то другого защищает?
                          0

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

                            0
                            Новые сертификаты и заголовки будут приняты браузером только после истечения max-age старых
                            +3

                            про Strict-Transport-Security


                            А если потребуется переключиться на HTTP перед сроком истечения max-age или если установлен preload? Не получится. Этот заголовок требует строгого соблюдения. Поэтому в этом случае пользователю придётся очистить историю и настройки.

                            Это ложь, если вам, как владельцу сайта, необходимо перейти на http, это делается очень просто: выставлением HSTS max-age=0 и редирект на http версию.
                            как-то так это выглядит в диалекте nginx


                                listen 443 ssl;
                                location / {
                                    rewrite ^ http://$host$uri redirect;
                                    add_header              Strict-Transport-Security   "max-age=0";
                            }
                              0
                              Это интересно. А прув есть? Просто автор утверждает обратное.
                                +1

                                Ну например, https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/. Однако, нужно понимать, что для отключения нужно передать этот заголовок в рамках нормально работающего https-сеанса, поэтому невозможно резко отключить HSTS, когда какой-то факап уже случился. Т.е. невозможно быстренько сделать вид, что никакого HSTS небыло, если забыл вовремя обновить обновить сертификат: нужно получать и устанавливать на сайт новый, и только с полностью работающим HTTPS можно будет, если всё ещё нужно, выставить max-age=0.

                                  0
                                  Да, действительно, спасибо за ссылку. Вот еще и в RFC то же написано.
                              –1
                              > если в исходном коде есть нечто похожее на запросы, то это может оказаться угрозой.

                              Лучше, думаю, не переводить вообще, чем переводить вот так. У вас вообще не объяснено как это работает и что это делает.
                                –1
                                За что купил, за то и продаю. Или вы хотите чтобы автор в одно предложение объяснил каким образом браузер находит XSS?
                                  0
                                  if you find a part of the request in the source code, it might be an attack.

                                  В оригинале идёт речь про конкретный запрос, почему у вас "запросы" во множественном числе?

                                    –2
                                    Да, хочу. Иначе зачем эта статья нужна? Это не какая-то эвристика или нейронная сеть, определяющая «угрозу», это очень простой алгоритм.

                                    Если в исходном коде страницы встречается аргумент из query string или path запроса без экранирования, то такая страница считается успешно атакованной XSS и не отображается пользователю.
                                      +1
                                      По-моему, это просто перевод, наверное, неплохой статьи. Требовать от переводчика разъяснений отдельных предложений было бы, скажем так, нежелательно.
                                        –1
                                        Я вроде требую от переводчика точного перевода.

                                        Было:
                                        if you find a part of the request in the source code

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

                                        Или вы считаете это достаточно точным?
                                          +1

                                          дело не в том, что вы требуете, а где вы требуете — об этом в личку пишут

                                  0
                                  По поводу Public-Key-Pins вы не очень хорошие примеры привели. facebook отдает только public-key-pins-report-only. Надо было смотреть что он в консоль вываливает при поддельных сертификатах. А google вообще никаких PKP в заголовках не отдает. Вот все и пропускается, видимо, с левыми сертификатами в локальных хранилищах.
                                    0

                                    github, например, отдаёт HPKP:


                                    Public-Key-Pins: max-age=5184000; pin-sha256="WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18="; pin-sha256="RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho="; pin-sha256="k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws="; pin-sha256="K87oWBWM9UZfyddvDfoxL+8lpNyoUB2ptGtn0fv6G2Q="; pin-sha256="IQBnNBEiFuhj+8x6X8XLgh01V9Ic5/V3IRQLNFFc7v4="; pin-sha256="iie1VXtL7HzAMF+/PVPR9xzT80kQxdZeJ+zduCB3uj0="; pin-sha256="LvRiGEjRqfzurezaWuj8Wie2gyHMrW5Q06LspMnox7A="; includeSubDomains
                                    0
                                    Тут выше поднимался вопрос про SEO. Вспомнил про заголовок X-Robots-Tag который по идее должен работать аналогично robots.txt

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

                                    Самое читаемое