Curl to shell isn’t so bad (2019)
arp242.net
arp242.net
It is almost always far, far easier to hack into somebodies website and replace replace "good shell script" with "evil shell script" (or hack into someones GitHub account and make a commit evilifying a shell script) than it is to both do that and get a hold of the developers private key and sign the script. The signing key is usually far more protected and non-public than the web server is.
So no, I'm probably not going to review the entire install script either way, but I'm FAR more comfortable running an install script I found online that has been signed by a developer I trust rather than one that hasn't. Package managers and OS installers handle this for you and freak out if there's any issues.
In other words, the question with package managers/installers is "Do I trust this developer?". The question with curl-to-sh is "Do I trust this developer AND do I trust that the website hasn't been compromised".
You also have to verify that the script is coming encrypted over TLS. It's not mandatory, and there's no warnings if its not. Sure, it's an easy check (barring redirects, which also occur), but how many people who are copy/pasting curl|sh scripts will think to do even that basic validation?
The problem isn’t curl but the challenge of trusting code. The default needs to be either Apple-style sandboxing (note how you get prompted if a new program tries to access your pictures, contacts, etc.) or something like Docker where the default is private with exceptions for the resources you enable.
Maintaining packages is a lot of work: there are many of them, all with different policies/update schedules/etc. It can be very time-consuming to maintain a package for all systems. Package managers are great, but does come with some trade-offs, like most things.
There is nothing really stopping you from signing shell scripts; although I'm not sure if you'll still be able to run them with some clever "curl | gpg | sh" pipeline; but you can "curl>file; gpg [..]; sh file" it.
I think very few people actually verify signatures manually anyway, not in the least because it's kinda hard to do so (gpg is a beast, although there are some better alternatives now, such as signify/minisign).
The real problem is shell, or really any custom scripts in any language. Acquiring or building software should happen via well-understood reusable tools. Any time building executes bespoke code, you're reducing the maintainability of a system.
Distro package managers are one good solution, but a properly developed language package manager would also ideally not rely on custom scripts.
A contributing factor to the event-stream issue was that it was considered acceptable to distribute code minimized by _who_knows_what, rather than by any reproducible process.
Distro package managers allow execution of custom scripts at every point of the installation. If you're getting packages from outside the distro repos, you're at risk. Sometimes you're at risk even when you get the packages from the distro repos :-)
https://www.debian.org/security/2008/dsa-1571
Just because it comes from a distro doesn't mean it's from the developer.
It's a chain of trust that can't be provided by web servers and X509 certs.
At one level, any build/install tool is executing extremely complicated code on your machine, and could do lots of weird things. The advantage is that you can learn what it does, and have trust in its authors. So well behaved custom scripts created by a trusted party that has articulated standards about how things should work are much better than using shell scripts from an arbitrary project.
Still, I'd certainly prefer it if the distro didn't have custom scripts either. It would simplify the task of knowing "this is how the distro does things, and there are no exceptions".
From a security point of view, those are the same as curl | bash, basically.
Installer systems that chain these "download and run" scripts (Node RED is the most recent I've used) scare me despite all the valid points TFA makes. "Not invented here / history must be reinvented" seems like philosophical point for some of these systems.
This is why checking signatures is the most important part of code distribution. It doesn't solve every problem, but it solves most. At least then you know whose code you're getting, and that they attest to the code's validity (including safety). Maybe they're wrong or maybe they're not as good as you thought they were, but it's still a big improvement.
I prefer a package over either case, but lacking a package I'd prefer to use something that has some expectations of how it should behave. As a packager I find that software with a Makefile, CMakeLists.txt, or a configure script is likely to be easier to package than something that just provides a shell script. Those might still need to be patched or tweaked but there's an expectation that it's going to try to behave a certain way.
Every time somebody suggests this, the author needs to get slapped with a trout. Copy/Pasting code to get entered is BAD ENOUGH; nobody learns anything that way AND it is not secure!
In a race to the bottom everyone looses.
If I don't trust docker.com because I think it might deliver malware in the install script or a poorly written install script, then I shouldn't use Docker because why would anything different apply to their main software.
If I don't trust docker.com because I fear it might be hijacked then I shouldn't use Docker because who guarantees me that their source code or any derived binaries aren't also hijacked.
My point is telling new users to blindly copy/paste/autorun ALL scripts just to get $thing to work only hurts US (FOSS proponents) and the end user.
===
Partial content: the shell may execute half the script due to a network error.
Easily fixable by running in a function:
do_work() {
:
}
do_work
All of the cited examples already do this.
===
This is the one argument that I think the author gets wrong. Just because the projects he cited do this correctly doesn't mean that all `curl install.sh | sh` scripts will do this correctly. And this is the main fear that I have. I'm not all that concerned about people publishing malicious installation shell scripts. These things are normally public, so it would be easy for them to get caught. I am concerned about the scripts being either (a) altered in transit or (b) corrupted in transit (which is really the same thing).
It seems like there could be some happy medium where there was an install script that had a published signature (SHA1 and/or full cryptographically signed), and a tool that downloaded it, verified the signature, and then called a standard function: `my_install()` (or something).
If a vendor does deliver software over HTTP, then you should verify the script before executing it via a checksum delivered over some secure channel. (This is also what apt, the Debian package manager, does by default afaik.)
[1] https://stackoverflow.com/questions/34610581/is-it-necessary...
If you are curl|sh'ing and know why you're curl|sh'ing and know what you're curl|sh'ing and understand the implications of curl|sh'ing, then I don't see the problem.
Like most things, it's subjective.
Like I said, it's subjective. No such statement as "curl|sh is bad" or "curl|sh is fine" can be accurate on its own.
Exactly the same problem as with apt-get, brew, yum, npm, yarn, cargo, <the list just goes on and on>.
Most of those will run any number of scripts during execution without your knowledge.
[1] https://securityaffairs.co/wordpress/88433/hacking/npm-insta...
[2] https://securityaffairs.co/wordpress/74497/hacking/malicious...
[3] https://lists.debian.org/debian-security-announce/2019/msg00...
And if it takes a CVE to allow a MITM attack to inject a malicious payload into an apt package, that's already better than curl, which does not. It's also worth noting that the CVE had a stable fix available as of that announcement.
It's also worth noting that the problem was there before it was discovered, fixed, and then disclosed.
Ultimately, it comes down to how paranoid you are about your sources of software: https://wiki.c2.com/?TheKenThompsonHack
Later on if I decide to use the software, the bash script usually makes a nice reference for starting my own Ansible role or Dockerfile.
Link: https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-p...
HN discussion: https://news.ycombinator.com/item?id=10277470
How can I “sandbox” a shell script?
https://unix.stackexchange.com/questions/363363/how-can-i-sa...
What would a proper sandbox look like? Every session runs within a Docker image?
I don't know anything about this stuff. My intro to the sandboxing and security notions was Java and its Applets. I guess I thought we'd eventually do everything that way.
Check this out: https://www.idontplaydarts.com/2016/04/detecting-curl-pipe-b...
> You’re not running some random shell script from a random author, you’re running it from a software vendor who you already trust to run software.
Between custom domain names, TLDs, Let's Encrypt (I love Let's Encrypt, but it provides is encryption, not trust) and cheeky developers using combinations of those, how can I really know that a script coming from (fictional example) https://install.dock.er is actually the Docker company?
If you want to pull this even further. When is the last time you verified the signing keys of your OS distribution repo without relying on the internet?
A lot of install methods that are not curl/sh are like: here copy this bash line to add apt GPG keys for our repo, apt update and install. A lot of people don't bother to check those keys.
This is (currently) not possible to do with scripts downloaded from a web page. Especially when immediately piped into a shell.
I've seen this in other places as well. Vendor makes a comprehensive guide. Some people condense that to a minimum and will even boast they "made" an easier way to do X or Z, whilst ommiting all the caveats. Of course that will become the popular 'standard' people find. And they'll go complain to the vendor if it doesn't work without even reading the original instructions.
Plus you are pushing forward the bad pattern and being part of the problem.
You are encouraging other authors and users to do the same.
https://sysdig.com/blog/friends-dont-let-friends-curl-bash/
https://www.idontplaydarts.com/2016/04/detecting-curl-pipe-b...
These attacks can be mounted on the network side.
Also you can inadvertently execute data from a benign captive portal or a server error page and so on.
This is why its safe to download packages from mirrors.
With that having been said, Debian takes an extra step into the absurd by using plain HTTP with no TLS for downloading packages. There’s no obvious security issue with that, but it does feel like a bad decision, since anyone in your request path can see what software you’re installing, and if there ever were a vulnerability it would be much easier to exploit due to the lack of security at the transport layer.
x509 certificates certainly don't provide those assurances.
There’s differing levels of paranoia. I don’t pipe curl to shell at work. I do it at home sometimes, usually via Github.
Instead of providing justifications, perhaps we should focus on education (or making it simpler to be secure)?
Not that the autoconf input is readable itself, either, anyway...
Yes, surely? Somebody is probably exploiting it and you just aren't aware, because why wouldn't they have that in their toolbox?
I tried finding an example, and asked last time this was on HN as well, and thus far I've not found a single example.
Absolute security isn't realistic; it's often a trade-off between convenience, cost, etc. I can probably break in to your house by throwing a brick through your window ... should we now all invest in more secure windows? Doesn't strike me as a good trade-off for most people.
Linux distributions have this kinda figured out a long time ago with signed packages - almost a requirement if you want to distribute your software on mirrors that you don't control. This is why it's safe to download a package from a Debian HTTP mirror and install it. The thing afaik any of them still don't do, and is really important too, is checking the signature with a revocation policy.
I actually started writing about how I distributed a CLI for macOS, Linux, and Windows a few years ago but never finished it.
If you are writing Go code you want to take a look at Equinox.
I used it to distribute a CLI in my previous job, and it worked like a charm. One of the things I liked most was that I was finally able to push safe updates because I authenticated every release with my private key, and only allowed users to update if the key matched. If you have a primary and a secondary key, and a strategy to revoke it, this means you have a quite safe release process.
Related:
https://developer.apple.com/library/archive/documentation/Se...
https://developer.apple.com/macos/distribution/
https://developer.apple.com/documentation/xcode/notarizing_m...
https://blog.jessfraz.com/post/why-open-source-firmware-is-i...
https://docs.microsoft.com/en-us/windows/win32/seccrypto/cry...
https://docs.microsoft.com/en-us/windows/win32/seccrypto/sig...
https://www.mothersruin.com/software/SuspiciousPackage/
https://successfulsoftware.net/2012/08/30/how-to-sign-your-m...
https://arstechnica.com/gadgets/2012/02/developers-gatekeepe...
(I'm sure this issue has something to do with the popularity of containers)
Sure, some install scripts will be quite simple, but in that case, why do you need to have the install script in the first place? You'd only need it if the installation procedure was too complicated for an `INSTALL` or `README` document.
Surprisingly, yes. Especially for *nix systems where a lot of things (but not package managers) are more-or-less unified. The author may not have the time or desire to learn the half-a-dozen or so package managers and set up a build system to create packages for all of those, and then do the work of getting them into the standard repositories.
Just write software that is not unnecessarily difficult to package.