Skip to main content
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: Jeff Coughlin
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: Jeff Coughlin

Optional Password Protection Added To Incident Commander

By
Published in Comments (3)

Now that I've rebuilt my Incident Commander triage app in ColdFusion, I've been trying to incrementally improve it. First I added the ability to use markdown in the incident description and status updates; then I added the ability to upload supporting screenshots; and now, I've added the ability to include an optional password to satisfy particularly security-minded teams.

Run this app at www.incident-commander.com.

View this code in my Incident Commander project on GitHub.

Considering Risk Appetite In Security

There is no "one way" to do security in a ColdFusion web application. All security is a collection of trade-offs that balance the strength of the security against the user experience (UX). The better the security, the worse the user experience; the better the user experience, the weaker the security.

The goal is to find a compromise that feels commensurate with the sensitivity of the data being stored. In the case of incident triage, the data is sensitive; but not that sensitive. Yes, it may deal with the proprietary information about software architectures and system landscapes; and, it may contain screenshots of internal logs and metrics graphs; but, it's unlikely to contain information about credit cards or personally identifiable information (PII) about the users.

It's important to remember the context in which incident triage is being performed. Things are on fire! Users are freaking out! Systems are down! Engineers may be getting paged in the middle of the night! People are in panic mode; and will almost certainly be operating in a degraded state.

Because of this fraught context, I needed there to be no barrier to entry when starting an incident. No mucking around with Single Sign-On (SSO) workflows. No having to create accounts ahead of time. No connecting to VPNs (Virtual Private Networks). No waiting for magic passwordless email links to arrive. No futzing with Two-Factor Authentication (2FA) tokens.

When an incident needs to be opened, the incident commander (IC) needs to be able to open the site, quickly initiate the incident triage session, and get to work!

The Baseline Security of an Incident

When the incident commander opens an incident triage session, a new incident record is created in the database. This record has two core parts:

  1. The id, which is an auto-incrementing BigInt.

  2. The slug, which is a randomly generated, 64 byte alpha-numeric string.

When you access an incident in the browser, both the id and the slug need to be provided in the URL (which is done using a single compound "token"). The id is used for the database look-up; and then, the slug is used to provide security against the brute-force guessing of incident IDs.

Aside: In theory, I could have only required the slug to be provided in the URL. But then, I'd have to index the slug column; and either define it using a case-sensitive collation or author the SQL query to use a case-sensitive text comparison. Since I already had an index on the id (the primary key), it seemed simpler to just pull the record back based on the id and then use the compare() function on the ColdFusion side for a case-sensitive comparison.

The slug is 64 characters long and is built using an alphabet that contains 62 possibilities (a-zA-Z0-9). Which makes the "key space" for the slug astronomically large at 62^64 possible combinations. Adding on top of that the fact that I have rate-limiting in the application layer and the slug alone is enough to make a brute-force attack virtually impossible.

The incident commander should feel confident that when they start an incident triage session, they are immediately dropped into a safe and secure context.

A Non-URL Authentication Mechanism

That said, having nothing but a URL-based authentication mechanism will raise some eyebrows for teams that are obsessively security-minded. While the slug is very strong, it is—as I mentioned above—ultimately a set of trade-offs. The ease-of-use does come with some disadvantages:

  • A URL-based security token will show up in the browser's history API.

  • A URL-based security token can show up in Http-Referer logging for any links that link from the incident triage content.

    Aside: In the incident commander app, I'm using JSoup to enforce noopener and noreferrer directives on all anchor links to help prevent any Http-Referer logging. As such, that should be less of a concern for people using modern browsers.

  • A URL-based security token will be logged in much of the network infrastructure that routes the request from the user's browser to the ColdFusion server.

  • A URL-based security token will likely be logged in any error tracking, both on the client-side and on the server-side.

  • A URL-based security token could accidentally show up in a URL or screenshot that is shared publicly.

  • A URL-based security token may not have a manual rotation mechanism to help remediate any accidental information leakage.

None of this makes the URL-based authentication mechanism a "bad" or "weak" option—it only means that is has both advantages and disadvantages when used in isolation.

For teams that want an additional layer of security to hedge against the aforementioned trade-offs, I've added an optional password feature. Once an incident triage session has been started, the incident commander can go into the "Password" section and set the password:

When the password is set, it's stored in an encrypted state using AES/CBC encryption with a 256-bit secret key. If a user goes to access an incident that is password protected, they are redirected to an authorization form where they must enter this password:

Upon successful entry of the correct password (a workflow that is, itself, rate-limited), I set an authorization cookie that is signed using ColdFusion's hmac() function with the HmacSHA256 algorithm and a 512-bit secret key. The cookie contains nothing but a manifest of id values that the user can access. Each id entry in this manifest is valid for 24-hours (after which the password will need to be re-entered).

This cookie is defined using the HttpOnly and Secure flags which prevent them from being accessed via JavaScript or transmitted over a non-SSL/TLS connection, respectively. As such, the chances that the cookie value is logged or intercepted are vastly reduced when compared to the core URL-based slug authorization.

On top of that, the cookie itself is set to expire in 7-days. And, uses a SameSite="strict" policy to help prevent cross-site request forgery (CSRF) attacks.

When the incident commander sets a password for the triage session, the Slack-ready message is updated to include the password in the copy-paste text:

Screenshot of Slack showing that the password is included in the copy-paste ready message.

For people who are concerned with "Security Theater", rendering the password in plain-text will certainly ruffle a few feathers. Generally speaking, this is something you want to avoid.

But, you must remember that security is a set of trade-offs, not a set of absolutes. The primary goal of the Incident Commander application is to make it easier for teams to communicate during incident triage. In order to make it easier for everyone on the team to participate in a way that adds the most value, the password must be something that is accessible. If the password were only known to the IC, the IC becomes the limiting factor and a bottleneck in the flow of information.

The password isn't there to prevent your team from accessing the incident details; the password is there to prevent malicious actors from accessing the incident. The password is there to minimize the risk of information leakage, not to eliminate it. Again, security is a set of trade-offs, balancing user ergonomics and risk appetite.

When faced with an outage—especially one in the middle of the night—the last thing you want to do is deal with complex authentication schemes, VPNs, or other draconian security measures. You need to be able to open an incident triage session and start investigating root cause problems immediately. As such, I've tried to design the Incident Commander application experience to have no barriers to entry. That said, for those of you that want a little extra security peace-of-mind, I'm hoping that the optional password protection will do the trick.

Reader Comments

26 Comments

@Ben,

From what I understand, UUID V7 was created specifically to address the use case for unique non-incrementable values while also being indexable. Currently traveling and don't have a good link to share discussing more about it.

Not sure if there is a ColdFusion implementation of it yet, but I'm aware of a built-in .NET 9 version (very recently released).

15,912 Comments

@Danilo,

I don't think there is a ColdFusion native way of doing it; but, there's got to be a JAR file somewhere that we could pull in. When it gets down into the weeds of storing a UUID in the database; I don't have the muscle memory for it. But, I'm pretty sure that a UUID can be stored in some databases as a native binary datatype (ie, not a 36-character string), which can be indexed and accessed quickly.

To that end, there could have been a way for me to have just the slug (as a UUID) and not worried about concatenating it with the id. I just have a better sense of how a BigInt will perform.

15,912 Comments

So, I'm just watching some of the Mastering Postgres video course by Aaron Francis, and in the section on primary keys, he mentions the UUID v7. Apparently it can be stored as 16-bytes and the first part of the UUID is a timestamp, so it's still increasing (which is great for insertion ordering and speed).

Post A Comment — I'd Love To Hear From You!

Post a Comment

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel