Comments 34
А рядом сидит сурового вида парень в толстовке с капюшоном, который ворует чужие сессии через раздачу заражённого jquery с подогнанным хешем.
Именно из-за этого хэш использется только для проверки целостности и никак иначе
оф дока: www.w3.org/TR/2014/WD-SRI-20140318/#risks-1
С описанным по приведённым ссылкам (ещё раз спасибо!) вполне можно бороться. Там два типа атаки:
а) Обход CSP (расписан на примере XSS). По крайней мере тот пример, что там есть — смешно читать. Нейтрализуется простым правилом: наличие same-origin CSP влечёт запрет загрузки из хэш-кэша. Всё.
б) Брутфорс ожидаемых хэшей (например, некий сервер по GET-запросу (!) отдаёт пользователю идентификационные данные (!!)). Нейтрализуется тоже достаточно просто: если сервер разрешает хранить передаваемый субресурс в хэш-кэше, то он отдаёт специальный заголовок, например, Allow-Subresource-Sharing
(сокращённо — ASS-заголовок). Делается тремя строчками в htaccess, обратную совместимость не ломает, сделать такое случайно… Надо постараться. Хотя с тем, что всякие wp-admin.css
в хэш-кэш лучше не класть, спорить сложно.
Видимо, буду пытаться направить эти соображения туда… кстати, порекомендуйте, а куда лучше и через что?
1) Для нормальной работы кэша достаточно указать правильные заголовки — браузер не будет ничего грузить
2) Более сложные сценарии (в том числе работа offline) уже успешно решены с помощью WebSockets
- Обновил один файл стилей
- Пересобрал 10 страниц сайта, т.к. в теле каждой изменилось значение одного хеша.
Итого: вместо 1 файла, браузер должен будет обновить 11.
Имхо: если интернет настолько медленный, что даже ETags не затянуть, то можно считать, что его нет вообще.
jQuery со своего домена или с CDN?
Замечательный CDN от Cloudflare: https://cdnjs.com
Если же какой-то модифицированный jquery, то со своего сервера через тот же CF (на бесплатном тарифном плане).
Рекомендую к прочтению блогозапись «Почему Интернету нужен IPFS, пока ещё не поздно» и её обсуждение на Хабрахабре.
> или со своего домена.
> В первом случае уменьшается время загрузки сайта (в том числе первичной, т.е. при первом заходе посетителя на сайт) за счёт того,
> что файл с серверов Гугла с большой долей вероятности уже есть в кэше браузера.
Шанс того, что кеш браузера, заваленный добром от недавно просмотренных десятков сайтов, будет содержать именно тот файл с CDN, который лично данному сайту необходим, крайне невелик. Но пусть это не 1%, пусть целых 5% — т.е. у одного из 20 человек именно этот файл будет доступен на 0.2 сек быстрее.
Зато у 19 из 20 будут лишние задержки на DNS-поиск, возможное установление https-соединения с дополнительным хостом, плюс имеем риск недоступности файла с CDN — в общем, 19 из 20 посетителей имеют шанс получить ухудшение вместо улучшения.
Как по мне, так не та статистика, за которую надо владельцу малого и/или малопосещаемого сайта держаться. Лучше положить файлы js и стилей себе на сервер, объединить их и минифицировать, настроить сжатие (в идеале — gzip_static), настроить кеширование — положительный эффект будет куда большим!
А версионирование файлов легко и непринужденное делается через указание версии в URI файла (а не в GET-параметре, как это любят неотключаемо делать мамонты вроде Битрикса). Хоть в виде http://domain.tld/files/js/VERSION/file.js, хоть в виде http://domain.tld/files/js/file-VERSION.js — настроить веб-сервер на отдачу в каждом случае файла, лежащего по факту в /files/js/file.js (т.е. на игнорирование часто VERSION) несложно, а польза безо всяких расширений языка разметки (и реализации поддержки расширения в браузере) несомненна.
И, да, заголовок etag как раз и придуман для реализации того, что вы в своем предложении упоминаете. Только куда более прозрачно и с меньшим влиянием на процесс создания html-кода страницы.
Спасибо за развёрнутый комментарий!
Начну с конца.
etag:
а) требует запроса к серверу. Это время и трафик (пусть и мизерный). И нагрузка на сервер (тоже небольшая).
б) не позволяет разделять субресурсы (картинки, библиотеки и т. д.) между сайтами. А в этом есть определённая выгода. Некоторые библиотеки (и в первую очередь jQuery) действительно очень популярны и с очень большой долей вероятности окажутся в кэше. Размер jQuery достаточно невелик (в пределах 200 кБ, сжатая — и вовсе 32 кБ). Или, например, типовые смайлики на phpbb-форумах — за каждым отдельный запрос слать и etags сверять, учитывая, что такое добро наверняка уже в кэше валяется?
Вы знаете, сколько различных версий одной jQuery? Плюс минифицированные и полные варианты.
По одной версии на каждую актуальную версию вордпресса/джумлы и все остальные версии.
А вообще вопрос интересный, тянет на отдельную тему для исследования. Спасибо.
Часто заменяются на альтернативные.
Часто, но не всегда. Хотя согласен, что году эдак в 2007-м подобных повторяющихся элементов оформления было больше.
А если серьезно, вы поизучайте свой кеш. Да, jquery невелика (хотя как посмотреть!), но и экономия, кроме лишнего запроса, будет не смертельна. А вот вы посмотрите, каков размер кеша в вашем ПК, а каков в вашем телефоне, потом прикиньте, какой из вариантов jqeury туда надо поместить, чтобы многие сайты им воспользовались, и осознайте, сколько, глядя на объем запрашиваемых файлов любого современного сайта, вы каждым кликом по ссылке в вебе в кеше заменяете/удаляете.
CDN только Гугла отдает 54 (!!) версии jquery, да еще умножьте на 2 (протоколы поддерживаются и http, и https), да еще, наверное, у них есть и «просто», и «min»-версии. Таким CDN далеко не один, а минимум штуки 4-5 (я про самые популярные). Итого, если я зашел на один сайт, где с CDN грузилась jquery, а потом сразу на другой (где тоже jquery и тоже с CDN), то имеем вероятность примерно 1/500 — 1/1000, что библиотека jquery там и там — одна и та же, и на втором сайте не будет грузиться, т.к. загрузилась на первом. Это при условии, что кеш вообще объемен, и что-то хранит. Ну и да, теперь давайте подумаем, сколько в вашем кеше только под разные версии jqeury отведено места ))
Скажем прямо: идея унификации хороша, но в реальном мире проще не городить огороды. Вы боретесь с лишним http-запросом? Попросите сначала Яндекс с Гулом в своих счетчиках посещений сайта не делать столько http-перенаправлений :) — пользы для людей будет больше!
Про старые браузеры оговорено отдельно — едва ли их смутит новый атрибут. Хотя вот за IE не ручаюсь...
А если серьёзно, то спасибо, Вы меня окончательно убедили в том, что необходимо серьёзное исследование. С цифрами и фактами.
Понимаете, если у меня из-за нестабильного мобильного интернета отвалится счётчик Яндекса или Гугла — я переживать не буду, даже вряд ли замечу. А вот если jQuery — скорее всего, не смогу нормально пользоваться сайтом.
Сейчас унификация малоактуальна — нет контентной адресации. Вы совершенно верно указали на зоопарк CDN'ов. Теперь представим, что зачатки контентной адресации в виде предлагаемого хэш-кэша внедрены и начинают использоваться на некоторых сайтах. И вот в один прекрасный момент производитель некоторого мобильного браузера публикует список ресурсов (основных библиотек и шрифтов, например), которые будут захардкожены в кэш, основываясь на статистических данных. Естественно, что сайты, использующие именно эти библиотеки/шрифты, будут работать быстрее (в данном браузере), что создаёт стимул к унификации. Например, к переходу на несколько более новую (и распространённую) версию jQuery.
А также напрочь останавливает какой-либо прогресс.
Отнюдь. Вышла новая jQuery — прилетело обновление браузеру. В чём проблема?
В том, что тут же сломаются все сайты, что полагались на старую логику работы. При этом одним пользователям уже прилетело, а другим ещё не прилетело. Поддерживать обе версии одновременно — то ещё удовольствие.
Не сломаются. Хэш (в том числе ради обратной совместимости) страхуется классическим урлом субресурса.
А это тут при чём?
Процитирую статью:
<link href="//habracdn.net/habr/styles/1468852450/_build/topic_form.css" rel="stylesheet" media="all" checksum="ef4547a3d5731e77f5a1a19e0a6d89915a56cd3a"/>
Найдя в теле веб-страницы подобный тэг, браузер смотрит, есть ли объект с таким хэшем в кэше, и если есть, то не отправляет никаких запросов вообще.
Или, в нашем случае,
<script src="//somecdn.net/libs/jquery-9.9.9-max.js" checksum="004547a3d5731e77f5a1a19e0a6d89915a56cd3a"/>
(контрольная сумма — рандом).
Если у браузера нет в кэше файла с хэшем 004547a3d5731e77f5a1a19e0a6d89915a56cd3a
, то браузер честно идёт по указанному урлу, выкачивает оттуда файл и кэширует его. Если файл в кэше есть, он берётся оттуда.
Гипотетическое же обновление браузера заключается в том, что наиболее ожидаемые файлы попадают в кэш заранее и закрепляются там. Всё. Никакого нарушения обратной совместимости.
Версионирование файлов указанным способом — конечно, круто, но есть некоторые проблемы. Например, версионировать натуральным рядом не всегда оптимально: некоторые файлы при бампе версии могли не измениться. Остаётся версионировать хэшем. В итоге получаем то же решение, что и предлагаемое, но с двумя минусами:
а) версия и путь смешаны в кучу
б) нельзя разделять субресурсы
А фишка-то именно в разделении.
Кстати, а что Вы имеете против GET-параметра?
Кэш, хэш и няш-меш