Из предыдущих материалов мы знаем, что в движке Joomla 3.x и до Joomla 5.x входящие параметры в ссылках вовсе никак не фильтруются - это позволяет забомбить кэш добавляя в ссылку лишние параметры и/или случайным образом изменяя их значения.
В журналах сервера неоднократно встречались запросы по-ссылкам типа:
https://example.com/itemlist?start=5540&url=770&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&start=5540&format=feed&type=atomОткуда боты берут такие ссылки, или создают их намеренно, - неизвестно. По-факту в кэш попадают все УРЛы, включая ссылки с дубликатами параметров и/или случайным образом изменёнными в них значениями.
Page Caching (плагин Система - Кэш) позволяет добавить исключения, которые реализованы в isExcluded() файла /plugins/system/cache/cache.php:
// Gets internal URI. $internal_uri = '/index.php?' . JUri::getInstance()->buildQuery($this->app->getRouter()->getVars());
$internal_uri получается примерно таким: /index.php?Itemid=666&option=com_k2&view=item&id=6666:article-alias-here
К $internal_uri добавляется $this->_cache_key, содержащее запрошенный УРЛ типа https://example.com/itemlist?start=666, потом перебирается массив с исключениями и выполняется проверка их наличия в строке:
if (preg_match('#' . $exclusion . '#i', $this->_cache_key . ' ' . $internal_uri, $match))
Поиск исключений идёт одновременно по внешнему https://example.com/article-alias-here и внутреннему /index.php?Itemid=666&option=com_k2&view=item&id=6666:article-alias-here адресам.
Поэтому кэш полностью отключится при наличии в исключениях одного из таких слов и/или символов, как:
- index
- option
- view
- item
- id
- itemid
- .
- /
- ?
- &
- =
- -
- :
В исключения можно добавить запятую и обратный слэш заэкранировав их следующим образом:
- \,
- \\
В исключения можно добавить названия компонентов (com_something), ключевые слова из веб-адресов не требующий кэширования (страница билинга например), и ещё что угодно. Но, исключения не спасут от попадания в кэш страниц по-ссылкам с лишними параметрами или дубликатами параметров типа start=5540&start=5540.
Обратить внимание также следует и на то, что параметры в разных регистрах, как например Start=5540&stART=5540 и start=5540&start=5540, будут считаться разными ссылками.
Для решения данной проблемы на всём фронтенде сразу предлагается добавить фильтр для серверных переменных $_SERVER['QUERY_STRING'] и $_SERVER['REQUEST_URI'] разместив его в файле /defines.php
// PREVENT BOMBING CACHE WITH PARAMS DUBLICATE if($_SERVER['QUERY_STRING']){ $allowKeys = [ 'start' => '', 'format' => '', 'option' => '', 'view' => '', 'layout' => '', 'limit' => '', 'link' => '', 'pop' => '', 'print' => '', 'task' => '', 'template' => '', 'tmpl' => '', 'tpl' => '', 'type' => '', 'id' => '', 'item' => '', 'itemid' => '', ]; // // Fix param in $_SERVER['QUERY_STRING'] parse_str(strtolower($_SERVER['QUERY_STRING']), $queryStr); if (count($queryStr) > 0) { foreach ($queryStr as $key => $value) { // isset() faster instead array_key_exists() if (!isset($allowKeys[$key])) { unset($queryStr[$key]); } elseif (!empty($value) && preg_match('/[^\w\d\ \-:]+/i', $value)) { // if param value contain not word or not digit or not some symbol // then access deny //header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden'); header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); header('Content-Type: text/html'); echo 'Invalid vaue (' . $value . ') for parameter (' . $key . ')!'; exit; } } } $_SERVER['QUERY_STRING'] = http_build_query($queryStr); // // Fix param in $_SERVER['REQUEST_URI'] $requestUri = parse_url($_SERVER['REQUEST_URI']); $_SERVER['REQUEST_URI'] = $requestUri['path'] . '?' . $_SERVER['QUERY_STRING']; }
Данный PHP код:
- Отбросит все параметры, которых нет в $allowKeys;
parse_str()попутно удалит все дубликаты параметров;strtolower()переведёт всё в нижний регистр;preg_match('/[^\w\d\ \-:]+/i', $value)для полноты счастья проверит значение на присутствие там запрещённых знаков и выдаст HTTP 403 или 404 если таковые обнаружатся;http_build_query()соберёт параметры обратно в строку.
Добавленный в /defines.php PHP код будет выполнен в самом начале работы движка и приведёт в Божеский вид параметры строки запроса в $_SERVER['QUERY_STRING'] и $_SERVER['REQUEST_URI'].
Всего с десяток строк кода, а выгоды так цельный вагон.

