18 ms·
Backdooring Rust crates for fun and profit
- hn8788 5y agoStuff like this is why the place I work for decided not to use Rust as a replacement for future C projects. The devs evaluating it loved the language, and said they were more productive with it than they were with C, but being forced to either use no external dependencies, or audit tons of crates published by random people, made it a non-starter.
- dathinab 5y agoWhile the thinks mentioned are a thing, his recommendations and interpretation of them seems often strange for me. > Typosquatting Well known problem of more or less any open repo, namespaces do not solve it, they just shift the problem, maybe even make it more complex. > Misleading name Again not cargo specific and not specific to flat namespaces either. Namespaces help with first party packages from the same authors (but then it's not too hard to check the authors, but annoying; Annoying is insecure). But namespaces do not help with 3rd party libraries. I.e. many (most?) `tokio-` libraries are 3rd party libraries made to work with tokio, not libraries from the `tokio` authors. > Transitive dependencies Again something inherent to all package managers. Through some ecosystems like npm are worse due to using more smaller packages. In my experience while most rust crates have many dependencies most of them are to the same set of packages (like thiserror, anyhow, serde, etc.). Anyway trying to avoid unnecessary dependencies is generally not a bad idea. > “x.x.1” Update Basically: If you update a dependency you update a dependency, surprise. Anyway using a `=` dependency is a anti-pattern which produces an endless amount of headaches and incompatibilities especially with libraries using `=` imports. There is a reason lock-fiels exists and `cargo update` doesn't run by default. > Malicious update This point make no sense as: - cargo is not specific to the version control system you use it has some helpers for some vc systems, but that's it. - git tags are settable arbitrarily (and can be "moved"). - You get the source from crates.io, not GitHub. So the only way this can be a security vulnerability if you believe that reviewing not the source you use but source code from a different source is a good idea, while also trusting git tags while not fully trusting the author who sets the tags???? Just review the source code which you use, uploads to crates.io are immutable and you can download and read them. > Run code before main Neet to point it out, but not specific to either rust and even less to cargo/crates.io. It's specific to the systems binary file format and how binaries are executed. > principles of Rust is no life before main A design principal for the rust language, not a security statements. Anyway review the source code you use, not source code form a different source you believe should be the same (unspecific of rust). Rust could also improve on this by warning if (transitive) dependencies links to .ctor or similar. > Malicious macros Code generation is an interesting aspect to analyze across languages. Most have it, some like rust at compiler time and first calls, other at compiler time but second class and others at runtime (e.g. Java reflections). It's definitely an area where rust has a lot of potential to improve (e.g. default-wasm sandbox most proc-macros or similar). It's also unavoidable in some cases (e.g. building external dependencies). Additionally I would argue you probably could find a way to have code which somehow allows you to start running code when it's compiled due to you crafting the code in a way which triggers buffer overflows and similar in the underlying compiler (e.g. LLVM). You also tend to run tests... So theoretically you always should sandbox your IDE/project, even if you develop for a language which doesn't has compiler time code generation. As a side-note vscode ask you if you trust a project you open, if not it will change some settings for the project and rust-analyzer can be configured to no run build-scripts and proc-macros. (I haven't tested if not trusting automatically also makes rust-analyzer not run things.). > a bigger standard library would reduce the need for external [..] no, it doesn't reduce the need. See python. Or see how even some features in rusts standard library are frequently not used but instead externally libraries are used, e.g. parkinlot or crossbeam. Similar having 10 instead of 1 dependency might not decrease security if that 10 are a bundle from the same author in the same CI and have not (relevant) more code then if they where just 1 dependency. What you want is reducing the number of trusted entities (!=not packaged) and trusted lines of code. So having a group which manages a set of widely used packages with tight security would roughly be as helpful for the problem as having a bigger standard library, but much more practical. To some degree the rust nursery was going in that direction (but didn't reach that goal). > Rust supports git dependencies. It also allows pinning versions in Cargo.toml, pinning versions in lock-files and is immutable. Git dependencies are prone in making you miss security updates, similar 3rd party audits are likely done on the code uploaded to crates.io, not the one on GitHub. If you want to review all dependencies, and make sure to use them etc. then it's probably best to vendor all of them, and set thinks up so that your dev system can only see/reach vendored packages, while from time to time updating them based on crates.io and on diffs of the crates.io uploads (not GitHub).
- rectang 5y agoIs there a way to buy into PGP identity-based controls for crates.io packages? To say, "I trust the keys in this whitelist, so trust packages signed by those keys." > Thirdly, using cloud developer environments such as GitHub Codespaces or Gitpod. By working in sandboxed environments for each project, one can significantly reduce the impact of a compromise. That's appealing but expensive. I wish I could effectively sandbox a local developer machine. External boot drives, maybe?
- gpm 5y agoCargo-crev is that sort of web of trust, but it's really in it's infancy.
- rectang 5y agoCargo-crev's writ seems to be much more expansive and nebulous than security: https://github.com/crev-dev/cargo-crev/wiki/Howto:-Create-Review-Proofs https://github.com/crev-dev/cargo-crev/wiki/Howto:-Create-Re... > While it's still open for debate, the current opinion is that additional fields are not useful for the downstream users. Instead they just complicate their life, putting the burden of the decision from the reviewer onto them. At the end, a downstream user of a review just wants to know: "is it OK to use this package or not?". Your role as a reviewer is to provide that judgment. That irks me. I don't care about popularity contests, I only care whether a crate is malicious or not. If it has security vulnerabilities, I can deal. But if downloading and running a proc macro crate build runs gives an attacker remote code execution and they install a keylogger on my dev box, that's altogether different.
- ChrisSD 5y agoIf the crate is actively malicious then crates.io should be informed immediately and the crate removed. Probably the author too. If need be RustSec can issue a security advisory.
- dane-pgp 5y ago> Actually, my num_cpu crate has been downloaded 24 times in less than 24 hours, but I’m not sure if it’s by bots or real persons. Presumably the author could include some payload which phones home with a randomly generated ID, to detect how many machines the package could take control over. That's probably more meaningful than trying to decide whether the package was downloaded by a "bot", and wouldn't involve any GDPR-breaking information.
- CloselyChunky 5y agoThe easier, less invasive but also less accurate option would be to publish an empty crate with a random name that does not exploit typos (just some random junk) and check how often that crate is downloaded. You can assume that almost all downloads for this crate are bot downloads and just subtract that amount from the downloads of the typo-squatted crate
- wizzwizz4 5y ago> and wouldn't involve any GDPR-breaking information. Actually, this would (in my non-legal opinion) be a GDPR violation. See https://gdpr-info.eu https://gdpr-info.eu for details.
- dane-pgp 5y agoYou want me to read the entire GDPR? It's apparently 261 pages long. https://www.enterpriseready.io/gdpr/how-to-read-gdpr/ https://www.enterpriseready.io/gdpr/how-to-read-gdpr/
- wizzwizz4 5y agoIt's not that long, and you don't need to read the entire thing. The first few articles make it clear that you can't do this. Article 4 > ‘personal data’ means any information relating to an identified or identifiable natural person (‘data subject’); an identifiable natural person is one who can be identified, directly or indirectly, in particular by reference to an identifier such as a name, an identification number, location data, an online identifier or to one or more factors specific to the physical, physiological, genetic, mental, economic, cultural or social identity of that natural person; Creating a random identifier to identify individuals means you're working with personal data. (And it's coupled with the IP address, and hence crude location data – and OS information, and metadata about their behaviour…) Article 6 > Processing shall be lawful only if and to the extent that at least one of the following applies: None of them do. If you had consent, then this would be fine, but the whole idea is going behind people's backs to secretly reprogram their computers to phone home, for your own curiosity. That's not allowed.
- cntlzw 5y agoHow do rust crates compare with something like maven or npm? It looks like some issues for example Typosquatting can be done in all of these dependency managers.
- ChrisSD 5y agoThese do all seem to be things that apply to most package managers of this kind. So it would be good if Rust could find solutions that can be applied more broadly.
- junon 5y agonpm has some guards for typosquatting. They're annoying when you run into them but I appreciate that they're there. I have no idea how effective or extensive they are, though.
- tetha 5y agoMaven Central is somewhat resilient against this. In the java world, an artifact is identified by a group-id, an artifact-id and a version, and some technical stuff. The group id is a reversed domain, like org.springframework. If you want to upload artifacts with the group id "org.springframework", you first have to demonstrate that you own springframework.org via a challenge, usually a TXT record or some other possibilities for github group-ids and such. It's not entirely bulletproof, because you could squat group-ids "org.spring" or "org.spring.framework" (if you can get that domain). However, once a developer knows the correct group id is "org.springframework", you need additional compromises to upload an artifact "backdoor" there. Edit - and as I'm currently seeing, PGP signatures are also required by now.
- deleted 5y ago[deleted]
- brabel 5y agoIt's a hell of a lot harder to squat namespaces as you need to either spoof or steal or buy one domain per namespace, which is not trivial. Maven Central has require PGP signatures since the beginning as far as I know! In the olden days, it didn't use HTTPS though (which has been fixed for several years now), so unless you validated the signatures and kept track of the PGP keys, you could still run into trouble.
- rvz 5y ago> As Rust is designed for sensitive applications where reliability is important such as embedded or blockchain-like projects, it can raise concerns. This is why I get very concerned with Rust projects using tons and tons of external crates. Especially cryptocurrency projects using Rust. These sort of techniques can be used to compromise lots of them at once which in the very worst case can lead to loss of funds and is irreversible. Unfortunately we will see the same issues found in NPM be found in crates.io with cargo. Oh dear.
- natded 5y agoThis is an issue with any ecosystem. The alternative would be to have them in standard library which is silly. The actual solution I guess are domain specific languages.
- rvz 5y ago> This is an issue with any ecosystem. So repeating the same mistakes that NPM has into other package managers? We have therefore learned nothing at mitigating these supply chain issues then. > The actual solution I guess are domain specific languages. Any production real world examples of this?
- oytis 5y agoWith any ecosystem that has a packet manager. Try inserting a dependency backdoor into a C++ project where dependencies have to be managed manually (and consequently are few)
- ziml77 5y agoOf course if they need to be manually updated, there's a strong likelihood that they are using vastly outdated versions of their dependencies. Users could be wide open to unpatched exploits.
- oytis 5y agoNot necessarily. C/C++ relies vastly on dynamic linking which means keeping your dependencies up to date will be outsourced to distro maintainers. You'll have to make sure that your package builds for new versions of the distro.
- mullr 5y agoWhat are people doing about this on the client side? The solution that comes to mind is to do all my Rust builds in a sandbox of some kind, but with rust-analyzer involved, I'd likely have to put my editor in there as well.
- gpm 5y agoThere's some work towards moving the scarier parts of rust builds (e.g. procedural macros, that run arbitrary code) into a wasm-based sandbox. E.g. [1]. Obviously doesn't make the final artifacts safe to run though, and I also wouldn't trust LLVM to have no bugs exploitable by feeding it bad code, but at least it would raise the bar. [1] https://github.com/dtolnay/watt https://github.com/dtolnay/watt Edit: And someone on reddit brought up vscode's dev containers [2], to move everything into docker. Obviously docker isn't really a security sandbox, but again it raises the bar. [2] https://code.visualstudio.com/docs/remote/containers https://code.visualstudio.com/docs/remote/containers
- rectang 5y agoAt first glance, watt looks like a substantial improvement that would close the door on arbitrary code execution by proc macro crates. Yes, please! While this may not solve the general problem of package identity validation, it closes a Rust-specific hole that hopefully doesn't need to exist. Now if only `build.rs` could be nerfed...
- duped 5y agobuild.rs is particularly useful for Rust because it is routinely used to compile C/C++ object files as a previous step, which is crucial to having solid Rust to C/C++ FFI. It is no different from a ./configure script, or other prebuilt script. Lots of builds require these, and "nerfing" it just makes building Rust harder. Cargo is already a crippled build system that requires extensions like cargo-make to be useful. Getting rid of something so fundamentally required by modern software with no standard fallback would be a massive blow to the ecosystem. I really am not convinced that there is anything "scary" about a build.rs file - other than that standard tools like rust-analyzer find it sane to run external code during initialization. Your language server shouldn't be coupled to the build system and require it to run! (And yes, Cargo is a build system - it's just a bad one)
- loeg 5y agoYou don’t really need the ‘—allow-dirty’ flag to do as the author claims. There’s no enforcement that the local git commit is ever published to a public repo.
- Diggsey 5y agoThere's going to be a risk to running someone else's code. There are two factors here: 1) Do I trust the code I think I'm running. 2) Am I actually running the code I think I'm running. With (1) there's not really any way around it: someone or something has to review the code in some way. Even the suggestion to have a larger standard library doesn't really address it: with a larger standard library the rust project needs more maintainers, and it might just get easier to get vulnerabilities into the standard library. Someone could build a tool that automatically scans crates uploaded to crates.io. It could look for suspicious code patterns, or could simply figure out what side-effects a crate might have, based on what standard library functions it calls, and then provide that information to you. For example, if I'm looking for a SHA256 crate, and I notice that the crate uses the filesystem, then I might be suspicious. With (2) there are some easier options, such as making it easier to download or browse the contents of a crate directly from crates.io, or have a tool to show the full dependency source diff after a `cargo update`. For initially installing the crate, the number of downloads is a pretty good indicator of "is this really the crate I meant?".
- curun1r 5y agoI’m not sure I agree with your fatalistic take on (1). As an example, the proof-of-concept proc macro attack from the article could be addressed by running proc macros in a wasm sandbox. I know there’s been some exploratory work done towards that. Similarly, all of the attacks that execute code at compile time are mostly addressed currently by building code in a Docker container. It’s not a perfect security measure, but it greatly increases the probability that a build.rs or proc macro attack will fail. Your (1) strikes me as something that can never be solved to provide 100% safety, but that there are partial solutions which, in practice, can significantly reduce the attack surface. And hiding behind “fundamentally unsolvable problem” will get in the way pushing for the meaningful half-measures that offer some degree of real-world protection.
- kevincox 5y ago> could be addressed by running proc macros in a wasm sandbox Kind of. That will stop the compromise on build, but odds are then you run the code anyways so injecting the code into the executable is almost as good. I guess if you are building an application that is always run in a sandbox anyways (like a wasm application that never sees sensitive data) then sandboxing proc macros could be good enough but I suspect that is a very rare case.
- PragmaticPulp 5y agoI use “cargo … —-locked” to install things using the dependencies from the Cargo.lock file, which includes specific commit hashes for dependencies. Avoids things like the 0.0.1 problem or even replaced crates. Need to be careful to watch for actual security updates, though. I really wish crates.io would have at least launched with a name spacing feature. This wouldn’t solve every spoofing or typosquatting issue, but it would go a long way toward improving the situation. There’s a separate issue of crates.io squatting. One person famously registered hundreds (or thousands? Tens of thousands) of common words as crate names on crates.io and has been squatting them ever since. Those names are effectively unavailable for use but also completely useless because they don’t contain anything. It’s also becoming a huge problem for abandoned crates. New forks have to choose a completely different, less intuitive name because they can’t just namespace their alternative. As old crates get abandoned, this leads to weird situations where the newest, best maintained crate has the least obvious crate name. It takes work to find the good crate some times because the best named crates might just be the oldest, most abandoned ones
- Lifelarper 5y agohttps://users.rust-lang.org/t/name-squatting-on-the-crates-io/42415 https://users.rust-lang.org/t/name-squatting-on-the-crates-i... This a very old discussion if you keep digging through the links.
- ansible 5y agoI hope that the Rust Foundation (which finally exists) can put in some time / resources to help fix this. I totally get that maintaining crates.io is a time suck for all involved, and mediating disputes would increase that even more. But at some point, this is going to need to be addressed.
- belter 5y agoI think if somebody decides to act as a vandal I can too? https://crates.io/users/swmon https://crates.io/users/swmon Edit: Lots of love for this user in the thread.... https://github.com/swmon/Charles-Crack/pull/1 https://github.com/swmon/Charles-Crack/pull/1
- infogulch 5y agoI'd like to see a notification when the repo tag contents doesn't match the cargo tag version.
- Lifelarper 5y ago> I’m not sure if it’s by bots or real persons The bot usage is a significant amount of the low level noise, I've published things of no use to anyone and they always rack up a lot of dl's despite no one practically using them for a long time. > Firstly, a bigger standard library would reduce the need for external dependencies There's years worth of the same arguments tiringly made over and over again (same with namespacing) on the rust forum, everyone has played their hand on this issue a dozen times now, the community clearly has a majority stance on such things. > A variant of the previous technique is to use the --allow-dirty flag of the cargo publish command. Please correct me if I'm wrong but thought that flag simply allows uncommitted changes to be published, the source is still availabile for anyone to view on crates.io > We're sorry but this website doesn't work properly without JavaScript enabled. Please enable it to continue. Works perfectly fine for me. Maybe you couldn't serve me a gdpr or something. Thankfully I can keep it turned off for now :)
- dathinab 5y ago> crates.io matches the code on GitHub, There is no tight coupling between GitHub and cargo/crates.io (sure it uses GitHub internally but that is an implementation detail). But not only has it no tight coupling with GitHub it also doesn't require you to use git, you can use whatever version control you want and at worse you don't get support for "detect dirty repository". Similar git tags are fundamentally unreliable as you can always "move" some to any arbitrary commit. So IMHO the problem here is relying on code you didn't got from github which might not even use git to match a arbitrary tag on something on github which might not even be from the same author (but e.g. a mirror on GitHub from whatever VC the author uses). But uploads to crates.io are immutable and are source code uploads, so you can just review them. In general (independent of cargo) do review the code you use not some code you got form somewhere else which you hope/believe is the same.
- PragmaticPulp 5y ago> There is no tight coupling between GitHub and cargo/crates.io (sure it uses GitHub internally but that is an implementation detail). Cargo had a “locked” option that uses the URL and commit hash from the Cargo.lock file. If the crate, repository, or commit has changed then it won’t build. This is what everyone uses for reproducible and secure builds, but it’s not as commonly used for casual use.
- jhugo 5y agoMost cargo deps aren't specified as Git deps, so there's no repository or commit hash to check. Cargo.lock has a hash of the crate itself; there's no requirement that it even came from a VCS repository. You can publish from a local folder. Checking the hash of the crate still verifies that the code hasn't changed, I just want to clarify that there isn't some mechanism by which non-git deps are automatically verified back to the VCS repo commit hash they came from.
- rectang 5y agoIt may be possible to publish from a local folder and offer the user no history or context. However, I think it makes sense to privilege packages which can be cryptographically verified as deriving from a specific commit within an open source commit history, in a public repository at a specific URL.
- zelos 5y ago> How to protect? > By pinning an exact version of a dependency, tokio = "=1.0.0" for example, but then you lose the bug fixes. Surely no one uses version ranges in production? Is the default really not to use an exact version for crates?
- steveklabnik 5y agoThe default is to declare ranges, but then you get a lockfile after an initial build, and Cargo will use those exact versions until you ask for changes.
- Macha 5y agoThe default is to use ^x.y.z so it'll pull in patch versions.
- caffeine 5y agoSeems like you could address with a super-crate that includes "trusted" crate releases as "features" That crate could involve some automation like: * Checking that the code in the crate matches the code in Github * Checking whether the latest commit is from a new committer, or whether there is any code comitted by a user not in a whitelist, * Checking whether the package has any known security advisories * Checking that crate signatures match some whitelist * Running a project that includes the crate in a sandbox and seeing whether there are any files accessed, network accesses, etc. that were not pre-whitelisted New versions of included crates would have to go through this battery of checks before they get bumped in the super-crate. Crates that want to be included as features of super-crate or that need to change/add significant functionality, or add dependencies, would need to make a PR to update the relevant whitelists, which could then be reviewed by the super-crate team
- epage 5y agoThis has come up several times in the past. One name for it was stdx. Some in the ecosystem are very cautious of picking winners and losers, limiting the exposure to new break-out crates. Rarely recommending crates for different problems. This comes at the cost of making it a harder barrier to get involved because you need to be "in the know" for what crates to use or avoid. Another problem with stdx is if anyone uses types from this in their public API, they are decoupled from the individual crates semver constraints which makes it hard to know which breaking changes from your dependency are a breaking change in your API.
- 3r8Oltr0ziouVDM 5y agoWe should switch to using pure functional languages by default. Most of the packages don't need to do any side effects and only perform pure calculations. In a pure functional language it is obvious from function signatures if these functions are able to perform side effects, so it's not possible to hide a backdoor inside a pure function. An average project would depend only on a few impure packages, such as a HTTP client or a framework, therefore it would be much easier to verify the security (for small impure packages you could just inspect their code yourself, and bigger packages like frameworks would have many contributors that check the code and strict policies about their security). Languages like Rust and C++ for which the pure functional model doesn't work should then only be used for performance critical code, and projects written in impure languages should avoid third-party dependencies as much as they can.
- frenchyatwork 5y agoI don't get how that would solve you problem at all. You can implement a bitcoin miner using functional code then just add an http client as a dependency for getting data to/from the blockchain.
- 3r8Oltr0ziouVDM 5y agoYou can't perform HTTP requests from a pure function without making it obvious in its signature that it does side effects. For example in a language like Haskell: add : Int -> Int -> Int add x y = x + y There is no way a function like this can run a Bitcoin miner, all it can do is to return an `Int`. In order to do side effects, a function must return a special `IO` type that should then be returned from `main` (and only then these side effects would be performed).
- thewakalix 5y agounsafePerformIO exists, though. I suppose Safe Haskell might provide what you want, but (as someone mentioned elsewhere), the point of evaluating a pure function is to use its result somehow; a pure function that is supposed to look up a bitcoin address in a Map, but is changed to always return a constant one, could be just as bad of a backdoor.
- jrochkind1 5y agoMost of these are common to other platform packaging systems, and I'm not sure I've seen any especially interesting solutions to them. The macro-based ones are rust-specific and seem especially devious and challenging to me.
- ReactiveJelly 5y agoI think I/O isolation will be part of a solution. I'm interested to see how Deno handles that.
- devmunchies 5y agoDoes deno allow you to scope the IO permission at a dependency level? This comment from 9 months ago indicate its only at the app level. has it changed? https://news.ycombinator.com/item?id=26090873 https://news.ycombinator.com/item?id=26090873
- deleted 5y ago[deleted]
- peterth3 5y agoDiscussion on /r/rust about this article: https://www.reddit.com/r/rust/comments/qw3w01/backdooring_rust_crates_for_fun_and_profit/ https://www.reddit.com/r/rust/comments/qw3w01/backdooring_ru...
- verdverm 5y agoI wrote https://verdverm.com/go-mods/ https://verdverm.com/go-mods/ to talk about ways Go avoids some of these pitfalls. The forethought that went into `go mod` is one of the reasons I like and trust Go
- Groxx 5y agoI only see one that it avoids: domain names / URLs as import paths makes ownership much more clear, and slightly harder to achieve typo-squatting... sometimes. And I do very much like this part of go modules, it also helps decentralize the whole system a fair bit. I sincerely hope it becomes the dominant package-name strategy in time. But lets pick another that seems on the surface pretty likely to be mitigated: source for downloaded-version X not matching version X repo's source, under "Malicious update" with cargo's `--allow-dirty`. After all, goproxy pulls from git repos directly, right? There's no --dirty flag or anything to push random garbage. That's still a problem! Git tags are mutable, as are git repositories as a whole. You can absolutely tag a malicious version, get it into goproxy, and then change or remove the tag and any associated commits. The goproxy doesn't even store the SHA for correctly-tagged versions, only the code and a checksum of the code it saved, so finding the commit that it originally pointed to can be difficult or impossible. You can download the module and read the code from that, but that's true of any non-binary dependency system. You can't publish a change to an already-published version, but that's true of cargo too (afaik) as well as most package hosts (afaik), though goproxy takes a minor technical step further to make that accident-resistant (or at least easily detectable. which is great, everyone should do that).
- verdverm 5y agoA module in Goproxy should be in the global SumDB, so if you are consulting that (the default), even if someone managed to get a retag in, it would fail the sumdb check. I suspect that Goproxy, by virtue of running Go under the hood, consults sumdb prior to adding to the proxy. As long as a tag was fetched once, I would expect that any changes would be caught. There are of course edge cases, such as custom domain go get hosts are not all kept in the GoProxy, but their content hash should be.
- uncomputation 5y agoIMO some simple (not easy, but simple) solutions would go a long way here. - Support name spacing - Support specifying non-crates.io server (docket does this) - Throw warnings when the Git tag (if applicable) contents do not match the Cargo upload. Rate limit package owners so they are encouraged to set their tags right the first time and not move around RE: compile time execution. This is a harder problem, common to any binary file distribution.
- steveklabnik 5y agoThe second is already something that exists.
- jynelson 5y ago> While it’s possible to audit the code of a crate on https://docs.rs https://docs.rs on clicking on a [src] button, it turns that I couldn’t find a way to inspect build.rs files. Thus, combined with a malicious update, it’s the almost perfect backdoor. Docs.rs has its own source view on /crate that's separate from rustdoc's. For example, you can see the build.rs for boring-sys on `https://docs.rs/crate/boring-sys/1.1.1/source/build.rs https://docs.rs/crate/boring-sys/1.1.1/source/build.rs`.
- richardwhiuk 5y agoYou can also download the crate directly from crates.io
- thorum 5y agoI’m increasingly fatalistic about computer security. It seems like your options are carefully auditing all dependencies (difficult and maybe impossible if the dependencies are highly technical or the malicious code is sufficiently subtle or obfuscated) every time you update, not updating at all (which leaves you vulnerable to all the bugs and other security issues in the version you choose to pin), or not using dependencies at all (by spending months or years totally rewriting the libraries and tools you need, and of course your own code will have bugs too). Fixing the points addressed in this article helps by making it harder to slip these backdoors in, but will never be foolproof unless every single library has a maintainer with the skills to detect subtle bugs and security issues, who audits every line of code. Even then the marketplace for unreported zero day vulnerabilities means that there are probably undiscovered vulnerabilities somewhere in your dependencies (or in the code for your IDE or OS or Spotify app or mouse driver...) that can be exploited by someone. I’m reminded of the Commonwealth series by Peter Hamilton, in which the invading aliens have no machines, and quickly discover that ours are full of bugs that can be exploited to turn against us. I don’t know what the solution is. Sandboxing your development in a codespace like Gitpod is a big improvement for sure, but even in Gitpod a lot of people import credentials and environment variables that can be stolen. (And what dependencies is Gitpod itself running?)
- remus 5y ago> I’m increasingly fatalistic about computer security. It seems like your options are carefully auditing all dependencies (difficult and maybe impossible if the dependencies are highly technical or the malicious code is sufficiently subtle or obfuscated) every time you update, not updating at all (which leaves you vulnerable to all the bugs and other security issues in the version you choose to pin), or not using dependencies at all (by spending months or years totally rewriting the libraries and tools you need, and of course your own code will have bugs too). There is also the option of having trusted third parties review code. This is by no means an easy option but it does seem more feasible than everyone auditing every line of code they ever depend on. You do end up with spicy questions like who do we trust to audit code? Why do we trust them? How are they actually auditing this code?
- 5y ago
- ferdowsi 5y agoThe anemic standard library in Rust always seemed like a disaster waiting to happen. Javascript gets heaps of deserved criticism for its standard library, but at I can generate a SHA-256 without needing to pull in a third party library.
- lillecarl 5y agoNobody is mentioning C#, but my experience there is that I rely on a lot less dependencies and a rather big standard library from Microsoft. Microsoft has been splitting the standard library into separate dependencies now, but they're still maintained by them and I feel safe depending on them.
- pdimitar 5y agoThere's zero backdooring involved anywhere in this article. His most convincing argument seems to be "if your account as a package maintainer is hijacked then bad things could happen" -- well yeah, thanks for the insight Sherlock. I'd be genuinely excited to read objective and deeper analyses of the Rust ecosystem in which I am looking to invest myself further. I want to know what exactly I am getting involved with so I'd welcome any good criticisms of it. But not click-baity articles with almost zero substance inside. He's basically repeating old lists of risks of human error.
- stubish 5y agoHe describes compile time backdoors (Rust macros) and backdoors that can be triggered by loading the code into a standard development environment (standard hooks called by code editors on load). Both of these are novel. Name squatting and account compromise are common to several ecosystems, but using a compromised account to backdoor a transient dependency that automatically executes code when your CI system compiles, allowing it to steal the tokens you use to publish builds to your customers, while you are asleep, is somewhat novel and worrying. And then as a bonus, compromise your laptop when you start inspecting the rubble to work out what just happened.
- lilyball 5y agoNeither of these are novel. Compile-time behavior in existing language ecosystems such as C/C++ require running supplied configure/build scripts. The idea of running untrusted code at build-time is not remotely new. The part about triggered by loading code into a standard dev environment is identical to "my dev environment automatically compiles dependencies for me", and is something that is handled by the dev environment (e.g. VSCode's "trusted workspace" stuff) rather than the language. Rust is not responsible for IDE tooling running build scripts and compile-time macros. Also FWIW, rust-analyzer has settings for whether to do this (separate from VSCode's trusted workspaces).
- stubish 5y agoWhile my C/C++ knowledge is minimal and decades out of date, I don't recall dependency management systems that automatically download new versions of transient dependencies rather than using the tarballs you provided or simply linked with whatever it found in $INCLUDES (although I do recall custom build scripts that 'helpfully' tried to download and build dependencies like libssl, always annoying and often MITMable). Yes, you will be running untrusted code but you downloaded it and all the transient dependencies and had the opportunity to audit it (or realize you could be using the prebuilt OS packages instead and choosing to trust the those maintainers). I think Python shares the same issue as Rust in that the standard tooling will by default pull down newer versions of packages and building them can run arbitrary code. I don't think Go does, as I don't think the potentially dangerous code generation comments are run by default?
- pornel 5y agohttps://lib.rs/cargo-crev https://lib.rs/cargo-crev tries to address this. It allows you to review the actual published source of your dependencies. It then can check whether your project only uses reviewed dependencies. Reviewing everything is of course a lot of work, so there’s an option to mark crate owners as trusted, and also reuse code reviews made by people you trust.
- baby 5y agoThat's why I started https://github.com/mimoo/cargo-dephell https://github.com/mimoo/cargo-dephell and https://github.com/diem/whackadep https://github.com/diem/whackadep btw, to try to get a sense of the risk in our Rust dependencies. Whackadep runs a a webserver that updates periodically and shows you what's up with your dependencies. If there's a new update, the idea is to estimate a sense of urgency (are we lagging behind? Is it a major version change? Is there a RUSTSEC advisory?) and a sense of risk. For example, it'll tell you if a new dependency version touches a `build.rs` file. I wanted to add more rules, like the ones mentioned in the article, but never had the time to do it.
- gspr 5y agoI love Rust, but it's particularly frustrating to me how it (nearly) forces you to use a single centralized package repository. Shameless plug for an issue: https://github.com/rust-lang/cargo/issues/10045 https://github.com/rust-lang/cargo/issues/10045 I don't have a gripe with crates.io per se, but that the tooling doesn't work offline and works poorly without crates.io is a real problem.