master32

master32
Рейтинг
133
Регистрация
09.02.2022
Сергей #:

Спасибо!!! -50% трафика за месяц. На фоне блокировки моб. Трафика, хостинга, сайт вылетел с топа.

как говорится, меняй хостинг)
Приглашаем на вебинар про монетизацию сайтов в 16:00 мск
Уже сегодня: вебинар «Как находить точки роста в монетизации сайта»

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

https://vkvideo.ru/video-150593037_456240876
Александр Воробьев #:
Состояние на сегодня на github
скормил своему агенту и вот что он ответил:

Аудит joke-php/templator на коммите eecfa4b7dec3897f24dafa30cd450abada15fa0b

Короткое резюме

Коммит eecfa4b7dec3897f24dafa30cd450abada15fa0b реализует шаблонизатор с компиляцией AST в PHP и последующим include кэшированного файла. Ключевой риск не в классическом eval , а в цепочке compileFile() → сырой TextNode → include $cache->path : при неограниченном пути к шаблону это даёт чтение произвольных файлов, а при попадании в шаблон текста с <?php ... ?> — исполнение PHP-кода из “текстового” шаблона.

Топ-5 критичных/высоких проблем в этом коммите:

  1. LFI/path traversal через includeFile() / compileFile() : путь к шаблону никак не ограничен корнем шаблонов и читается напрямую через file_get_contents() .
  2. RCE через “обычный текст” шаблона: TextNodeHandler возвращает сырой текст без экранирования/нейтрализации PHP-тегов, а кэш затем исполняется через include .
  3. Расхождение compile vs render на отсутствующих ключах: compiled-mode генерирует прямой доступ вида $context['user']['name'] , тогда как render-mode идёт через resolveValue(..., $default) ; это ломает предсказуемость и приводит к предупреждениям PHP на пустых данных.
  4. Потеря внешних локальных переменных в вложенных foreach при компиляции: внутренний цикл затирает список localVars , из-за чего обращения к переменным внешнего цикла компилируются уже как $context[...] .
  5. {% csrf %} создаёт ложное ощущение защиты: код выводит только сырой токен, а не hidden-input; кроме того, compiled/render paths ведут себя по-разному при недоступных сервисах.


Нештатный путь к шаблону открывает чтение произвольных файлов.
TemplateEngine::includeFile() принимает $file, создаёт FileRelatedCache, а при отсутствии кэша зовёт compileFile($file, $context); compileFile() проверяет лишь file_exists($path) и затем делает file_get_contents($path). Ни template-root, ни realpath()-проверки, ни allowlist расширений тут нет.

Минимальный сценарий:

php

// Плохо: путь приходит извне
$engine->includeFile($_GET['tpl'], []);

// /page?tpl=../../../../etc/passwd



Короткая рекомендация: ограничить все template paths жёстким каталогом шаблонов, проверять realpath($path) на префикс корня, запрещать wrappers и принимать только ожидаемые расширения. Если библиотека сознательно низкоуровневая, это ограничение всё равно лучше реализовать в самом движке, а не делегировать приложению.

Сырый TextNode делает PHP-теги в шаблоне исполняемыми.
TextNodeHandler::compile() возвращает $node->content без изменений, а TemplateEngine::includeFile() затем исполняет кэшированный файл через include. Это означает, что шаблонный текст <?php ... ?> не выводится как текст, а реально выполняется в PHP-процессе.

Минимальный сценарий:

php

file_put_contents('/tmp/tpl.php', '<?php echo "PWNED"; ?>');
$engine->includeFile('/tmp/tpl.php', []);
// Ожидание от шаблонизатора: вывести literal text
// Фактически: выполнить PHP-код



Короткая рекомендация: при компиляции text nodes генерировать безопасный вывод, например <?php echo '...'; ?> через var_export($node->content, true), либо заранее отклонять любые PHP opening tags во входных шаблонах. В текущем виде это главный архитектурный дефект безопасности.

Compiled-mode и render-mode расходятся на отсутствующих ключах.
compileVarAccess() строит прямой код вида $context['user']['name'], а PrintNodeHandler слепо вставляет его в htmlspecialchars((string){$code}, ...); аналогично IfHandler делает (bool)($this->compileVarAccess(...)), а EachHandler компилирует foreach ({$arrayAccess} as ...). В интерпретаторе же везде используется resolveValue(..., $default), который возвращает default при отсутствии пути. В PHP 8.x чтение неопределённого ключа массива — это E_WARNING, а доступ к offset у null тоже даёт предупреждение.

Минимальный сценарий:

php

// Шаблон
{{ user.name }}

// Что генерирует компилятор по сути:
<?= htmlspecialchars((string)$context['user']['name'], ENT_QUOTES, 'UTF-8'); ?>

// Что делает render-mode:
$value = resolveValue($context, 'user.name', '', 'PrintNode'); // => ''



Короткая рекомендация: вынести общий helper safe-access и использовать его и в compiled-mode, и в render-mode. Иначе библиотека остаётся непредсказуемой: один и тот же шаблон на тех же данных ведёт себя по-разному в двух режимах.

Вложенный foreach теряет переменные внешнего цикла при компиляции.
В EachHandler::compile() после разбора аргументов список локальных переменных жёстко заменяется на [$valueVar] и, опционально, $keyVar; старые localVars не наследуются. В EachHandler::render() наоборот строится $iterationContext = $context и туда добавляются локалы; то есть интерпретатор внешнюю область видимости сохраняет, а компилятор — нет.

Минимальный сценарий:

twig

{% foreach user in users %}
  {% foreach role in roles %}
    {{ user }}
  {% /foreach %}
{% /foreach %}



Почему ломается:

php

// Внутри inner-foreach localVars уже только ['role'],
// поэтому {{ user }} компилируется не в $user, а в $context['user'].



Короткая рекомендация: вместо $localVars = [$valueVar]; использовать накопление области видимости, например array_values(array_unique([...$localVars, $valueVar, $keyVar])). Это исправит и compile/render parity, и вложенные циклы.

{% csrf %} не вставляет отправляемое поле формы и даёт ложную семантику безопасности.
Docblock обещает “генерацию скрытого поля или вывод токена”, но реализация compile() и render() фактически возвращает только строку токена: в compiled path делается echo $tokenManager->getServerToken($request);, а в render path возвращается сам токен. Браузер не отправляет “просто текст” из <form> как form field, поэтому такой API легко использовать неправильно и остаться без реальной CSRF-защиты.

Минимальный сценарий:

html

<form method="post">
  {% csrf %}
  <button>Save</button>
</form>



Фактический эффект:

html

<form method="post">
  3c6f4b...
  <button>Save</button>
</form>



Короткая рекомендация: либо сделать директиву полноценным hidden-input (<input type="hidden" name="_token" ...>), либо честно переименовать её в csrf_token и заставить разработчика явно оборачивать значение. Дополнительно стоит выровнять compile/render null-handling: сейчас compiled path сервисы проверяет, render path — уже нет.

Лексер имеет очевидную деградацию по производительности на больших шаблонах.
findNext() на каждой итерации перебирает все token descriptors и для каждого вызывает strpos($template, $descriptor->open, $pos); сам автор оставил TODO про производительность именно на этом месте. При двух маркерах проблема не катастрофична, но на больших шаблонах с длинными текстовыми сегментами это лишняя повторная работа.

Минимальный сценарий:

php

$template = str_repeat('a', 1_000_000) . '{{ user.name }}';



Короткая рекомендация: заменить “много strpos на каждом шаге” на линейный сканер или единый regex/token automaton. Это не security issue, но для engine-level кода уже заметная structural cost.

Инструментальная картина и покрытие тестами

В коммите есть PHPUnit, PHP-CS-Fixer и PHPStan: это видно по require-dev и composer scripts (test, stan, fixer, check). PHPStan настроен на level 8, PHPUnit — с coverage-репортами по ./src, а тестовое дерево покрывает Lexer, Parser, Handler, Compiler, Render, TemplateEngine и config/provider слои.

Но есть три явных пробела. Первый: Psalm не подключён вообще — ни зависимостью, ни конфигом. Второй: .phpstan.neon.dist исключает tests, хотя script stan формально запускает анализ и по tests; это снижает реальный эффект “analyse src tests”. Третий: в корне этого SHA не видно .github/workflows, то есть автоматический CI на самом коммите не просматривается.

По имеющемуся списку тестов видно, что unit-тесты по слоям есть, включая CsrfHandlerTest.php, IfHandlerTest.php, EachHandlerTest.php, PrintNodeHandlerTest.php и TemplateEngineTest.php. Однако по самим именам/видимым точкам входа не просматривается отдельного end-to-end покрытия на самые опасные сценарии этого аудита: literal <?php ... ?> внутри text node, path traversal через template path, parity compiled/render на отсутствующих ключах и parity nested-foreach по внешним локальным переменным. Это не доказательство полного отсутствия кейсов, но как минимум они не выделены в явные отдельные test targets.

Команды, которые разумно запускать для воспроизведения на локальном checkout этого SHA:

text

composer install
composer stan
composer fixer
composer test
# Psalm в этом коммите не настроен; для него сначала нужно добавить зависимость и конфиг.



Команды stan, fixer и test подтверждены в composer.json; отсутствие Psalm — тоже.

Вывод

Главная проблема этого коммита — не синтаксис шаблонов как таковой, а то, что движок компилирует текст шаблона в исполняемый PHP-файл и затем делает include, одновременно позволяя читать шаблон по произвольному пути. В сочетании это даёт сначала LFI/чтение любых локальных файлов, а затем и RCE при наличии PHP-кода в source text. Остальные важные проблемы — несогласованность compiled/render semantics, сбой областей видимости в вложенных циклах и misleading CSRF API.

Если исправлять по приоритету, то порядок такой: закрыть template path, запретить/нейтрализовать PHP в text nodes, унифицировать safe-access для compile/render, починить наследование localVars в foreach, переопределить семантику {% csrf %}, а затем уже добирать CI/Psalm/perf-оптимизации лексера. Это даст наибольший выигрыш и по безопасности, и по корректности, и по сопровождению.

wasex #:

Здравствуйте. такая же ерунда. Сайт более 10 лет В РСЯ тематика - учеба. небольшой но стабильный трафик.
В феврале решил попробовать автоматические рекламные блоки и через пару месяцев сайт блокируют.

Заблокировано Сайт или приложение не соответствует Правилам участия в РСЯ по иным причинам 

В поддержку обращался но там боты отвечают.

Есть ли возможность узнать больше информации о причинах и непонятна сама ситуация.

Cайт 10 лет соответствовал и вдруг одномоментно перестал соответствовать и его тут же блокируют без каких либо возможностей разобраться в ситуации.

бот принял решение, скорее всего перемодерация вручную тоже ничего не даст положительного эффекта, но попробовать написать в личку стоит https://searchengines.guru/ru/users/2068158
что делать:
снять РСЯ и метрику,
привести в порядок свой сайт,
через пару месяцев вернуть метрику и ждать от полугода письмо от РСЯ, что площадка может участвовать в программе)

Mik Foxi #:
если это статейник, то 50к цена будет много.
нет, это бесплатный сервис, 50к он принесет за 5 месяцев)
с того времени как я его пытался кому-то впарить за 200-300к (после ухода адсенса), он уже принес ~700-900к на РСЯ, то есть окупился на 200-300% и продолжает генерировать прибыль)

а чтоб облигации приносили ~100к в год, надо купить бумаг на 1кк

TonyBlackberry #:
это называется не сайт, а готовый бизнес. 
получается, что сайт это дизайн в виде картинок и html кода? есть мысли почему перестали покупать сайты?
TonyBlackberry #:
вы неправильно считаете. в случае покупки сайта через 5-7 лет у вас будет сайт и деньги, которые вы потратили на его покупку. а в случае облигаций или вкладов через 5-7 лет у вас будет в два раза больше денег. и при этом никакого риска.   а купленный вами сайт к тому времени может вообще обесцениться  
сайт = клиенты *без учета падения трафа и убыли клиентов
условно цены на мои товары/услуги/сервисы растут вместе с инфляцией,
а облиги и деньги стабильно сжирает инфляция, вопрос покроет ли процент доходности эту инфляцию или нет,

nikki4 #:
Но за неплохие сайты, что видел, хотят продать примерно за 5-7 лет окупаемости.
это и есть 15-20% годовых
ellienoise #:
Если нет ставок значит ваша "себестоимость" оторвана от текущих ожиданий по окупаемости) Снижайте старт до психологически комфортного минимума чтобы разжечь аукцион, иначе так и провисит мертвым грузом
за сколько купил бы сайт, стабильно приносящий 10к руб/месяц на РСЯ, последние 5 лет?
tish88 :
Может кто знает подобную реализацию? А может у кого-то из форумчан такое уже есть и могут предложить?
знаем, практикуем, используем, называется managed kubernetes)
Всего: 2129