disk 26.1150.0 Безопасность

Disk 26.1100.100 и 26.1150.0: SDK досок больше не шлёт JWT на любой origin, а секрет по умолчанию убран

2 мин чтения

Обновление безопасности

Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.

Диск приехал в коробку двумя версиями одним днём, 21 сентября 2026 года (по официальному каналу «Битрикс24 changelog»). В 26.1100.100 поменялась одна строка, и заметно это только на порталах с сессиями в режиме separated. 26.1150.0 закрывает канал postMessage в SDK досок, через который JWT и ссылка на файл уходили на любой origin, убирает из кода секрет JWT по умолчанию и запрещает встраивать редактор досок на чужие сайты.

Читать в первую очередь администраторам коробки со своим сервером досок. Если портал и сервер жили на секрете по умолчанию 'secret_token', после обновления они разойдутся по подписи JWT. Разработчикам нужно проверить вызовы StorageFileFinderOptions и свои копии шаблона редактора досок.

Сверьте секрет JWT с сервером досок

Document\Flipchart\Configuration::getJwtSecret() раньше подставлял 'secret_token', если секрет нигде не задан. Это значение лежало в коде и в секции boards файла .settings.php модуля, в 26.1150.0 его убрали из обоих мест.

Если секрет не задан ни в bitrix/php_interface/disk-boards.php, ни в конфигурации boards, ни в опции flipchart.jwt_secret модуля disk, метод при первом обращении генерирует sha1(random_bytes(32)) и сохраняет результат в эту опцию. В режиме облачного прокси (isUsingDocumentProxy()) секрет не создаётся, и метод возвращает пустую строку. Портал, который жил на значении по умолчанию, после обновления станет подписывать JWT новым случайным секретом, а сервер досок останется со старым, и подписи разойдутся.

До обновления проверьте, задан ли секрет явно хотя бы в одном из трёх мест. Главнее всех опция flipchart.jwt_secret: если она заполнена, значения из disk-boards.php и секции boards не используются. Если секрета нет нигде, пропишите на портале тот же секрет, что стоит на сервере досок. А раз 'secret_token' лежал в исходниках модуля, лучше сразу завести новый секрет на обеих сторонах. После обновления сверьте секрет, которым подписывает портал, с секретом сервера. Если отпечатки разошлись, меняйте опцию flipchart.jwt_secret: сгенерированный секрет лежит в ней, и правка disk-boards.php или .settings.php его не перекроет. Отпечаток снимается так:

        <?php declare(strict_types=1);

use Bitrix\Disk\Document\Flipchart\Configuration;
use Bitrix\Main\Loader;

Loader::requireModule('disk');

// если секрета нет ни в одном из трёх мест, вызов сам сгенерирует его и запишет в опцию
$secret = Configuration::getJwtSecret();

echo match (true) {
    $secret === '' => 'пустая строка, включён облачный прокси',
    $secret === 'secret_token' => 'старое значение по умолчанию, смените на портале и на сервере',
    default => 'отпечаток: ' . substr(hash('sha256', $secret), 0, 16),
};

    

На сервере досок посчитайте SHA-256 от его секрета и сравните первые 16 символов.

Убедитесь, что редактор досок откроется

Компонент disk.flipchart.editor теперь бросает SystemException и не рисуется в трёх случаях:

  • app_url не абсолютный http(s)-адрес (проверяет Configuration::isValidAppUrl());
  • заголовки уже отправлены, и FramePolicy::emit() не может выставить Content-Security-Policy: frame-ancestors 'self' и X-Frame-Options: SAMEORIGIN;
  • ServiceProfileResolver::resolveForEditor() не определил инстанс сервиса досок.

В последнем случае публичная ссылка, единая ссылка и Controller\Integration\Flipchart::viewDocumentAction() отдают страницу ошибки и пишут в лог через PilotLog.

Заголовки из FramePolicy запрещают встраивать страницу редактора на чужие сайты. Если вы показывали доску в iframe на другом домене, после обновления это перестанет работать. Если выводите компонент в своём коде, следите, чтобы до него заголовки ещё не ушли.

Адреса сервиса досок теперь зависят от инстанса. Configuration::getApiHost() и getAppUrl() получили необязательный параметр ServiceProfile $profile = ServiceProfile::Old. С ServiceProfile::New они читают отдельные опции и бросают DualMode\ConfigurationException, если адрес не задан или не проходит ServiceAddress::isValid(). Адреса обоих инстансов удобно проверять одним сервисом:

        <?php declare(strict_types=1);

namespace Vendor\Boards\Application\Service;

use Bitrix\Disk\Document\Flipchart\Configuration;
use Bitrix\Disk\Document\Flipchart\DualMode\ConfigurationException;
use Bitrix\Disk\Document\Flipchart\DualMode\ServiceProfile;
use Bitrix\Main\Error;
use Bitrix\Main\Result;

final class BoardAddressCheck
{
    public function check(ServiceProfile $profile = ServiceProfile::Old): Result
    {
        $result = new Result();

        try {
            $appUrl = Configuration::getAppUrl($profile);
            $apiHost = Configuration::getApiHost($profile);
        } catch (ConfigurationException $e) {
            return $result->addError(new Error($e->getMessage(), 'BOARD_ADDRESS_NOT_SET'));
        }

        if (!Configuration::isValidAppUrl($appUrl)) {
            $result->addError(new Error(
                "app_url не абсолютный http(s)-адрес: {$appUrl}",
                'BOARD_APP_URL_INVALID',
            ));
        }

        return $result->setData(['appUrl' => $appUrl, 'apiHost' => $apiHost]);
    }
}

    

Обновите свои копии SDK досок

SDK досок лежит в шаблоне disk.flipchart.editor, это исходник templates/.default/src/flip-board-sdk/src/lib/flip-board-sdk.js и собранный script.js. До 26.1150.0 он слал сообщения в iframe доски с адресатом '*'. Среди них был ответ на waitParams с параметрами доски, включая JWT (token) и boardData.fileUrl. Обработчик входящих событий, в том числе AI-запросов из доски, не проверял отправителя.

Теперь все postMessage адресованы origin из appUrl. isTrustedMessage() отбрасывает входящее сообщение, если event.source не iframe доски или event.origin не совпадает. Подписку на beforeunload убрали, а невалидный appUrl или схема не http(s) вызывают исключение уже в конструкторе.

Рядом с исходником в поставку попал SECURITY-CHECKLIST.md. Из него следует, что SDK — форк вендорного @flip-chart/flip-board-sdk 0.0.31 с защитой канала сообщений. После каждого обновления библиотеки чек-лист велит проверить grep'ом исходник и собранный script.js. Отправок на '*' быть не должно, isTrustedMessage должен быть на месте, подписки на beforeunload быть не должно. Потом чек-лист велит прогнать chef test unit, а после правки исходника пересобрать бандл через chef build.

Если вы копировали disk.flipchart.editor в свой шаблон сайта, обновление копию не тронет, и в ней остался старый SDK. Проверить её хватит одной командой:

        grep -rL "isTrustedMessage" --include=script.js --include=script.min.js \
  local/templates/*/components/bitrix/disk.flipchart.editor/ \
  bitrix/templates/*/components/bitrix/disk.flipchart.editor/

    

Файлы в выдаче собраны со старым SDK, такую копию пора пересобрать от нового .default.

Проверьте свой код поверх Диска

В конструктор Search\StorageFileFinderOptions (lib/search/storagefilefinderoptions.php) перед ?array $typeFileValues, который появился в 26.1100.0, вставили новый параметр array $additionalFilter = []. Вызов с восемью позиционными аргументами теперь отдаст список типов файлов в ORM-фильтр. null на восьмой позиции закончится TypeError, потому что новый параметр не nullable. Ядро само вызывает конструктор с именованными аргументами (lib/rest/service/file.php, lib/FilePicker/Provider.php), сделайте так же и передавайте типы как typeFileValues: [...]. Прочитать дополнительный фильтр можно новым getAdditionalFilter().

Internals\Model::setAttributes() (lib/internals/model.php) при пустом списке алиасов теперь доходит до setExtraAttributes() и заполняет extra-поля, а раньше выходил из метода до этого шага. Если ваша модель на базе Internals\Model рассчитывала, что после такого вызова extra-поля пустые, проверьте её.

При separated-сессиях пароль публичной ссылки спросят ещё раз

Это единственная правка кода в 26.1100.100. Internal\Service\ExternalLink\ExternalLinkPasswordService::getSessionId() берёт ID из Application::getInstance()->getKernelSession() вместо getSession(). От этого ID через sha256 строится ключ disk.external_link.password_access.<ID ссылки>.<hash>, под которым в PersistentStorageInterface 24 часа хранится подтверждение пароля публичной ссылки. Callback sessionIdResolver из конструктора, если он передан, по-прежнему главнее.

В режиме сессий default за kernel-сессией стоит KernelSessionProxy поверх той же сессии, getId() возвращает тот же ID, и для таких порталов ничего не меняется. В режиме separated kernel-сессия отдельная (KernelSession со своим ID), а общая сессия стартует лениво (enableLazyStart()). Там ключ теперь считается от другого ID, и подтверждения, сохранённые до обновления, не найдутся. Посетителю, который ввёл пароль меньше суток назад, придётся ввести его снова. Режим задаётся ключом mode в секции session. Ядро читает local/.settings.php, если он есть, иначе bitrix/.settings.php, а .settings_extra.php перекрывает эту секцию целиком.

Исправление касается и AJAX-контроллера disk.external.link/ajax.php (checkPasswordAction), который появился в 26.1100.0 (разбор) и вызывает validateAndConfirm().

Новое: FilePicker, второй инстанс досок, задачи из досок

Универсальный выбор файлов (FilePicker) состоит из контроллера Controller\FilePicker с экшенами getInitialStage, listChildren, search и resolveSelection (все POST и с CloseSession) и пространства Bitrix\Disk\FilePicker. Provider отдаёт источники, недавние файлы, дерево и поиск через StorageFileFinder, сортирует по белому списку из name, createTime и updateTime и возвращает страницу до 100 записей. SignedConfig и SignedConfigBuilder собирают подписанную конфигурацию выбора с режимом, лимитом, типами, сроком действия и привязкой к пользователю и сайту. К этому прилагаются компонент disk.file.picker (Controllerable, экшен getBootstrap) и JS-расширения disk.disk-picker и disk.disk-picker.internal на TypeScript. Опция disk_enable_universal_file_picker (в default_option.php она N) через \Bitrix\Disk\Configuration::isUniversalFilePickerEnabled() попадает только в настройки JS-расширения disk.disk-picker, экшены контроллера FilePicker от неё не зависят.

Второй инстанс сервиса досок живёт в lib/document/flipchart/dualmode/. ServiceProfile (Old и New) обозначает инстанс, ServiceProfileResolver выбирает его для объекта, папки назначения и редактора. Пилотом управляет PilotProjectService с методами prepare, activate, drop и emergencyRollback, адреса нового инстанса берутся из опций flipchart.new_service.api_host и flipchart.new_service.app_url, группы пилота из flipchart.new_service_group_ids. Консольной команды нет намеренно, в докблоке PilotProjectService сказано, что Symfony Console на коробке необязателен, поэтому процедуру запускают из /bitrix/admin/php_command_line.php. Опцию групп руками лучше не трогать. Так пропускается проверка, что хранилище группы пусто, а по тексту докблока последствия необратимы, потому что старый инстанс навсегда запоминает document_id. emergencyRollback() требует явного acceptDataLoss: true.

Задачи из досок включает опция flipchart.tasks_enabled (по умолчанию N, проверка через Configuration::isTasksEnabled()), фронтенд лежит в JS-расширении disk.board-tasks. Работают они только для досок на новом инстансе, это видно по флагу TASKS_ENABLED в disk.flipchart.editor/class.php.

Мелочи и находки

  • Грант на скачивание доски выдаётся, но пока нигде не проверяется. DocumentDownloadGrant подписан TimeSigner на 15 минут и привязан к сессии, объекту и версии, DocumentDownloadUrlService добавляет его в URL getDocument параметром grant. При этом Controller\Integration\Flipchart::getDocumentAction() по-прежнему ищет документ только по sessionId, а DocumentDownloadGrant::open() не вызывает ни один модуль коробки. По докблоку сервиса, три места сборки URL свели в одно, чтобы пропущенное место не осталось обходом проверки.
  • Экшен getBootstrap компонента disk.file.picker объявлен через 'prefilters', то есть с заменой стандартного набора фильтров. В нём Authentication и HttpMethod(POST), фильтра Csrf нет. Если берёте этот приём в свои Controllerable-компоненты, добавляйте Csrf сами.
  • include.php явно регистрирует автозагрузку bitrix\disk\controller\filepicker на lib/Controller/FilePicker.php, а в нашей тестовой коробке файл лежит в lib/controller/. Она развёрнута на регистронезависимой ФС, так что реальный регистр каталога в дистрибутиве по ней не определить. На Linux, если контроллер не найдётся, начните с этого пути.
  • Хотфикс собран позже основного релиза. VERSION_DATE у 26.1100.100 стоит 2026-08-26, у 26.1150.0 стоит 2026-08-07. После установки 26.1150.0 в ExternalLinkPasswordService остаётся getKernelSession().
  • Константа Storage::GROUP_STORAGE_CACHE_TAG = 'disk_group_storage'. Этот тег сбрасывается при создании и удалении хранилища группы (lib/storage.php), на него можно вешать свой тегированный кеш.
  • Ещё из мелких API: RecentlyUsedManager::getFileModelListWithRecentTimeByUser(), StorageFileFinder::loadModels(), Configuration::isValidAppUrl().
  • Схема БД не менялась. Добавились опции disk_enable_universal_file_picker, flipchart.tasks_enabled, flipchart.new_service_group_ids, flipchart.new_service.api_host и flipchart.new_service.app_url, а flipchart.jwt_secret теперь может записаться сама.

Что делать

Перед обновлением задайте на портале явный секрет JWT, тот же, что на сервере досок. После обновления прогоните проверку секрета и адресов из примеров выше, откройте доску в редакторе и по публичной ссылке. В своём коде поищите new StorageFileFinderOptions( с позиционными аргументами, в шаблонах сайта поищите скопированный disk.flipchart.editor.

Читайте дальше

disk 26.1100.0 Безопасность Свежее

Disk 26.1100.0: закрыты дыры в правах на публичные ссылки и версии, единые ссылки больше не выключаются

Disk 26.1100.0 вышел в коробку 2 сентября 2026 года (по официальному каналу «Битрикс24 changelog») и закрывает три дыры в правах. Любой, кто видел файл, мог поставить или снять пароль и срок действия его публичной ссылки, подпись файла `_uls` открывала всю историю его версий, а вложения к комментари...

4 мин
voximplant 26.700.0 Ломающее Свежее

Voximplant 26.700.0: оценку качества связи убрали, у notifyAdmins() появился тип

Модуль телефонии voximplant 26.700.0 вышел в коробочный Битрикс24 11 сентября 2026 года, по данным официального канала «Битрикс24 changelog». Из карточки звонка убрали оценку качества связи вместе с её JS-событиями, у `Im::notifyAdmins()` появился тип параметра, а публичные константы `SipStatusInfor...

3 мин
ui 26.687.0 Рутинное Свежее

UI 26.687.0: триал VibePlus в облаке и дизайн чипа TintedBitrixGpt

`Bitrix\UI\Controller\InfoHelper` при активации демо сначала спрашивает у модуля bitrix24, включён ли старт VibePlus, и если да, запускает триал VibePlus вместо обычного демо тарифа. Ветка срабатывает только при подключённом модуле bitrix24 и определённой константе `BX24_HOST_NAME`. В `ui.system.chi...

1 мин
ui 26.675.0 Ломающее Свежее

UI 26.675.0: ui.actionpanel переехал в бандл, а rich_text по-новому обходится с квадратными скобками

Модуль ui 26.675.0 собран 26 августа 2026. Из PHP поменялись `Converter` и `Whitelist` в `Bitrix\UI\Format\BBCode`, и пользовательские поля типа `rich_text` теперь иначе сохраняют и индексируют текст с квадратными скобками. На фронтенде старую панель групповых действий `ui.actionpanel` перевели на б...

4 мин
Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.
AI Домовой

AI Домовой История

на связи

пишет…
Нет истории чатов
AI Домовой

Нужна авторизация

Войдите, чтобы задавать вопросы AI Домовому.

Войти