Установка через curl | bash: как оценить риск и что смотреть
Почти на каждой странице «Quick start» современного инструмента есть строчка вида curl https://example.com/install.sh | bash. Она удобна — одна команда, и всё стоит. Но если вдуматься, что именно происходит: вы скачиваете произвольный код с чужого сервера и тут же выполняете его от имени своего пользователя, не глядя. В конце августа 2026 года этот паттерн никуда не делся и вряд ли исчезнет — вопрос не в том, «плохой» он или «хороший», а в том, когда его можно запускать спокойно, а когда стоит потратить пять минут на проверку.
Содержание
Почему curl | bash так распространён
Причина простая: это самый дешёвый способ дать пользователю одну команду, которая работает одинаково на Ubuntu, Debian, macOS и в WSL, не дожидаясь, пока пакет появится в репозитории дистрибутива. Через такой паттерн ставят себя менеджеры версий (rustup, nvm), пакетные менеджеры (Homebrew), рантаймы (Deno), удобные установщики CLI-инструментов и облачных SDK. Скрипт сам определяет ОС и архитектуру, скачивает нужный бинарник или настраивает окружение — то, что через apt install или .deb-пакет потребовало бы отдельной сборки под каждый дистрибутив.
Это не делает паттерн безопасным по умолчанию — просто объясняет, почему им пользуются даже крупные и уважаемые проекты, а не только сомнительные тулзы с форумов. Дальше важно не «доверять или нет одной команде», а понимать, что конкретно она может сделать и как это проверить до запуска.
Что технически происходит и где риск
Когда вы пишете curl URL | bash, происходит следующее: curl начинает стримить содержимое ответа сервера напрямую в stdin процесса bash, а bash исполняет команды по мере их поступления — построчно, без какой-либо паузы на просмотр. Три конкретных риска здесь:
- Права исполнения. Скрипт выполняется с правами вашего текущего пользователя. Если команда написана с
sudo curl ... | sudo bash— с правами root, то есть без ограничений вообще: чтение любых файлов, запись в/etc,~/.ssh/authorized_keys, системные cron-задания, правки firewall. - Контент не гарантированно тот же, что вы видели. Сервер отдаёт ответ динамически и может формировать разный контент в зависимости от User-Agent, IP, географии, времени суток или количества обращений с одного адреса.
curlпо умолчанию шлёт свой User-Agent (curl/8.x), отличный от браузерного — теоретически сервер может отдать браузеру безобидную страницу с текстом скрипта, а по прямому запросуcurl— другой файл. Это не значит, что так делает каждый сайт, но сама возможность существует, и полагаться на «я открыл ссылку в браузере и всё ок» — ошибка. - Разрыв между просмотром и запуском (TOCTOU). Time-of-check to time-of-use: даже если вы открыли
install.shв браузере, прочитали его и он оказался чистым, а через минуту выполнилиcurl URL | bash— между этими двумя моментами содержимое по URL могло измениться. Ни HTTP, ни сам паттернcurl | bashне дают гарантии, что второй запрос вернёт то же самое, что первый, если только на сервере не настроена неизменяемость конкретной версии файла (например, версионированный URL или immutable release-ассет).
Отдельно: если сеть оборвётся на середине передачи, bash может успеть выполнить часть команд из недокачанного скрипта и упасть в неопределённом состоянии — это скорее операционная проблема, чем угроза безопасности, но тоже повод не гонять такие команды в проде без внимания.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверШаг 1 — разделяйте скачивание и запуск
Самое простое и самое эффективное правило: никогда не пайпите curl напрямую в bash. Разбейте на два шага:
curl -fsSL https://example.com/install.sh -o install.sh
less install.sh
Флаги -fsSL заставляют curl завершиться с ошибкой при HTTP-статусе 4xx/5xx (-f), не печатать прогресс-бар (-s), но показывать ошибки (-S) и следовать редиректам (-L) — без этого набора часто скачивается страница с текстом ошибки вместо самого скрипта, и она молча "выполняется" как валидный shell-код.
Дальше — реально прочитайте файл, а не просто откройте и закройте. На что смотреть в первую очередь:
grep -nE 'curl|wget|base64|eval|rm -rf|chmod 777|authorized_keys|/etc/(passwd|shadow|sudoers)' install.sh
Тревожные признаки:
- Обфускация: длинные base64-блоки, которые потом декодируются и передаются в
evalилиsh -c— если скрипт прячет часть логики, у вас нет способа понять, что он делает, не декодировав это вручную. - Вложенные загрузки:
curl ... | bashвнутри самого скрипта, ведущий на другой, менее заметный домен — вы проверили верхний уровень, но не второй. - Запись в SSH-конфиг — добавление ключей в
authorized_keys, правкаsshd_config. Легитимному установщику приложения это не нужно. - Правки firewall или отключение защит —
ufw disable,setenforce 0, массовые правилаiptables -A INPUT -j ACCEPT. rm -rfс широкими путями и подстановкой переменных без кавычек — классический источник разрушительных багов, даже без злого умысла.
Если после чтения вопросов не осталось — запускайте локально сохранённую копию (bash install.sh), а не заново скачанный поток. Так вы гарантированно выполняете именно то, что прочитали.
Шаг 2 — проверяйте источник и целостность
Чтение кода снимает часть риска, но не весь — читаемый и «чистый на вид» скрипт всё равно может быть заменён на сервере через час. Здесь помогает репутация источника и криптографическая проверка:
- Домен. Официальный домен проекта — не сокращённая ссылка (
bit.ly/...), не паста на стороннем хостинге, не зеркало. Ссылка из официальной документации на собственном домене проекта — совсем другой уровень доверия, чем та же команда, скопированная из комментария на форуме или из поста в соцсети. - Чек-суммы и подписи. У зрелых проектов рядом со скриптом часто лежит файл с хешем или GPG-подписью:
curl -fsSL https://example.com/install.sh -o install.sh
curl -fsSL https://example.com/install.sh.sha256 -o install.sh.sha256
sha256sum -c install.sh.sha256
Если издатель подписывает релизы GPG-ключом, проверка выглядит так:
curl -fsSL https://example.com/install.sh.asc -o install.sh.asc
gpg --verify install.sh.asc install.sh
Это не защищает от компрометации самого сервера сборки, но снимает риск подмены на пути «сервер → вы» и подтверждает, что файл не тронули после подписания.
- Альтернативный способ установки. Если у проекта есть официальный APT/YUM-репозиторий, подписанный Docker-образ на Docker Hub/GHCR или бинарный релиз на GitHub с чек-суммами в releases — обычно у этого пути более выстроенная цепочка доверия (подпись пакета, воспроизводимость сборки, история версий), чем у динамически генерируемого shell-скрипта. Если выбор есть — он предпочтительнее.
- История и репутация репозитория. На GitHub — возраст репозитория, число контрибьюторов, открытые issues про сам install-скрипт, активность мейнтейнеров. Разовый скрипт от аккаунта без истории — повод насторожиться сильнее, чем инструмент с многолетней публичной историей.
Шаг 3 — запуск в изоляции для непроверенных источников
Если источник новый, малоизвестный, или вы просто не хотите тратить время на полный аудит скрипта — не выполняйте его на рабочей машине или проде. Варианты изоляции по нарастанию строгости:
Одноразовый Docker-контейнер — самый быстрый вариант на своей машине:
docker run --rm -it --network bridge ubuntu:24.04 bash
# внутри контейнера
apt update && apt install -y curl
curl -fsSL https://example.com/install.sh -o install.sh
cat install.sh
bash install.sh
Контейнер изолирует файловую систему хоста, но не сеть по умолчанию — если хотите ещё и ограничить исходящие соединения, добавьте --network none и разрешайте доступ точечно, либо мониторьте трафик отдельно. Подробнее о том, как выстраивать такую изоляцию сервисов системно, — в статье про изоляцию через Docker для безопасности и в разборе лучших практик безопасности Docker.
Одноразовый VPS — вариант понадёжнее контейнера, если скрипт трогает системные настройки, ядро или сетевой стек так, что это не полностью видно изнутри контейнера. Поднимаете дешёвый сервер именно под тест, прогоняете install-скрипт, смотрите на результат и логи, при подозрении — уничтожаете инстанс и всё. Дешевле и быстрее, чем разбираться, что именно поломал непроверенный скрипт на боевой машине.
Непривилегированный пользователь без sudo — если контейнер или отдельная машина недоступны, хотя бы запустите скрипт от пользователя без прав на sudo и посмотрите на его поведение: пытается ли он сам себе эскалировать права, просит ли пароль там, где не должен.
Сетевой мониторинг во время установки — параллельно откройте ss -tnp или iftop, чтобы увидеть, к каким адресам скрипт обращается. Легитимный установщик обычно ходит на 1-2 известных домена (сам проект, GitHub releases, CDN пакетов); россыпь незнакомых IP — повод остановиться.
Когда паттерн приемлем, а когда стоит насторожиться
| Признак | Приемлемо | Стоит насторожиться |
|---|---|---|
| Источник ссылки | Официальная документация проекта на его домене | Ссылка из письма, DM в мессенджере, комментария на форуме |
| Домен | Основной домен проекта, HTTPS с валидным сертификатом | Сокращённая ссылка, паст-сервис, домен не связан с проектом |
| Возраст и репутация проекта | Годы публичной истории, крупное сообщество, открытый код | Свежий репозиторий без истории, аноним-мейнтейнер |
| Содержимое скрипта | Читаемо, без обфускации, делает то, что заявлено | base64-блоки, eval, скрытые вложенные загрузки |
| Права | Просит sudo с понятным обоснованием (например, установка системного бинарника в /usr/local/bin) | Требует root без объяснений, трогает SSH и firewall |
| Проверяемость | Есть чек-сумма или GPG-подпись, есть альтернативный способ установки (пакет, релиз) | Только скрипт, ничего для сверки |
| Контекст запроса | Вы сами искали инструмент и пришли на его сайт | Кто-то прислал команду с призывом срочно её выполнить «для исправления проблемы» |
Итоговое правило простое: чем известнее и прозрачнее проект — тем меньше формальностей нужно соблюдать при разовой установке на личной машине. Но на продакшен-сервере, где от одной ошибки зависит рабочий сервис, стоит применять шаги выше независимо от репутации источника — тестировать install-скрипт на отдельном сервере или в контейнере, а не сразу на боевом окружении, разумно даже для хорошо известных инструментов. Если готовите сервер с нуля и хотите заодно закрыть базовые дыры помимо этого конкретного риска — весь набор шагов собран в чек-листе безопасности нового сервера.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Достаточно ли открыть ссылку в браузере, чтобы проверить скрипт перед запуском?
Нет. curl по умолчанию отправляет другой User-Agent, чем браузер, и сервер технически может отдавать разный контент в зависимости от этого заголовка, IP или времени запроса. Просмотр в браузере снижает риск, но не заменяет проверку файла, реально скачанного тем же инструментом, которым вы будете его запускать.
Что если я скачал и проверил скрипт, но запускаю его через час — риск остаётся?
Да, в теории контент по URL мог смениться за это время (TOCTOU). Практическое решение — использовать локально сохранённую копию файла для запуска (bash install.sh, а не повторный curl | bash), тогда вы точно выполняете то, что читали.
Безопасно ли запускать curl | bash с sudo, если проект известный?
Разумнее и с известным проектом сначала скачать и просмотреть скрипт, а уже потом запускать с повышенными правами — привычка разделять шаги ничего не стоит, а при разовой компрометации сборочного сервера проекта (что случалось и с крупными именами) спасает именно она.
Как быть, если у проекта нет ни чек-суммы, ни GPG-подписи?
Это не редкость для небольших open-source утилит. В таком случае компенсируйте отсутствие крипто-проверки чтением кода и запуском в изоляции — контейнере или одноразовом VPS, — а не пропускайте шаг проверки полностью.
Стоит ли писать собственные install-скрипты в таком же стиле curl | bash?
Если аудитория — разработчики, которые разберутся, это удобно, но вместе со скриптом стоит публиковать SHA256-чек-сумму и, если возможно, GPG-подпись, а сам скрипт держать коротким и читаемым, без динамической генерации кода на лету — так вы сами не создаёте пользователям ту самую проблему, которую разбирает эта статья.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →