
02.11.2025
Rails CSRF Protection: Best Practices Checklist

Dariusz Michalski
CEO
Implementing CSRF protection in Rails is essential for safeguarding user data. Follow best practices to secure your web applications from attacks.
Protecting your Rails app from CSRF attacks is crucial to safeguarding user data and maintaining trust. CSRF, or Cross-Site Request Forgery, exploits user sessions to perform unwanted actions without their consent. Rails offers built-in CSRF protection, but proper implementation and regular reviews are key to ensuring your app stays secure.
Here’s a quick overview of the best practices:
Enable
protect_from_forgeryinApplicationControllerto verify authenticity tokens for non-GET requests.Use Rails form helpers like
form_withto include CSRF tokens automatically.Avoid GET requests for state-changing actions to prevent exploitation.
Review and limit
skip_forgery_protectionusage to specific, justified cases like API endpoints.Include
csrf_meta_tagsin your layout for secure AJAX and JavaScript interactions.Secure cookies with attributes like
SameSite,Secure, andHttpOnly.Prevent XSS vulnerabilities to protect CSRF tokens from exposure.
For API-only setups or JavaScript-heavy applications, you may need to adjust your CSRF strategy, such as disabling it for stateless endpoints or manually handling tokens in AJAX requests.
Final Tip: Regularly audit your app for potential risks, and ensure all team members are trained on secure coding practices. These steps will help you maintain a safer environment for your users and comply with local data protection laws.
Rails Cross-Site Request Forgery (CSRF)

Setting Up CSRF Protection in Rails
Rails comes with built-in CSRF (Cross-Site Request Forgery) protection, but you can further customise its configuration to enhance security. This protection relies on three key components.
Using protect_from_forgery in ApplicationController
The ApplicationController acts as the backbone for enabling CSRF protection across your Rails app. With just one line of code, you can extend this protection to every controller that inherits from it.
Here’s how you can set it up:
This command ensures that Rails verifies authenticity tokens for all non-GET requests. By placing it in the ApplicationController, all other controllers automatically inherit this security measure.
If your application combines a web interface with API endpoints, you might need to tweak this setup for certain controllers while keeping it as the default behaviour for others.
You can also define how your app should respond to CSRF verification failures.
Configuration Options for CSRF Protection
Rails provides three different ways to handle CSRF token verification failures, tailored to varying security needs and application scenarios.
Configuration Option | Behaviour | Best Use Case |
|---|---|---|
| Throws | Ideal for standard web apps prioritising strict security |
| Returns an empty session without resetting it entirely | Suitable for APIs with mixed authentication methods |
| Completely clears the session | Best for apps demanding maximum session security |
The :exception option is the go-to choice for most traditional web applications. It halts any malicious request by raising an exception, ensuring that the attack is logged and can be monitored.
The :null_session option is a middle-ground solution for apps that serve both web pages and API endpoints. Instead of blocking the request outright, it provides an empty session, neutralising the attack without causing disruptive errors.
The :reset_session option takes a more aggressive approach by wiping the user’s session entirely when a CSRF verification fails. While this guarantees that no compromised session data remains, it forces users to log in again, which might disrupt their experience.
For Swiss businesses collaborating with USEO’s development teams, the choice of strategy often hinges on your app’s specific needs. The :exception option works well for most web apps, while :null_session is better suited for apps with more complex authentication requirements.
The next step in securing your app is to include CSRF tokens in your layout for JavaScript requests.
Adding Tokens with csrf_meta_tags
To protect AJAX and JavaScript-driven interactions, your layout must include CSRF tokens. The csrf_meta_tags helper bridges the gap between Rails' server-side token generation and client-side JavaScript requests. Adding this helper to your main layout ensures that CSRF tokens are available throughout your app.
Insert the following line into the <head> section of your app/views/layouts/application.html.erb file:
This helper generates two key meta tags in your HTML:
These meta tags are essential. Forms created with Rails helpers like form_with automatically include the CSRF token as a hidden field. However, JavaScript-driven requests need to extract the token from these meta tags to ensure secure API calls.
Without csrf_meta_tags, your JavaScript requests won’t have the necessary token, making them vulnerable to CSRF attacks or causing them to be rejected by Rails' security mechanisms. This is especially critical for single-page applications or sites with heavy JavaScript usage.
CSRF Protection Best Practices Checklist
Securing your Rails app against CSRF attacks requires a structured approach. By following these practices, you can strengthen your app's defences and make the most of Rails' built-in protections.
Use Rails Form Helpers
Rails' form helpers, like form_with or form_for, automatically include CSRF tokens to ensure secure form submissions.
This example generates a form with an invisible authenticity token field, which Rails manages for you.
Avoid creating forms manually using plain HTML for state-changing actions. Manually built forms skip Rails' token insertion, leaving you vulnerable to CSRF attacks. If you must use custom forms, make sure to include the following manually:
Avoid Using GET for State-Changing Actions
GET requests don't trigger CSRF checks, so they should never be used for actions that modify data. Always use POST, PUT, PATCH, or DELETE for these operations.
For example, a GET-based action like <a href="/users/123/delete">Click here</a> could delete a user account if the delete action is improperly configured to use GET. This makes your app susceptible to attacks through deceptive links or image loads.
HTTP Method | Purpose | CSRF Protection | Example Use |
|---|---|---|---|
GET | Data retrieval | None | Viewing profiles, listing items |
POST | Creating resources | Full protection | User registration, new posts |
PUT/PATCH | Updating resources | Full protection | Editing profiles, updating data |
DELETE | Removing resources | Full protection | Deleting accounts, removing posts |
Review skip_forgery_protection Usage
The skip_forgery_protection method disables CSRF verification for specific actions or controllers. Misusing this method can expose your app to unnecessary risks, so it's important to audit its use.
Search your codebase for skip_forgery_protection or skip_before_action :verify_authenticity_token and document the reasoning behind each use. Legitimate cases might include:
API-only controllers using token-based authentication
Webhook endpoints from trusted sources
Public endpoints that don't handle sensitive data
If these exceptions are no longer needed or alternative security measures have been implemented, restore CSRF protection immediately. Regularly reviewing and removing unnecessary exceptions is a critical part of maintaining app security.
Set Secure Cookies with SameSite Attribute
The SameSite attribute on cookies prevents them from being sent with cross-site requests, reducing the risk of CSRF attacks. Configuring this in your Rails app is straightforward:
Using :lax ensures most cross-origin requests are blocked while maintaining usability for legitimate navigation, such as when users click links from other sites. For maximum security, you can use same_site: :strict, but be aware that it might disrupt user experience when navigating from external sources.
This approach is particularly relevant for Swiss businesses collaborating with USEO's development teams, as it enhances security with minimal code changes.
Fix XSS Vulnerabilities
Cross-site scripting (XSS) vulnerabilities can undermine your CSRF defences. Malicious scripts injected into your app can access CSRF tokens from hidden fields or meta tags, allowing attackers to forge legitimate-looking requests.
To prevent XSS attacks:
Sanitise user input to remove harmful scripts.
Escape HTML output to avoid rendering injected code.
Implement Content Security Policy (CSP) headers to restrict the execution of untrusted scripts.
Rails helps with automatic HTML escaping in ERB templates, but you should still be cautious with user-generated content and dynamic HTML rendering. Regularly scan your codebase for potential XSS risks, particularly in areas like:
Search functionality
Comment sections
Features that render user-provided HTML or markdown
Since XSS can compromise CSRF tokens, addressing both vulnerabilities together is essential. A single XSS issue can render your CSRF protections useless, so comprehensive security testing is non-negotiable.
Advanced CSRF Protection Scenarios
Modern Rails applications often require customised CSRF protection strategies, especially for API-only setups and JavaScript-heavy interfaces. These approaches need to account for how traditional CSRF mechanisms fit into contemporary development practices.
CSRF Protection in API-Only Applications
For API-only applications that rely on stateless authentication methods like API tokens, JWT, or OAuth, CSRF protection is typically unnecessary. Since browsers no longer automatically send cookies with these requests, the traditional CSRF risk is significantly reduced. In fact, enabling CSRF protection in such cases can cause issues.
To disable CSRF protection in API-only controllers, you can skip the protect_from_forgery method like this:
If your application is a hybrid, serving both web pages and API endpoints, you should maintain CSRF protection for web controllers while disabling it for API controllers. The critical requirement here is to ensure robust authentication for API endpoints. This means validating API tokens on every request and implementing strict authorisation checks to safeguard your application.
Protecting AJAX Requests
AJAX requests, especially in JavaScript-heavy applications and Single Page Applications (SPAs), require a different approach to CSRF protection. Unlike traditional form submissions, AJAX requests don’t automatically include CSRF tokens, so you’ll need to handle this manually.
The simplest way to do this is by reading the CSRF token from the meta tags that Rails generates and attaching it to the X-CSRF-Token header for any state-changing requests:
For applications using modern JavaScript frameworks like React or Vue, the cookie-to-header pattern offers a more streamlined approach. Here, the server sets a CSRF token in a cookie, which the client reads and includes in a custom header for each request. The Rails backend then validates the token from the header against the one in the cookie.
While Angular handles this pattern out of the box, React and Vue require manual implementation or the use of helper libraries like axios interceptors to manage token handling efficiently.
When working with AJAX requests, always include the credentials: 'same-origin' option in your requests to ensure cookies are sent, allowing Rails to properly verify the CSRF token.
Preventing Token Exposure
Exposing CSRF tokens can compromise your entire security setup, so careful handling is essential. Never include CSRF tokens in URLs. Tokens in URLs can be exposed through browser history, referrer headers, server logs, or shared links, making them vulnerable.
Instead, tokens should only be transmitted through secure channels like HTTP headers, hidden form fields, or cookies. If using cookies to store CSRF tokens, configure them with the right security attributes:
Avoid logging headers that contain CSRF tokens, and take extra care when integrating with third-party services. Webhook endpoints and external API integrations should rely on separate authentication mechanisms rather than CSRF tokens, which could accidentally be exposed via referrer headers or redirect chains.
Regular audits of token storage and transmission are crucial. Check that tokens are not stored in localStorage or sessionStorage, ensure they are not cached by browsers, and verify that they don’t appear in debugging output or error messages that might be visible to users.
Summary and Final Checklist
Key Takeaways
Rails' built-in CSRF protection requires a consistent and layered approach to be effective. While the protect_from_forgery method offers strong safeguards, its success hinges on proper implementation and uniform application across your entire codebase.
Consistency is key - whether you're securing forms, handling AJAX requests, or reviewing API endpoints. Even a single oversight, like a GET request altering application state or a form bypassing Rails' helpers, can compromise your app's security. This is especially critical for Swiss businesses managing sensitive financial or personal information, where regulatory compliance and user trust are non-negotiable.
Modern Rails applications often include JavaScript-heavy interfaces and APIs, which demand tailored CSRF strategies. For API-only controllers, you must carefully evaluate whether CSRF protection adds value or creates unnecessary complications.
Lastly, strengthening cookie security with SameSite and Secure attributes complements Rails' token-based defences, adding an extra layer of protection.
Use the checklist below to confirm your CSRF protection strategy is comprehensive.
Final CSRF Protection Checklist
This checklist summarises the key practices discussed earlier.
Foundation Setup
Ensure
protect_from_forgeryis enabled inApplicationControllerwith a suitable strategy.Confirm the presence of
csrf_meta_tagsin your application layout.Test that CSRF tokens are being correctly generated and validated.
Form and Request Security
Always use Rails form helpers like
form_withorform_forfor forms that modify application state.Identify and convert any GET requests that alter data into POST, PUT, PATCH, or DELETE requests.
Review all instances of
skip_forgery_protection, ensuring it’s limited to stateless API endpoints.
Cookie and Session Configuration
Configure session cookies with SameSite, Secure, and HttpOnly attributes.
Double-check that cookie settings are properly implemented in your production environment.
JavaScript and AJAX Protection
Verify that all AJAX requests include the CSRF token in the
X-CSRF-Tokenheader.Handle tokens correctly in single-page applications.
Test JavaScript frameworks to ensure they follow the cookie-to-header token pattern.
Security Validation
Scan your application for XSS vulnerabilities that could expose CSRF tokens.
Confirm that CSRF tokens never appear in URLs, logs, or referrer headers.
Regularly use automated tools to audit your code for potential weaknesses.
Team and Process
Train your developers on secure coding practices.
Incorporate CSRF protection checks into your code review process.
Document any exceptions or specific cases where CSRF protection is intentionally disabled.
Revisit this checklist regularly, especially when introducing new features or updating dependencies, to ensure your application remains secure.
FAQs
What are the best practices for implementing CSRF protection in a Rails application with both web pages and API endpoints?
To keep your Ruby on Rails application safe from CSRF attacks, especially when managing both web pages and API endpoints, here are some important steps to follow:
Turn on CSRF protection by default. Rails has built-in CSRF protection, and it’s best to keep it enabled unless there’s a compelling reason to turn it off.
For web pages, make use of the
csrf_meta_tagshelper in your HTML templates. This ensures the CSRF token is included in your forms and AJAX requests, providing an extra layer of security.For API endpoints, it’s better to use token-based authentication methods like OAuth or API keys rather than relying on cookies. If cookies must be used, make sure CSRF tokens are part of the API requests to prevent vulnerabilities.
Keep your Rails application up to date. Regular updates ensure you’re using the latest security patches and improvements, including those related to CSRF protection.
By following these steps, you can build a more secure application and minimise the risk of CSRF attacks.
What risks come with disabling CSRF protection for specific controllers, and how can they be addressed?
Disabling CSRF protection in a Ruby on Rails application can leave your app vulnerable to cross-site request forgery attacks. These attacks allow malicious actors to trick users into performing actions they never intended, potentially leading to unauthorised data changes, security issues, or even compromised user accounts.
If you need to disable CSRF protection, do so only when it's absolutely unavoidable. Restrict it to specific, controlled situations - such as APIs that rely on token-based authentication. To further reduce risks, make sure to validate incoming requests carefully, enforce strict access controls, and keep an eye on logs for any unusual activity. It's also essential to test your application thoroughly for vulnerabilities before rolling out any changes. Always prioritise security to protect your users and their data.
What is the SameSite attribute in cookies, and how does it help protect against CSRF attacks?
The SameSite attribute in cookies is a security feature that determines whether a cookie is included with cross-site requests. By setting this attribute to either Strict or Lax, you can control cookie behaviour and minimise the risk of Cross-Site Request Forgery (CSRF) attacks.
Strict: Cookies are only sent with requests that come from the same site. This provides the highest level of security but might interfere with certain functionalities, especially for multi-site workflows.
Lax: Cookies are sent with top-level navigations and safe HTTP methods. This setting strikes a balance between security and usability, making it a practical choice for many applications.
When implementing the SameSite attribute, it's important to check how it interacts with different browsers your users may use. Testing is crucial to ensure it doesn’t disrupt your application's functionality, particularly for third-party integrations.


