Almost nine years ago, a new open source project named NuGet (www.NuGet.org) made its debut and two years after that debut, NuGet was and continues to be shipped with Microsoft Visual Studio. NuGet is one of several package managers, like Node Package Manager (NPM) for JavaScript and Maven for Java. Package Managers simplify and automate library consumption. For example, if you need a library to implement JavaScript Object Notation (JSON) capabilities in your .NET application, it takes a few clicks of the mouse and just like that, your application has powerful capabilities that you didn't have to write, free of charge.
Once upon a time, developers built and maintained their own libraries. If you needed a library, chances were, you asked fellow developers in online communities hosted in CompuServe in the giving spirit that was incident to such communities, and chances were good that you could get a code library to meet your needs or, at the very least, you could get guidance on how to build it.
Today, Open Source Software (OSS) has created an unprecedented availability to code and package management systems that make absorbing that code into your applications a nearly friction-free process. That progress has ushered in not only numerous benefits, but new risks and problems as well. One recent example is the November 2018 Event Stream incident involving NPM (https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident). This article addresses how to responsibly leverage NuGet in Visual Studio in a way that mitigates risk.
If you work for a public company governed by SOX or are subject to the Health Insurance Portability and Accounting Act (HIPAA) or Payment Card Industry (PCI) regulations, if your applications directly rely on a public NuGet source, there's more than a fair chance that your company may be in violation of the aforementioned standards despite the lack of any adverse event.
No production application or build process should ever take a direct dependency on any public package source.
In Case You're Not Familiar with NuGet
If you're not familiar with NuGet, what it is, and generally how it works, for additional context, you may want to consult the documentation: https://docs.microsoft.com/en-us/NuGet/what-is-NuGet. If you want the comprehensive documentation PDF, you can download it here: http://bit.ly/NuGetPDF. If you're a Pluralsight subscriber, you may want to watch my Introduction to NuGet Course: https://www.pluralsight.com/courses/NuGet.
The concepts presented herein do not require an extensive NuGet understanding. The intended audience includes experienced developers as well as directors and managers tasked with implementing a company's security and risk mitigation policies.
Package Managers and Package Sources
Before delving into the basic package manager concepts in .NET/Visual Studio with NuGet, let's get some context on package managers and packages in general. The following are the core definitions you need to understand:
- Package: An archive file (i.e., a zip or tar file) that contains code artifacts and additional metadata used by a package manager that, in turn, is used by a development environment to add a package's contents to a project.
- Package Manager: A tool that an application development environment (i.e., Visual Studio, Eclipse, etc.) uses to gain access to packages contained in a package source. Common package managers are NuGet, Maven, and Node Package Manager (NPM). Not only does a package manager manage access to a specific package, it also manages the access to other packages that the downloaded package depends upon (dependency management).
- Package Source: A collection of packages that, for each package, contains metadata about that package. Such metadata includes the current version number, release history, links to the source code repository (i.e., GitHub), documentation, licensing information. Common package sources include NuGet.org, MyGet, and npmjs.com.
Companies should build and manage their own packages and the dependencies thereof, and create and use their own Package source feeds.
The relationship among these three (NuGet.org, MyGet,, and npmjs.com) is simple: Application development environments use package managers to connect to package sources and obtain packages to be used in an application development project.
What's the Risk?
Of the three elements in the bulleted list above, risk arises from two: Packages and Package Sources. Package sources like npmjs.com and NuGet.org are open environments to the extent that anybody can get an account and upload a package for others to download. For that reason alone, such open
package sources are inherently untrustworthy. Does that mean you should avoid such open sources? Of course not. What it does mean is that when taking packages from such sources, you should perform the necessary due diligence to verify that package's contents. If you can't determine a package's provenance and its contents with certainty, you're exposing your firm to risk that could be otherwise mitigated. A real-world example of risk exposure and the consequences thereof was the Event Stream incident discovered in November 2018. That incident involved malicious code in a package that harvested account information from accounts having BitCoin balances of a certain level. The register reported (https://www.theregister.co.uk/2018/11/26/npm_repo_bitcoin_stealer/) that the code was part of a popular NPM library that on average, was downloaded two million times per week.
If you can't determine a package's provenance and its contents with certainty, you're exposing your firm to risk that could be otherwise mitigated.
On one hand, open package sources make code easily available. On the other hand, these open package sources DO NOT and feasibly, CAN'T police submissions for malicious content. Who should be policing packages? The answer is simple: YOU! If you bring a package into your organization, it's your responsibility to verify not only the package's contents, but the contents of every other package that the downloaded package depends upon.
Managing dependencies is another nice feature that a package manager provides. If you're thinking that bringing a malicious package into your organization is like unleashing a virulent virus, you're getting the point.
The fact is, no production application or build process should ever take a direct dependency on any public package source. Setting aside malicious actors, there are many innocuous reasons to not trust public package sources:
- You're leaving everything up to the package owner to manage versions and dependencies. What if the package owner introduces a dependency that makes the package work, but is completely incompatible with your application?
- What if the package owner uploads a new package version that works, but nevertheless introduces a bug into your application? If you set your build process up to automatically upgrade your packages, you've now introduced what might be a costly bug that you'll need to spend real money fixing.
Companies should build and manage their own packages and the dependencies thereon and create and use their own package source feeds. If you leverage a package from a public source, you should open the package and evaluate its contents, and add that package to your own source feed or add the contents to your own package.
Doesn't Package Signing Mitigate the Risk?
In a word, yes, but it's a qualified yes. Signing mitigates some risk, but not all risk. Signing wouldn't have prevented the Event Stream Incident. The only thing package signing does is validate the package author/contributor. Indeed, in most environments, you can limit which packages you can take to certain authors. If you have the public key, then only those packages signed with the author's certificate can be taken. However, that doesn't mean you just take any package from that author. What if the author's certificate was compromised? What if the author made an innocent mistake that ends up with your company sustaining some injury?
Now that you have a background on packages, package managers, and package sources, and the associated risks, let's apply that knowledge to NuGet.
NuGet at a Glance: Creating Your Own NuGet Source
As previously stated, this article is not a comprehensive how-to on NuGet. For that, consult the materials introduced at the beginning of this article. Just like packages, package managers, and package sources in general, NuGet follows the same approach. In Visual Studio, there is the NuGet Package Manager, illustrated in Figure 1.
If you leverage a Package from a public source, you should open the package, evaluate its contents, and add that package to your own source feed or add the contents to your own package.
Also illustrated in Figure 1 is the package source. Most likely, your active package source is NuGet.org. In my case, it's something labeled Local Package Source. Figure 2 illustrates what that is:
As you can see, the Local NuGet Source is just a directory on my development computer. This may be news: Setting up a NuGet Source is as simple as creating a directory! Figure 3 illustrates the NuGet Packages in the directory:
The Anatomy of a NuGet Package
A NuGet Package is just a zip archive with a different extension (.nupkg). Figure 4 illustrates how to open the contents.
Figure 5 illustrates the package contents. Let's examine what are arguably the most popular and widely used NuGet Packages: NewtonSoft.Json.
Referring to Figure 5, the items of interest are the lib folder and the signature, license, and nuspec
files:
- lib folder: This folder contains one or more subfolders that use a naming convention for each supported .NET version. You can learn more about targeting multiple .NET versions here: https://docs.microsoft.com/en-us/NuGet/create-packages/supporting-multiple-target-frameworks.
- .signature.p7s file: As the name implies, this is the signature file signed by the author's certificate. You can find more information on how to sign NuGet Packages here: https://docs.microsoft.com/en-us/NuGet/create-packages/sign-a-package. You can learn now to require that only signed packages be accessible and to limit packages to certain authors here: https://docs.microsoft.com/en-us/NuGet/consume-packages/installing-signed-packages.
- License.md: This is a markdown file that contains the license terms and conditions for your package. Typically, this consists of an open source license such as the MIT, GNU, or Apache 2.0 licenses.
- Nuspec: The
Nuspec
file is the manifest file. This is an XML file that is used to create the NuGet Package. This file will be discussed in the next section.
Creating Your Own NuGet Package
You now understand what Packages, Package Managers, and Package Sources are and have a basic understanding of how NuGet fits into that space. You also understand how to create and reference your own package source with nothing more than a directory of file share. All that's left to get started is to learn how to create your own NuGet Package. To illustrate, I'm going to use the Immutable Class Library I created and wrote about a few issues back (https://www.codemag.com/Article/1905041/Immutability-in-C#).
There are several approaches you can use to create NuGet Packages. I'm going to show you the method I consider the easiest to use and understand. There are also many options you can apply that I won't cover here. For comprehensive coverage of all you can do with package creation, consult the documentation at NuGet.org.
Step 1: Create a Package Directory Structure and Add Your Binaries
Figure 6 illustrates the directory structure.
I added an icon.png
file that will be displayed in the Package Manager, as shown in Figure 1. The license text file contains the MIT License Language. Finally, there's the nuspec
file, which is illustrated in Figure 7:
Step 2: Create Your Nuspec File
The nuspec
file illustrated in Figure 7 is very basic.
For a complete nuspec reference, you can find that information here: https://docs.microsoft.com/en-us/NuGet/reference/nuspec. The ID you choose for your package must be unique in the context of the source within which it's hosted. Accordingly, if you elect to make your NuGet Package available in the NuGet.org feed, the ID must be unique in that universe. Figure 8 illustrates how the package appears in the NuGet Package Manager:
Step 3: Create Your NuGet Package
In order to create your NuGet Package from the command line, you need the NuGet Command Line Tools. Figure 9 illustrates where you can download NuGet.exe.
Figure 10 illustrates how to generate your NuGet Package:
Step 4: Publish Your Package
Depending on the type of package source you are using, your steps may be slightly different. For a file directory source, the process is as simple as copying the file to the directory. If you're hosting your own NuGet Server (https://docs.microsoft.com/en-us/NuGet/hosting-packages/NuGet-server), you will use one of the methods described here: https://docs.microsoft.com/en-us/NuGet/NuGet-org/publish-a-package.
Other Hosting Options
Instead of self-hosting or using the NuGet.org public feed, you may instead elect to use a third-party service. For NuGet, there are paid services such as myget (myget.org) and chocolatey (chocolatey.org). If it's so easy to host your own feed, why would you consider a paid service? These paid services have their own DR (Disaster Recovery) infrastructure. If you host your own feed, you need to consider how your server will be backed-up and replicated and how you will recover in the event of a catastrophic event.
Conclusion
Open source has made it easier than ever to add features to your applications. Part of that ease is speed. Speed and ease mean less friction. Once upon a time, before open source as we know it today, before the Internet, and before package management, there was implicit friction in the system, which provided time to assess and evaluate. Developers of another generation, in my opinion, had a better understanding of change management. They understood the discipline and rigor required to mitigate risk. For all the benefits of today's technology and the speed and ease we get with it, it's more important than ever to employ risk mitigation techniques such as what is discussed in this article because if it's easier for us to do good things, it's easier for bad actors to use the same technology. Robust security and risk mitigation aren't free. If there's one negative side-effect of free open source, it's the expectation that things heretofore with a cost no longer have a cost. Consider that the next time a package is introduced into your environment. If your organization is governed by SOX, HIPAA, FINRA, PCI, etc. - if you're compliant, you're not letting that situation occur.