Внедрение закладок в исходном коде публичных репозиториев. Как бороться?

0

На YouTube-канале «Global Digital Space» опубликована запись трансляции, посвященная теме борьбы с внедрением закладок в исходном коде публичных репозиториев.

В дискуссии приняли участие: Дмитрий Гадарь («Тинькофф Банк»), Рустэм Хайретдинов (BI.ZONE), а от компании «Эшелон» — заместитель генерального директора Виталий Вареница. Модератором встречи выступил известный блогер по проблемам информационной безопасности Алексей Лукацкий.

Ниже приведена расшифровка самых горячих вопросов состоявшейся дискуссии.

В чем разница между закладкой, уязвимостью и недекларированной возможностью (НДВ)?

Виталий Вареница: Да, эти понятия разделяют, но каждое из них является подмножеством одной и той же сущности. Если базовое множество – это все-таки уязвимость, то программная закладка и незадекларированная возможность – это частный случай. Это те же дефекты, которые умышленно внесены разработчиком. Конечно, все зависит от того, к чему это может привести. Если это математическая ошибка, которая глобально не повлияет на доступность конфиденциальной информации при работе в этой системе, то это «косяк». Если же разработчик скопировал откуда-то кусок кода, не разобравшись, что фрагмент кода отвечает за какие-то механизмы разграничения доступа, то это уже является недекларированной возможностью.

Рустэм Хайретдинов: Когда говорят про закладки, имеют в виду некоторые намерения. Но тому, кто будет эксплуатировать код, все равно, было намерение или нет. Любая некорректность кода должна быть найдена и исправлена.

Дмитрий Гадарь: Все имеют 3 разных механизма поиска и выявления. Есть различные подходы к управлению уязвимостями, закладками и недекларированными возможностями. Но по сути это, наверное, одно и то же, и без разницы, было это умышленно сделано или неумышленно.

Где граница между доверием разработчикам и паранойей поиска закладок?

Дмитрий Гадарь: Вопрос доверия в информационной безопасности, на мой взгляд, не должен стоять. Либо это контролируется, либо это рискованно. Конечно, уязвимости, закладки и недекларированные возможности выявляются по-разному. И делают это разные команды. Есть и разработчики, которые обучаются правилам безопасной разработки. Есть инструменты, интегрированные в процесс continuous integration, continuous delivery. И этими инструментами пользуются как разработчики, так и application security. Есть core-команда application security, которая разрабатывает инструменты и дает возможность тем же разработчикам и командам пользоваться результатами их разработки. Для критических элементов инфраструктуры есть отдельные application security – инженеры, которые погружены непосредственно в бизнес-линию и занимаются вопросами архитектуры.

Рустэм Хайретдинов: Вопрос, надо ли заниматься профайлингом? Ну, в принципе, я думаю, что надо. Доверие – это сегодня непозволительная роскошь. Я знаю компании, которые просто раз в месяц людей прогоняют через полиграф, мониторят их действия в соцсетях, для этого все инструменты есть. А насколько эти инструменты подходят для митигаций от конкретных рисков, решают люди, которые за это отвечают. Кто-то любит решать дела полицейскими мерами, кто-то любит технические меры – слежение, запись камеры и так далее.

Может ли профайлинг и слежка негативно повлиять на лояльность разработчика?

Рустэм Хайретдинов: Есть разные люди. Кого-то это грузит, кому-то на это наплевать, скрывать нечего. И мы, конечно, решаем, что нам важнее: лояльность или… Ну, если это выражается в том, что человек уволится, это одно. А если начнет саботировать – это другое. Не думаю, что нужно сейчас погружаться в психологию конкретных людей. Программисты – люди специфические, у каждого какие-то тараканы, как и у каждого из нас, поэтому обобщать достаточно тяжело. Техническая и кадровая работа должны сочетаться.

Виталий Вареница: Понятно, что умысел – вещь сложная, ее без общения с разработчиком в теории тяжело идентифицировать, но есть косвенные технические параметры. Например, если объектом проверки является какая-то прошивка какой-то железки, например, коммутатора. Внешние аудиторы, которые проводят security code review с помощью SAST или ручного анализа, например, обнаруживают в коде учетную запись с root-правами, но при этом с очень хитро замаскированным паролем, динамическим, который генерируется в зависимости от входных параметров. Например, число, месяц, час. Дальше считается какая-то хэш-функция от этого значения и полученное значение вводится в командную строку, например. Первый вопрос у любого технического специалиста: зачем это здесь?

Можно ли отслеживать наличие закладок в публичных репозиториях?

Виталий Вареница: Когда мы говорим про поиск уязвимостей, только SAST и только DAST – это недостаточные средства. SAST плюс DAST плюс code review, тогда это работает. И тот специалист, который выявляет подобные куски кода, он дальше должен задаться вопросом: почему? Если это open source, то мы понимаем, что не всегда реальные авторы этого кода идут на контакт. Здесь возникает не столько технические, сколько организационные проблемы. Технологически некоторые из закладок можно действительно выявить, но далеко не все. И основная сложность здесь в том, что во многих случаях нет обратной связи.

Рустэм Хайретдинов: Скажем так, известные закладки, если мы назовем их закладками, найти можно. А если это что-то изысканное, то никак.

Дмитрий Гадарь: По поводу закладок, особенно в open source, это тема всегда непростая, это комплекс мер. Мне нравится фреймворк SLSA, который предполагает набор требований, которые могут если не исключить, то значительно снизить риск компрометации зависимостей, которые загружаются. И этот фреймворк гораздо лучше. SAST и DAST, ручной анализ – это здорово, если это не десятки, сотни и тысячи зависимостей, которые скачиваются ежедневно организацией. На таком потоке проверить невозможно. Поэтому должны быть средства автоматизации и технического контроля. SLSA предлагает очень крутые проверки, и там тред-модели перечисляют, от каких известных в мире атак это бы спасло. Это история изменений, ревьюер и апвьюер, то есть кто это делал, когда, поддержка, история изменений зависимостей и контроль этой истории. Вообще идеальным вариантом является форк какой-то стабильной версии и продолжение разработки самостоятельно.

Вчера читал, что есть скрытые символы Unicode, которые позволяют сделать закладку или класс определить, которого не только не видно в коде. Это просто пустой, скрытый символ Unicode, который является дополнительным параметром какой-либо функции, и это довольно сложно искать. И там триггеров исполнения закладок может быть миллиард. Они могут триггериться на какую-нибудь дополнительную версию зависимости, которая находится в вашем коде. Или они могут триггериться на то, что они находятся в тестовой среде. Или то, что они находятся в рантайме и ожидают определенного состояния приложения, например, интернета и пришедшего определенного количества пользователей. Вы можете никогда не выявить какой-то кусочек кода, который будет юникодом скрыт, доставлен и ждать какого-то пакета. Это как раньше, были классные трояны, которые, как на пианино, простукивали порты, и после этого троянская программа активировалась, делала резкий дроп на небольшое количество пакетов и закрывалась обратно. Такие закладки выявлять сложно. Пока те закладки, которые мы видели, не представляют чего-то сложного. Но я верю в то, что это будет развиваться, и нужен комплексный подход. Есть класс решений типа RASP, который погружен в контекст приложения, и с его помощью надо обязательно защищаться, в том числе, от закладок, видеть, что приложение не начало вести себя как-то по-новому.

Есть информация, что на 2020 год 17% уязвимостей в проектах на GitHub были добавлены намеренно. Как вы оцениваете долю закладок в общем числе уязвимостей opensource кода?

Виталий Вареница: Еще условно в 2012 году, я общался с коллегами по ИБ, многие более старшие коллеги ухмылялись, когда я говорил слово «уязвимость». Да ладно, какие там уязвимости! Сейчас же уязвимости, атаки, закладки настолько вошли в нашу жизнь, никто даже не ставит вопрос об актуальности. 17% — это много. Тут есть еще момент, сколько мы еще не нашли. И то, что Дима говорил, там форк и так далее, на самом деле, эта технология используется очень давно. Если мы возьмем строго категорированные вещи, всякие КИИ, то там это строго обязательные требования. Ни одни наш регулятор нам не запрещает как разработчикам взять open source. Никто не говорит, что это нельзя. Пожалуйста! Но как только ты этот open source к себе в проект добавил, это твоя ответственность. Ты отвечаешь за обновления, за поиск уязвимостей нулевого дня.

Насколько стоит опасаться, что закладка прилетит с обновлениями от именитых вендоров?

Виталий Вареница: Любое обновление подразумевает, что, если у нас была определенная степень доверия к инфраструктуре, то все новое, чтобы добавляем, неважно, где мы это взяли, говорит о том, что это потенциальная угроза. И рассматривать надо с точки зрения тех рисков, которые это обновление может конкретной организации принести. Если мы говорим о критически важной инфраструктуре, то там все понятно, регулятор все написал уже, что нужно дополнительные меры. И там всегда контроль любых дополнений подразумевает проверку этих обновлений. Если это какие-то бизнес-решения, там есть базовые правила, security policy внутри компании. Тут нет серебряной пули, мол, делайте все так.

Есть ли риск, что зарубежные вендоры, ушедшие с нашего рынка, потенциально могут встраивать какие-то программные закладки в обновления? Да, конечно, есть. Такие случаи известны, причем на фоне некоторых зарубежных европейских компаний, с которыми мы работали. Причем они начались не в феврале этого года, это было в течение несколько лет ближайших. У нас были реальные кейсы, когда мы находили те вещи, которые в самом R&D ребята даже не знали. У них там было 2 или 3 человека, которые сидели в разных частях мира, которые сказали: «О, да! Мы подтверждаем».

У нас есть еще такая тема, как требования доверия новые. Они так называются, мне нравится, — требования доверия. Насколько мы, оператор или пользователь, можем доверять продукту. Есть определенные технические рекомендации, которые говорят, что при выполнении таких-то кейсов можно доверять на столько-то. Так что готового универсального решения и не может быть. Каждая организация, каждый сегмент рынка должны оценивать риски с учетом тех активов, тех процессов, продуктов, которые у них реализованы.

Буквально месяц или два назад представители регуляторов на прямой вопрос сказали, что они с 24 февраля ни разу не столкнулись с ситуацией, чтобы в обновлении прилетело что-то, что могло нарушить работу софта, операционок, железа и т.д. Насколько ваша организация закладывается на это при получении обновлений от Microsoft, Oracle, Cisco и так далее?

Дмитрий Гадарь: На самом деле, все обновления проверяются. Нет такого, что мы прямо сразу накатываем все. Такой риск и такую угрозу я рассматриваю как актуальную. Вероятность того, что там непредумышленно будет что-то заложено, сильно ниже у вендора, чем у open source. Обычно в open source один человек пилит библиотеку, без каких-либо ключей, просто с логином и паролем и выкладывает на GitHub. И таких случаев на моей памяти порядка 17 за последнее время, которые мы блокировали. Это не значит, что они были загружены, это значит, что мы блокировали на периметре, чтобы они не дай бог не были загружены. Причины разные, мы не выясняли. Это либо взломан разработчик, либо разработчик имеет определенные политические взгляды.

В России у нас есть уровни доверия ФСТЭК, ОУД Центробанка, ГОСТ 15408. Насколько они помогают выявлять закладки, а не ошибки или паттерны небезопасного программирования?

Виталий Вареница: Любая методика работает только тогда, когда включается здравый смысл. Мы берем типовую методику и делаем из нее адаптированную под конкретный релиз. За прошлый год такая интересная статистика, что порядка 70% вендоров, которые начали у себя внедрять меры по безопасной разработке с использованием адаптированных методик, с помощью своих обученных команд стали выявлять уязвимости в своих продуктах, причем рост почти в геометрической прогрессии. Сами разработчики сильно удивлялись. Во всех современных методиках нет ничего нового, специалисты по ИБ и так все это знают. Что такое методики? Это просто сводки того, что необходимо выполнять. Но когда вендор начинает пошагово все действительно выполнять, то находит множество проблем, о которых догадывался, но не мог прощупать сам. Опять же, все наши регуляторы в положениях своих, если брать сертификацию, например, так и говорят, что есть типовые требования, но каждая методика под каждый проект отдельно согласовывается, она уникальна.

Адаптация методик требует определенной квалификации от людей. Можно ли этому научиться самостоятельно? Если да, то где, если мы говорим о России? Или это только удел очень небольшого количества компаний, которые могут схантить лучших обсекеров?

Виталий Вареница: По поводу схантить лучших обсекеров. Это сложная задача, поскольку лучшие обсекеры, как и лучшие разработчики, не всегда замотивированы только финансовой стороной вопроса. У них может на первом месте стоять интересность задач. У нас сложился подход следующий. Фактически руководители IT-направлений департаментов, которые у нас есть, — это наши топовые обсекеры, которых мы очень стараемся беречь и держать, они команды под себя обучают. У нас есть практика работы с нашими крупными техническими вузами с 3,4,5 курса, привлекаем студентов под задачи, пока они учатся, а когда заканчивают вуз, то через пару лет становятся довольно сильными специалистами. Которые потом уже тоже хантятся более крупными компаниями, где другие задачи. Понятно, что для крупной компании захантить готового специалиста вполне нормальный кейс. А для средних или мелких, не всегда возможно. Поэтому для них вариант – нанимать аутсорсинговую компанию, которая будет это делать.

Дмитрий Гадарь: Мы говорим про обсеков. И я часто вижу ребят больше заточенных на анализ защищенности, на проведение пентеста, и начинает перенасыщаться рынок пентестерами. Как сломать – еще не означает, как защитить. Это просто одна функция, которой, грубо говоря, можно пренебречь по отношению к безопасной архитектуре кода, обучению.

У нас есть требования по анализу кода для финансовых организаций и для субъектов КИИ, если это значимый объект. Допустим, значимых – 60 000 организаций. Насколько российский рынок готов обслужить все эти организации с точки зрения анализа кода?

Виталий Вареница: Не все из этих 60 000 начали решать эту проблему. Всегда, когда появляются новые требования, фронтом выступает ЦФО, Москва, Питер, а это условно до 1000 компаний. Сколько вообще сейчас на рынке компаний оказывать услуги по данному направлению? Думаю, около 15 серьезных игроков. Я бы не сказал, что у нас мегасупердефицит. Если стоит задача у вендора это сделать, то найти можно сейчас.

Дмитрий Гадарь: Мы так же, как и Виталий, проводим школы по безопасности. У нас школа разработчиков есть, очень много ребят приходит из различных вузов и не только – кто хочет развиваться. И оттуда мы набираем ребят, которые показывают отличные результаты. За 2 года люди становятся лидами каких-то направлений.

Если посмотреть на тех, кто занимается, например, мониторингом ИБ в SOC-ах, у них есть такая конструкция, как atomic red team, набор таких тестов, которые запускаются против IPC-ов, idear-ов, тем самым выявляем эффективность наших средств мониторинга. По идее на одних и тех же тестах и одном и том же билде должны быть одни и те же выходные результаты, тогда мы можем предположить, что у меня код работает предсказуемо. Если он начинает генерить разные результаты, возможно, здесь какая-то аномалия. Есть такое или это фантазия?

Виталий Вареница: Очень хороший вопрос, это не фантазия. Если мы возьмем крайние требования по статическим анализаторам, то мы там увидим то, о чем идет речь. Еще несколько лет назад буквально, когда речь заходила о SAST, многие и разработчики SAST, ребята, которые с этими продуктами работали, на самом деле, подразумевали сигнатурный анализ. Мы сегодня говорили, что база, зависит от базы. Современный SAST, если мы говорим про современные требования статического анализа, в нем есть много чего еще. Там есть и сигнатура, и эвристика, и контекстно чувствительный анализ, поблоковое выполнение элементарных функциональных элементов. Мы, в том числе, являемся разработчиком SAST, к примеру. У меня команда разработки, которая пишет SAST+DAST, набор фазеров под разные задачи, поэтому вот это все реализовано. Как показывает практика, с помощью автоматизированного средства мы, в том числе и в open source, находим интересные вещи – парольные вещи можно найти, мы сегодня о них говорили, но там тоже есть особенности, где уже сигнатурка чисто не отработает. Там должен быть модуль эвристический, который нормально настроен на этот поиск.

Как разработчики SAST мы сталкиваемся вот с чем. Что хочет заказчик? Коробку с одной красивой кнопкой, и чтобы дальше все сам сделал. Когда мы говорим про сложные методы статического анализа, понятно, что это продукт тоже специфический, что у оператора, который будет работать с этим продуктом, тоже есть понимание, квалификация. Даже не просто что они знают какие-то там языки программирования и умеют читать код, этого уже недостаточно, на самом деле. Они уже имеют определенную базу понимания того, как это работает. Можно ли таких специалистов выучить? Да, можно. У нас, например, есть учебный центр, в котором есть разные курсы. Есть общие типа этичного хакинга, но есть и специализированные. Например, для разработчиков двухнедельный курс по внедрению мер по РБПО. Процессная часть, практическая часть и организационная. В практической части, мы показываем, например, если есть требования по фаззинг-тестированию, как можно фаззинг проводить внутри ренди? На каких-то open-source проектах используем различные инструменты, не только нами разработанные. Это ценно, когда это не голая теория, а когда есть синхронизация требования с тем, как это можно реализовать. Такие курсы интересны.

Насколько лучше сертифицированные обсканы, чем тот же RSON QP или анализаторы кода, которые выпускает Facebook? Что лучше: сертифицированное решение или open source?

Виталий Вареница: У нас много задач, в том числе проверки кода других вендоров. Есть средства, которые разрабатывает наша организация. При этом в 80% проектов мы не пользуемся только своими продуктами. Мы используем open source, доработанные нами или разработчиком. По этому поводу регулятор в некоторых редакциях своих документов пытался написать, что неплохо было бы, чтобы разработчики или организации, которые проводят независимую оценку соответствия или сертификацию тоже пользовались более чем одним средством. Но дальше стоят финансы, понятно, мы в реальном мире живем. Поэтому open source – почему нет, если мы ему доверяем?

Чтобы ответить на ваш вопрос, нужно входные параметры уточнить. Если мы говорим, что сертифицированы по новым требованиям, это значит само по себе средство автоматизации (SAST, DAST) уже доверенное. Правильная конфигурация, когда мы говорим про сертифицированные, сейчас какая? Это определенный уровень доверия к самому продукту плюс проверка того, что в нем реализованы те требования и рекомендации, которые прописаны в ГОСТе по статанализаторам, к примеру. То есть это не просто сигнатурный анализатор какой-то, который поддерживает 50 языков, а это действительно средства статического анализа, в котором реализованы все эти механизмы. То же самое можно сказать про фаззинг. У нас есть отдельные требования. Там есть требования по входным параметрам, по выходным параметрам, по условиям завершения фаззинг-тестирования, например. Если мы говорим «сертифицированный анализатор», то надо понимать, что он соответствует ГОСТу и имеет определенный уровень доверия. Тогда окей. По поводу насколько он лучше или хуже? Это исключительно вкусовщина. Кому-то интерфейс нравится где-то большое, кому-то нравится, что можно работать с командной строкой. Эти вещи не имеют отношения к качеству статистического анализа, но влияют на принятие решения, что лучше, а что хуже. Мы каждый год проводим статистику по наиболее часто используемым платформам языкам программирования, по нашим проектам, в основном, мы не смотрим международные, и забавно, что из 100% проектов за год 99% проектов написаны на 5-6 различных языках. Отсюда вывод, тот же статанализатор по-хорошему должен поддерживать эти зависимости. На российском сегменте это языки C++, Go, Java, PHP, Python. Встречается C-sharp.

Дмитрий Гадарь: Выбирая между сертифицированным о опенсорсным решением, я бы выбрал то, которое строит синтаксическое дерево, потому что, кажется, параметры внутри самого решения важнее, и сертифицированная может быть хуже, чем опенсорсный статистический сканер, который построит дерево и выявит все входы в приложение и параметры манипуляции приложением.

Отправляете ли вы в upstream правки по безопасности в opensource компонентах, которые вы находите, и принимает ли сообщество такие правки?

Дмитрий Гадарь: Конкретно по средствам защиты по тем библиотекам, которые мы допиливаем для себя, такой потребности нет. Если б была небольшая правка, уязвимость, то да. А кусок форка, не то, что мы его скрываем, а он просто будет неинтересен сообществу, поскольку применим конкретно в том, где нам нужно.

Виталий Вареница: У нас модель другая. Поскольку у нас много проверок кода конкретных вендоров, то не секрет, что многие российские вендоры используют open source, для нас как внешнего аудитора неинтересно, откуда они его взяли. Статистика такая, что в каждом первом проекте мы находим уязвимости, и не то, что мы делимся, мы обязаны делиться. Мы обязательно должны вендору это отдать, чтобы он это исправил. Другой момент, у нас есть известная всем БДУ, это больше касается тех продуктов, которые сертификацию проходят, там и разработчик, и лаборатория по-хорошему должны добавлять информацию об этих уязвимостях в БДУ ФСТЭК. Я с Дмитрием полностью согласен, что шарить исправленный open source и подписывать информацию об исправленных уязвимостях – это даже маркетинговое преимущество. Это говорит о том, что разработчик действительно занимается безопасной разработкой, а не пилит что-то на коленке и никому не показывает.

Как все-таки действовать в процессе CI/CD при выявлении закладок и вредоносов в опенсорсе?

Дмитрий Гадарь: Я не видел закладок в каких-то критических библиотеках. Log4j, например, не влияет на функциональность, библиотека. Можно просто заблокировать и ничего страшного там не случится. Если влияет на функциональность, то даунгрейдить, либо пересобирать либу, выдирая из нее только тот функционал, который будет использоваться и переиспользовать в билде новую либу, которая будет локализована.

Виталий Вареница: Мы сталкивались реально с проблемами open source, где, например, videl какой-нибудь как видеодвижок для какой-то там программулины, которая с графикой работает, и это ее основная функциональная задача. И уязвимость приводила к тому, что иногда даунгрейд не помогал. Это особенность была конкретно реализации. И там единственный кейс, который мог эту проблему закрыть, — это переход на другую библиотеку. Либо сами разработчики должны быть это выпиливать. Глобально я согласен, это какие-то зависимости, которые в целом на бизнес-логику работы не влияют, можно заблочить, можно продаунгрейдить, и проблема решится.

Сканеры «Эшелона» могут отдавать данные в SIEM, SOC как триггер на сработку?

Виталий Вареница: Да, конечно, с учетом, что у нас SIEM дорабатывается, то это все синхронизировано. У нас есть сканеры, статические анализаторы, динамические, они все вполне объединяются в SOC и интегрируются под разные задачи. У нас есть определенное количество проектов, где мы вендорам тоже рекомендуем так делать. Это лучший подход, когда все работает в комплексе.

Кто отвечает за вопрос безопасной разработки – разработчики или внешняя часть в безопасности?

Дмитрий Гадарь: Вопрос безопасности должен быть возложен на каждого, кто принимает участие в разработке. В том числе на quality assurance, разрабов, core-команды безопасности. Это вопрос роста культуры безопасной разработки. Чем больше людей сюда вовлечено, тем меньше будет проблем.

Виталий Вареница: Контролер однозначно внешний, независимый. Есть вообще хорошая практика, когда контролер отвечает только перед топ-менеджментом. То есть у него нет никаких смежных зависимостей. А по поводу того, кто в этом участвует, то разработчики, тестировщики, QA, архитекторы, которые глобально эту архитектуру всю отстраивают.

Надо к определенному сроку выпустить релиз, при этом обнаруживается, что там есть какие-то проблемы, и мы явно не успеваем к моменту выпуска релиза. Как из практики разруливать эти конфликты?

Дмитрий Гадарь: С этим не нужно бороться, этим нужно управлять. В этом и состоит смысл application security. У нас есть градации уязвимостей, понятные и разработчикам, она сделана на основе CVSS, она прозрачна разработчикам, бизнесу и всем подряд, где перечислены сроки устранения, опасности, exception policy, как могут применяться компенсационные меры. То есть это заранее подготовленный макет, как работать с разными уязвимостями, в зависимости от того, где они находятся.

Виталий Вареница: Есть такой документ в рамках наших стандартов, которые в России действуют, это, допустим, руководство безопасной разработки. Если мы CVSS используем, critical, high, low, то там прописывается, что если high или critical, то это проблема, сроки не сроки, это то, что не может быть выпущено в релиз, потому что тут идут серьезные риски. Если там написано, что low, то в следующем релизе или в патче закроем, это тоже нормальная история. Так в реальной жизни это и работает. По поводу сроков, я называю экстремальной разработкой, когда сроки одни, договоренности другие, безопасность не взаимодействует, а пытается навязать свои требования. Это плохой кейс безопасности. Когда безопасность вместе с разработкой, тестировщиками, она рассматривает этот кейс так, что мы в одной лодке, и мы решаем в принципе одинаковые задачи, то разработчики понимают, что они не просто контролируют, они в том числе отвечают за безопасность и качество продукта, и это нормальным языком до них донесено. Психологический момент если не на первом, то на втором месте точно.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *