Parameters
The data sent with incoming request is known as parameters. The parameters in Rails can be found in the params
hash
and include:
- Path Parameters: Embedded in the URL, e.g.,
/posts/:id
. - Query String Parameters: Added to the URL, e.g.,
/posts?title=rails
. - Form Data: Submitted via forms using
POST
requests. - JSON Data: In APIs where the request body contains JSON.
Unlike a plain Ruby hash, the params
hash is an ActionController::Parameters
object which treats symbols (e.g., :key
)
and strings (e.g., "key"
) as equivalent keys.
Strong Parameters
Strong parameters allow us to explicitly permit and require specific attributes in the controller, preventing mass assignment vulnerabilities.
We can manually filter parameters:
class PostsController < ApplicationController
def create
@post = Post.create(
title: params[:title],
content: params[:content]
)
end
end
Testcase: params = { title: "Welcome to Rails", content: "Deep dive into rails...", published: true }
Output: { title: "Welcome to Rails", content: "Deep dive into rails..." }
Simplified with Strong Parameters
The ActionController::Parameters
object provides predefined methods like require, permit
and expect, simplifying parameter handling.
Also, we had this strong_parameters gem that we could use in rails 3 projects.
class PostsController < ApplicationController
def create
@post = Post.create(post_params)
end
def post_params
params.permit(:title, :content)
end
end
This eliminates manual filtering while ensuring secure and concise code.
Why strong parameters
By default, Rails allows all parameters to be passed to the controller, which can create security vulnerabilities. Strong parameters help us to prevent mass assignment vulnerabilities.
Let us Imagine we have a post
with attributes like title
, content
,
and published
(where published indicates whether the post is visible to the public).
Without Strong Parameters
Without whitelisting, creating a post with user-provided params can compromise data if unauthorized fields are included.
{
"post": {
"title": "Welcome to Rails",
"content": "Deep dive into rails...",
"published": true
}
}
@post = Post.create!(params[:post])
INSERT INTO "posts" ("title", "content", "published", "created_at", "updated_at")
VALUES ('Welcome to Rails', 'Deep dive into rails...', TRUE, '2025-02-18 12:34:56.789', '2025-02-18 12:34:56.789');
In this case, the post is made publicly visible even if the user does not have permission to publish it, as only an admin is allowed to publish posts. The published: true
field is altered without authorization, leading to a potential security issue.
With Strong Parameters
We have to explicitly define which attributes are allowed to be assigned, ensuring unauthorized fields (like published) cannot be set by the user.
@post = Post.create!(post_params)
def post_params
params.require(:post).permit(:title, :content)
end
Even if the attacker sends this malicious request:
{
"post": {
"title": "Welcome to Rails",
"content": "Deep dive into rails...",
"published": true
}
}
The post_params
method ensures only title
and content
are permitted, while the published
field is ignored unless explicitly whitelisted, thus preventing unauthorized publishing of the post.
INSERT INTO "posts" ("title", "content", "created_at", "updated_at")
VALUES ('Welcome to Rails', 'Deep dive into rails...', '2025-02-18 12:34:56.789', '2025-02-18 12:34:56.789');
The importance of protecting against mass assignment vulnerabilities was highlighted in 2012 when GitHub suspended a member over a ‘mass-assignment’ hack exploited by Homakov, demonstrating how critical this safeguard is for application security.
How Strong Parameters Work
When a user sends a request (e.g., via a form or API):
{
"post": {
"title": "Welcome to Rails",
"content": "Deep dive into rails...",
"published": true
}
}
We can define allowed parameters in the controller:
def post_params
params.require(:post).permit(:title, :content)
end
- The
require
ensures the presence of a specific key (e.g., :post). - The
permit
whitelists attributes (e.g., :title, :content).
Use post_params
in actions to filter parameters before passing them to the model:
@post = Post.create!(post_params) # Only :title and :content are assigned
Any unpermitted fields, like published
, will be ignored, even if included in the request.
The params#expect method, which was introduced in Rails 8 for better parameter processing, enables filtering by expected types to avoid errors caused by tampering or invalid input:
params.expect(post: [ :title, :content])
For reliable, type-safe parameter processing in Rails 8 and later, the expect
method is advised.
Conclusion
Strong parameters are a crucial feature in Rails, as they significantly enhance application security by offering protection against issues with mass assignment.
By explicitly whitelisting permitted parameters for each controller action, developers can prevent unauthorized modifications.
Strong parameters are also simple to construct, guaranteeing safe input handling while preserving the simplicity and clarity of the code.