When developing web applications, it’s common to expose database IDs in URLs, such as example.com/posts/123. While this is convenient, it has potential drawbacks. Sequential IDs can reveal information about your database, like the number of records or the order in which they were created. To address this, developers often look for ways to obfuscate these IDs while keeping them reversible for internal use. This is where SQIDs come into play.
What is Sqids?
Sqids is a library designed to generate short, non-sequential, and URL-friendly IDs from integers. Unlike UUIDs, which are long and not user-friendly, Sqids provide a compact alternative that can be used in URLs to hide the real database IDs. They’re particularly useful in scenarios where you want to obfuscate your IDs without modifying your database schema or introducing significant overhead.
Why Not Use UUID?
UUIDs (Universally Unique Identifiers) are often used as an alternative to numeric IDs for their uniqueness across distributed systems. However, UUIDs have a few drawbacks:
- Length: UUIDs are typically 36 characters long, which can make URLs cumbersome.
- Not Sequential: While they are unique, UUIDs are not sequential, making indexing in databases less efficient.
On the other hand, Sqids offer a balance between security, URL friendliness, and reversibility, making them an ideal choice for many applications.
Implementing Sqids in Rails
Here’s how you can implement Sqids in a Rails application using a concern. This approach ensures that you don’t have to modify your database schema, and you can easily integrate it with your existing models.
Step 1: Install the Sqids Gem
First, add the Sqids Ruby gem to your Gemfile:
gem 'sqids'
Run bundle install
to install the gem.
Step 2: Create a Concern for Sqids
Next, create a concern to encapsulate the logic for encoding and decoding Sqids:
# app/models/concerns/sqids_encodable.rb
module SqidsEncodable
extend ActiveSupport::Concern
# arguments here are optional ; you can change the alphabet to change the encoding sequence
SQIDS = Sqids.new(alphabet: 'k3G7QAe51FCsPW92uEOyq4Bg6Sp8YzVTmnU0liwDdHXLajZrfxNhobJIRcMvKt', min_length: 8)
def to_param
sqid
end
def sqid
SQIDS.encode([id])
end
class_methods do
def find_by_sqid(sqid)
find(SQIDS.decode(sqid).first)
end
end
end
This concern does a few key things:
-
to_param
method: Overrides the default to_param method to return the SQID instead of the numeric ID. This ensures that Rails uses the SQID in URLs. -
sqid
method: Encodes the model’s ID using Sqids. -
find_by_sqid
method: Allows you to find a record by its SQID, decoding it back to the original ID.
Step 3: Use the Concern in Your Models
To use this in a model, include the SqidsEncodable concern:
# app/models/post.rb
class Post < ApplicationRecord
include SqidsEncodable
# Your model logic here
end
With this setup, whenever you generate a URL for a Post, Rails will automatically use the SQID instead of the numeric ID.
Step 4: Use Sqids in Your Controllers
When querying for a record, use find_by_sqid:
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def set_post
@post = Post.find_by_sqid(params[:id])
end
# Other controller actions
end
This ensures that Rails can correctly retrieve the record using the obfuscated ID.
Conclusion
We went from example.com/posts/123
to something like example.com/posts/5sQ1BZoD
.
Sqids offer a practical solution for obfuscating database IDs in a Rails application. They allow you to hide the actual IDs from users, while still being able to reverse the process internally. Compared to UUIDs, SQIDs provide a more user-friendly, compact, and efficient approach.
It’s important to note that while Sqids obfuscate the IDs, they do not encrypt them. If you require encryption for your IDs, you’ll need to look into more robust security measures. However, for most applications, SQIDs strike a good balance between security and usability.
Learn more about Insecure Direct Object Reference
Learn more about Sqids | GitHub repository
Top comments (0)