TIL: Best Practices for Handling Secret Keys in Sinatra - The Do's and Don'ts
Thierry Chau
Posted on July 28, 2023
Introduction
As developers, we often find ourselves dealing with sensitive information like API keys. Sinatra, a lightweight Ruby web framework, offers an excellent platform for creating robust applications. However, when it comes to managing secret keys, it's essential to follow best practices to ensure the security and integrity of our applications.
In this TIL post, we will explore the insights I gained about secret keys in Sinatra. We'll delve into the dos and don'ts of handling sensitive information, the importance of using environment variables, and the risks associated with exposing secret keys.
I asked dezgo to generate an illustration for this blog post.
1. 1. What is an API?
From Wikipedia:
An API (Application Programming Interface) is a way for two or more computer programs to communicate with each other. It is a type of software interface, offering a service to other pieces of software.
For example, Google Maps has an API which allows us developers retrieve information they have gathered about the location of our choice. A URL request looks like this:
maps_url = "https://maps.googleapis.com/maps/api/geocode/json?address=INPUT_LOCATION&key=#YOUR_API_KEY"
Pirate Weather is another API. Together with Google Maps, we were able to develop an application which asks the user for a location, and provides coordinates, temperature, and a suggestion of whether or not to bring an umbrella!
umbrella main % ruby umbrella.rb
Will you need an umbrella today?
Enter your location:
Chicago, IL
Checking the weather at Chicago, IL...
"Your coordinates are 41.8781136, -87.6297982."
It is currently 73°F (23°C)
Clear for the next hour.
Hours from now vs Precipitation probability
65| *
60| * *
55| * *
50| * *
45| * * *
40| * * *
35| * * *
30| * * * *
25| * * * *
20| * * * * *
15| * * * * * *
10| * * * * * * *
5| * * * * * * *
0+------------------------------------
1 2 3 4 5 6 7 8 9 10 11 12
You might want to take an umbrella!
One of the most famous API currently is probably Open AI, which allows developers to use and tweak the power of Chat GPT for custom applications. One example of this is an AI powered TA that is customized to provide software development specific answers (and more specifically in Ruby).
1. 2. What are these API Keys?
APIs are used to enable controlled access to a service or application's functionality and data. To regulate access and ensure security, APIs often require authentication or authorization. This is where API keys come into play.
An API key is a unique identifier issued to developers or applications that want to access an API. It acts as a secret token that grants permission to interact with the API and access its features or data. The API key is typically included in the request headers or parameters when making API calls.
More importantly, these API services are usually not provided for free. API keys is a way to track usage, and bill accordingly. For this reason, developers need to carefully handle their API keys and not let other people have access to it.
2. Understanding Secret Keys and Environment Variables
Environment variables allow us to do just that. These variables are read using the ENV.fetch()
method, which retrieves the value of the environment variable based on its name.
The beauty of using environment variables is that they remain stored on the server where the application runs, making them inaccessible to users visiting the website. As long as we do not display, send, or log these variables inappropriately, they stay securely hidden from prying eyes.
3. 1. Caution with Development Gems
Even when correctly stored as environment variables, secret keys can be exposed with the use of development gems, such as better_errors (which provide enhanced error pages during development). While these gems are beneficial during development, they should not be used in production environments due to their potential to expose sensitive information during errors.
3. 2. Gemfile good practices
One way to avoid this is by separating gems by environment with the group :environment syntax. This is important as it ensures that certain gems are only loaded in the appropriate environments. A Gemfile could look like this:
gem "sinatra"
gem "sinatra-contrib"
gem "http"
group :development do
#gem "better_errors"
gem "binding_of_caller"
end
group :development, :test do
gem "pry"
end
When deploying to production, it’s crucial to set the RACK_ENV or RAILS_ENV environment variable to production. This will ensure that only the necessary gems for that environment are loaded.
As a rule of thumb, any gem that provides debugging or testing capabilities should not be used in your production environment.
We can set this RACK_ENV
directly in the command line when starting your server. For example:
RACK_ENV=production ruby app.rb
Conclusion
By using environment variables to store sensitive information, we ensure that these keys remain inaccessible to users visiting our websites.
Development gems used in production environments can result the accidental exposure of sensitive information. A properly set Gemfile can help avoid that.
By following these best practices, we can build secure and reliable Sinatra applications, protecting our users' data and maintaining the integrity of our code. Happy coding!
Posted on July 28, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.