While writing a gem today to manage creating encrypted JWTs (JWE) with managed encryption keys and secure-by-default options, I was contemplating different ways of managing loading keys. Because I personally store my keys in application.credentials, my brain immediately jumped to importing through credentials by a preset default prefix key. When I was about to implement the function I wanted to use to do so, I immediately realized just how much access is available to credentials once loaded. I could get access to anyone’s credentials simply by checking that Rails is defined in the gem from anywhere with no security checks in place to restrict those credentials to application code.
What do we do to ensure credentials are ONLY accessed by code that we write?
You’re not wrong to be alarmed! The typical app depends on a lot of third-party code without diligent vetting. But there aren’t many ways, if any, around maintaining a high degree of trust in the third-party code you call. Any code running in the application process has full access to all of its memory—that’s a fundamental property of the operating systems we use, not something we can address in an application framework.
In short, securing application credentials means:
Dependency hygiene: only loading and running trusted third-party code in-app.
Running untrusted code at arm’s length in separate, least-privilege processes.
Limiting the blast radius of credential disclosure with single-purpose, least-privilege, preferably short-lived credentials.
Would love if Rails would block any of my credentials being accessible to any/all gems (rails engines, devise, etc.) or allowing a subset of credentials explicitly declared by my app in some sort of configuration.
Rails should be safe by default, I totally get Rails has a lot of sharp edges and I embrace it. However in this scenario I’m hoping we could perhaps look at ways to make the default behaviour a little cautious.
Limiting the blast radius of credential disclosure with single-purpose, least-privilege, preferably short-lived credentials.
Let’s say I add a new rails engine/ or a new gem, that gem can access Rails.application.credentails and can get access to more than I bargained for. Sure, the gem is badly designed but that’s a diff thing entirely.