Skip to main content

Keeping your open source credentials closed

著者:

2015年12月14日

0 分で読めます

Earlier this month, a researcher named ChALkeR shared his research on leaked credentials in npm packages. The findings showed credentials, such as npm and GitHub tokens and passwords, are frequently included in published npm packages or GitHub repositories. In fact, 13 of the top 15 npm packages depend on packages that leaked credentials, thus exposing their users.

ChALKeR’s post is a good read and the first npm-specific leaked credentials analysis I know of, but the problem itself isn’t new. GitHub search made it easy to find private keys nearly three years ago (reportedly exposing keys from the Chrome team), and Google can expose all sorts of private info. As code gets more discoverable, mistakes like this would be more easily found, which is all the more reason for you to do something about it.

To ensure you are following proper security guidelines, download Snyk's cheat sheet outlining 10 npm Security Best Practices. You'll learn how to adopt secure npm usage practices, useful for Node.js and JavaScript developers.

Why you should care about leaked credentials

Leaking credentials means exposing secrets that provide access to different accounts.

The most common types of leaked credentials are passwords, API keys and SSH private keys. These keys may be sufficient for an automated tool - be it your own or an attacker’s - to perform an action, for instance publish a new version of a package or delete code. The actual range of actions each key is allowed to do varies by key and system.

If you’re consuming open source packages, the credentials that should worry you most are those that allow publishing new code, such as an npm token or a GitHub deploy key. An attacker with access to those can easily publish a new “fix” version with malicious code in it, which you’ll often implicitly install.

If you’re hosting your open source project somewhere, you should also beware leaking any information about your runtime systems. This goes beyond npm, as you may expose your AWS keys, SSH private keys or passwords for different systems. Any one of these keys could give attackers access to your system, which can be used for anything from stealing your IP and user data to simply getting free compute (leaving you with the bill).

As an open source developer, what should I do?

Beyond being aware of the risk, you should establish a few best practices as part of your flow, and introduce multiple layers of defense to help prevent mistakes. Here are some specific suggestions you could consider:

Avoid blanket git add * commands

Using wildcards can easily capture local files not truly intended to be shared. This is especially important when adding entire subfolders (e.g. git add dirname), as doing so will include hidden (dot) files too.

Instead of wildcards, name each file you commit, or use git add -p to review each change you add.

Name sensitive files in .gitignore & .npmignore

Both git and npm support a local file listing exclusions from packaging and commits, which you can use as a safety measure against accidental inclusion of sensitive files. If you don’t specify ignores, npm will still ignore certain files, but git will include them all. Defaults aside, neither tool knows your application as well as you do, so its best to edit these files yourself.

Sample files to be wary of are:

  • CI configuration files (e.g. .travis.yml, circle.yml)

  • Dockerfile and docker-compose.yml

  • Build output files (e.g. gypi)

  • Custom deploy scripts (e.g. anything under /deploy/ or /scripts/).

ChALKeR lists a few other examples in his post, and you can use GitHub’s sample .gitignore files for other inspiration.

Note that npm’s broader default ignores were only introduced in npm@2.14.1, so be sure to upgrade to that version or newer.

Encrypt or use environment vars when publishing from CI

If you publish to npm through your CI, you’ll need the CI to have access to your npm token, and its easy to mistakenly add that token to the CI config files and expose it.

When possible, use an environment variable to hold that token instead, keeping it out of source control and obfuscating it in the output (at least on Travis & Circle). If for some reason you have to include a key in your source control (for instance, if you want to commit content back into GitHub), make sure you encrypt it well.

git-secrets: git hook prevents committing in credentials

Michael Dowling at AWS Labs recently released a useful tool called git-secrets. The tool hooks onto git commit, and breaks the commit if it includes patterns that appear to be credentials. This is a good content-focused safety net, complementing the previously suggested filename based protection.

It’s important to note you need to catch these before you commit (or rather, before you push), like this tool does. For open source projects, testing as part of the CI or pull request process is too late - the credentials have already leaked.

Invalidate leaked credentials

Lastly, if you learn that you’ve already leaked some key or password, make sure you quickly invalidate those tokens.

Removing the token from the latest release or branch will not be enough. Even if you deleted historical references, copies of your key will be around even if you now remove them from GitHub and npm - the internet never forgets. It’s also a good idea to do some house inspection and see if anybody used the key in the meantime to publish bad code or access your systems.

As an open source consumer, what should I do?

There isn’t much you can do as a consumer of open source packages. By using a package you’ve explicitly put your trust in it and implicitly trust the dependencies it pulls along. Security blunders by those dependencies can compromise your own systems, be they leaked credentials or vulnerabilities (you can use Snyk to address the latter). According to ChALKeR, the credentials he discovered have now been invalidated by GitHub and npm respectively, and invalidated credentials do not pose a security risk anymore (assuming they haven’t been exploited in the interim).

That said, if you want to be proactive you could consider auditing your own dependencies and see if they share information you think they shouldn’t. Some bash foo can help you find the relevant dot files in your dependencies, after which you can make your own decision about whether or not they contain private information.

Here’s a bash Mac/Linux command to get you started. It finds some of these files, drops duplicates and outputs them along with the filename:

find . \( -name '*.gypi' -o -name '.npmrc' -o -name '.travis.yml' \) | xargs md5 -r | sort | awk '{print $2" "$1}' | uniq -f1 | sort | awk '{print "echo "$1";cat "$1}'

Summary

Developing in the open is great, but not everything is meant to be shared. Leaking credentials puts your consumers at risk, and in turn their users.

Separate your credentials from your code, and make everybody aware and alert to this risk. Look for leaks in code reviews, and add it as a check to your standard practices. Beyond process, set up the safety nets described above to catch cases of human error. Lastly, if you learn you’ve leaked, handle it well - invalidate the tokens, alert your users, and inspect your code for malicious traces.