Secure your apps! Protect sensitive data! Easy to say, harder to find solid answers on all the bits and pieces you need to adjust to make sure that happens. That's why we've put together this list of practical advice for securing your Ruby on Rails applications. Whether you're a Rails developer or work on any stack that relies on cloud technologies, we think you'll find something that stands out. The logic is straightforward: improve your rails appsec practices to improve your overall data security.
Use this in conjunction with the OWASP guidance on securing web applications to make sure your Rails apps are as secure as possible. Let's get to it!
Force all incoming communication to HTTPS
For all traffic to your application to be encrypted though SSL:
This helps avoid attacks like session hijacking. More importantly, unencrypted HTTP communication sends all requests as plain text, meaning anyone listening in can see all the traffic and extract user data. While you want to avoid sending sensitive data whenever possible, it's unavoidable so protecting the connection is an important method of improving your rails app's data security.
Force all outgoing communication to HTTPS
Make sure all your external HTTP calls are performed using HTTPS:
When using SMTP make sure to enable TLS connection
Sending email through SMTP protocol doesn’t necessary means it’s encrypted.
In Rails, to enable SSL encryption on SMTP traffic you need to explicitly enable it
Avoid transferring data through FTP
Do not use FTP protocol to transfer data, especially file containing sensitive data.
In Rails it means avoiding the Net::FTP class:
Instead, use the SFTP protocol:
Always verify SSL certificate validity
When using net-http, the default HTTP client in Ruby, by default SSL verification is on but sometimes developer turn it off for tests. Make sure this is not the case, avoid such code:
Make sure it’s also the case for your SMTP configuration:
Make sure database connection is secure from the client side
When setting-up rails database connection, always make sure that this connection is secure in production:
Or even better, now with Rails 7 you can also force check that the server hostname matches the name stored in the server certificate. If the server certificate cannot be verified, the SSL connection will fail:
Why does this matter? Aside from the best practice alone, unsecured database connections are an easy way to open yourself up to a data security breach—exposing sensitive user data to the world.
Do not send sensitive data through HTTP Get parameters
Never include sensitive data in GET parameters, use POST instead.
For example, if you’re using Ruby default Net:HTTP library, change this code:
Data-at-rest encryption prevents unauthorized users from making sense of your data if they gained access to your databases.
Enable encryption for all your database instances storing sensitive data. For instance, you should encrypt your Amazon RDS database instances.
Encrypt data at the application level
Application-layer encryption encrypts data based upon the application that owns it, rather than for the storage medium where the data is stored. Data encryption and decryption is performed at the end application, so someone with legitimate access to a particular user account does not have full access to all the data stored in that account.
Use the Active Record library to encrypt sensitive data at the application layer:
Do not use weak hash/encryption algorithms
According to OWASP, MD5, RC4, DES, Blowfish, SHA1. 1024-bit RSA or DSA, 160-bit ECDSA (elliptic curves), 80/112-bit 2TDEA (two key triple DES) are considered as weak hash/encryption algorithms and therefor shouldn’t be used.
Avoid using such libraries:
Logging & Monitoring
Add monitoring and logging to your application
Security logging and monitoring is the ninth item of the OWASP Top Ten. Security logging consists of logging security information during the runtime operation of an application.
Third-party monitoring solutions such as Datadog, New Relic, and Splunk provide these capabilities.
Avoid logging sensitive data
For example, do not log passwords, session ID, credit cards, or social security numbers like this:
Sanitize log for sensitive data
In case you still log sensitive data, without knowing about it, add sanitation rules to remove sensitive data from your logs.
Configure Rails to sanitize sensitive data in log files:
Third-party monitoring and tracking solutions like Datadog, New Relic, Splunk and Sentry provide capabilities to scrub sensitive information from your logs, but beware it needs to be configured appropriately.
Monitor third-party libraries and packages for security flaws (aka CVE)
Vulnerabilities are software coding flaws or system misconfigurations through which attackers can directly gain unauthorized and privileged access to a system or network. Appsec's role focuses on more than your internal code. You also need to keep tabs on any external vulnerabilities.
It is estimated that 60-90% of the total codebase of a software project relies on open source or other third party code. If this code contains vulnerabilities, you are exposed.
Use a vulnerability scanner such as GitHub Dependabot, GitLab dependency scanner or Snyk to automate vulnerability testing across your dependencies. You can also use a tool like bundler-audit to further assess gem versions.
Monitor third-party integrations
Third-party data breaches happen when you share sensitive data with vendors with weak security standards. Make sure you have a process that cannot be bypassed to review new integrations with external services.
For each vendor, document:
- The data you share with them (based on your data taxonomy).
- Their processing location.
- Their security standards and certifications (e.g., SOC2, ISO 27001).
Legal documentation such as contractual agreements, Service-Level Agreements, and Data Processing Agreements.
Cookies, Session, Cache, JWT
Avoid storing sensitive data in cookies
For example, avoid code like this:
Avoid storing sensitive data in JWT
Avoid practices like this:
Don’t store sensitive data using HTM5 Storage
Avoid using HTML5 storage to store sensitive data. For instance, avoid:
Encrypt cookie data
In case sensitive data leaks into cookies, you should encrypt their data.
For instance, do:
Since Rails 6, the CookieStore uses the encrypted cookie jar to provide a secure, encrypted location to store session data. Cookie-based sessions thus provide both integrity as well as confidentiality to their contents. The encryption key, as well as the verification key used for signed cookies, is derived from the secret_key_base configuration value.
Safely store sessions
By default, Rails uses a Cookie based session store. This makes invalidating cookies difficult as they are stored on the client. Instead, the best practice is to use a database-based session, which is done easily in Rails through configuration:
Static file & Storage
Don't generate and store files locally
Avoid generating static files that contain sensitive data. If you have to do it, store them directly on a secure file storage system such as Amazon S3 with the appropriate permissions.
Avoid code like:
Rails provide a complete built-in storage mechanism, Active Storage, that we encourage you to use and especially to not set to “local” in production:
Close temporary files
When a Tempfile object is garbage collected, or when the Ruby interpreter exits, its associated temporary file is automatically deleted. This means that it is unnecessary to explicitly delete a Tempfile after use, though it's good practice to do so: not explicitly deleting unused Tempfiles can potentially leave behind large amounts of tempfiles on the filesystem until they're garbage collected. The existence of these temp files can make it harder to determine a new Tempfile filename.
Therefore, you should always call unlink or close in an ensure block, like this:
Do not store files containing sensitive data in your Git Repository
Do not store CSV, XLS, SQL dumps or TXT files containing sensitive data in your Git Repository.
Configure S3 buckets for different purposes
Configuring several S3 buckets for different uses gives you better control over the policy of each asset type.
You can define a default bucket in your application.rb.
If you want to use the analytic_store bucket, you can update your model to use it explicitly
Or if you want to generate a pre-signed URL:
Encrypt files containing sensitive data in S3
Amazon S3 provides a built-in server-side encryption mechanism at the object level to securely store your data.
If you’re using Rails’ built-in Active Storage solution, make sure to activate the server-side encryption setting in the configuration:
Store password safely
Use well known open source libraries such as Devise or Authlogic, or use the built-in Rails method has_secure_password that by default uses a bcrypt password-hashing function.
Implement proper password strength controls
OWASP recommends a password length of at least 8 characters. Here is a validation constraint example below:
Never commit your credentials in plain text:
Instead, use a secret manager solution. Rails provide a built-in system allowing to safely store and use credentials. Otherwise, you can use a third-party solution as AWS Secrets Manager, AWS Key Management Service, or HashiCorp Vault.
Do not use the built-in database accounts
Make sure to never use built-in database accounts, as postgres, admin or root.
Monitor for leaked tokens in your Git repositories
Use GitHub secret scanner, GitLab secret detection or a solution like GitGuardian.
Protect against CSRF attacks
Cross-Site Request Forgery (CSRF) vulnerabilities allow an attacker to perform actions on behalf of a user.
Rails provide out-of-the box protection against CSRF attacks, just make sure to have enabled it in your configuration as documented here:
Do not use subshell commands with user input
Subshell commands are not recommended to be used in web applications. In case you still need them, avoid associating it with user inputs.
Conduct database backups
Enable automated backups
Database backups ensure that all your data is available and recoverable in case of loss or corruption due to human error, natural calamities, or malicious black hat hackers.
Your cloud provider should provide automated backup functionalities. Ensure that:
- Automated backup is enabled on all your database instances.
- The backup retention period is configured in accordance with your Disaster Recovery Plan, your Recovery Point Objectives, and your personal data retention policy if you are subject to privacy laws such as GDPR.
For instance, you should enable automated backups of your Amazon RDS database instances.
Enable cross-region backups
Cross-region automated backups feature enables disaster recovery capability for mission-critical databases by providing you the ability to restore your database to a specific point in time within your backup retention period.
This allows you to quickly resume operations in the event that your cloud provider services becomes unavailable in your primary region. For instance, you should configure your Amazon RDS database instances to replicate snapshots and transaction logs to another AWS Region
Conduct regular security assessments
Conduct security audits
A security audit is an evaluation of an organization’s security controls against an established set of standards.
They are necessary if you are willing to get information security certifications such as ISO 27001 and SOC 2, which you can then leverage to demonstrate your strong security posture to prospects and customers.
They are also needed if you are subject to data regulations such as HIPAA or PCI.
Perform penetration tests
A penetration test simulates a real-world attack. Testers will attempt to identify and exploit any vulnerabilities within your system. Perform penetration tests at least once a year.
Document your data flows
Catalog your applications’ components
Build a central and unified view of your applications’ architecture by cataloging:
- Applications, or code repositories.
- Databases, data stores and data warehouses.
- Internal services (APIs, message brokers, gateways, etc.)
- External services, or third-party API integrations.
Map sensitive data flows
You can’t secure your data if you don’t know where it lives. Following your data taxonomy, document the data your applications’ components process.
You can do this manually by digging through your code repositories and storage systems, and by collecting information from developers. You can also rely on data discovery and classification tools to automate this process.
If only that were the case. There are always going to be new threats, new best practices, and new risks. Make sure you're in touch with your security team and leadership to make sure any security controls and policies are clear. We'll be sure to add to this list as new techiques arise too. See anything we missed? Let us know on Twitter @trybearer.