Cross-site attacks in apps are very common and cause apps to respond incorrectly if not handled. Preventing XSS in an application is essential from a security perspective. And yes, who wants to be attacked by annoying requests and pop-ups ?! Some of the common XSS attacks should be handled as follows
1 2 3 4 | <svg/onload=alert(1)> <svg.onload=confirm(document.cookie) y> {{constructor.constructor('alert(1)')()}} |
All of the above XSS attacks when you show the alert alert or the confirmation popup automatically click yes and run the script before you even know it. And this is really annoying!
So, how to prevent these XSS attacks in the application? In Rails, this is pretty easy. The first and foremost thing we have to do is sanitize the parameters. And to do so, we need the sanitizer module to do this with different types of parameters. You can see the module just to sanitize any type of parameter – object, array, or file. You can use them with a simple function and pass all ActionController parameters and sanitize them.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | frozen_string_literal: true module RailsSanitizer class << self def steralize(data) @sanitizer = Rails::Html::FullSanitizer.new sanitize_now(data) end def steralize_text(text) Loofah.fragment(text).text(encode_special_chars: false) end private def sanitize_hash(myHash) myHash.each do |key, value| if value.is_a?(Hash) sanitize_hash(value) else myHash[key] = if value.is_a?(Array) sanitize_array(value) else if value.is_a?(ActionDispatch::Http::UploadedFile) value else @sanitizer.sanitize(value.to_s) end end end end end def sanitize_array(myArray) myArray.each do |value| if value.is_a?(Array) sanitize_array(value) else if value.is_a?(Hash) sanitize_hash(value) else @sanitizer.sanitize(value.to_s) end end end end def sanitize_now(data) data_class = data.class if data_class == Integer @sanitizer.sanitize(data.to_s).to_i elsif data.is_a?(Hash) sanitize_hash(data) elsif data.is_a?(Array) sanitize_array(data) elsif data.is_a?(ActionDispatch::Http::UploadedFile) data else begin @sanitizer.sanitize(data.to_s) rescue StandardError data end end end end end Usage: sanitize_parameters(params) def sanitize_parameters(parameters) sanitized_parameters = parameters.to_h.each_with_object({}) do |(key, value), sanitize_parameters| sanitize_parameters[key] = RailsSanitizer.steralize(value) end end Usage: sanitize_text("Rails <> Sanitizer & Steralizer") Output: "Rails &lt;&gt; Sanitizer &amp; Steralizer" def sanitize_text(text) RailsSanitizer.steralize(text.to_s.html_safe) end Usage: sanitize_text("Rails <> Sanitizer & Steralizer") Output: "Rails <> Sanitizer & Steralizer" def steralize_text(text) RailsSanitizer.steralize_text(text.to_s.html_safe) end |
This module can sanitize the parameters, but there are some cases where we want to keep &, <,> as in the timezone name. For that, unfortunately we have to save it as allowed parameters and save them after sanitize the parameters. To display sanitized text, you can use sanitize_text for texts where you don’t have to display <> and & if not, you can use steracy_text to display them in the view. So now you can sanitize both parameters and views in Rails with a simple parametric sanitize module.