Topic: Global filtering of GET and POST data?

Is there any way of setting an input filter for all data received via GET and POST? Specifically I'd like to strip all HTML and other nastiness (Javascript, XSS attempts, etc) from everything in params.

I'm aware of sanitize and the white list plugin, but only for use on a single string. Is there a way to apply these globally for all incoming data?

Many thanks,

Chris

Last edited by cdr (2007-01-17 06:11:50)

Re: Global filtering of GET and POST data?

I guess the quick and dirty solution would be to add this to app/controllers/application.rb:

include ActionView::Helpers::TextHelper

class ApplicationController < ActionController::Base
  before_filter :sanitize_params
 
  def sanitize_params
    params.each do |key, value|
      params[key] = sanitize(value)
    end
  end
end


Essentially this intercepts all requests and sanitizes every parameter in that request.

The dirty bit is including the ActionView text helper into the controller. Also, you would need to check the performance impact -- especially if you are sending large parameter values. For example I need to upload chapters with many thousands of words of text in my online library (17books.com) and I guess the performance hit would be quite severe.

Anyway, please let me know if this helps!

Last edited by philipp13 (2007-01-17 12:56:03)

Re: Global filtering of GET and POST data?

I was also thinking along the same lines... but the problem is that params[key] is not always a string. The value can be a string, a hash or an array - and within that there may be further nested hashes and arrays! We'd need to extract each string to run sanitize on it.

I started on something to deal with all of these situations, and this is as far as I got:

# a very basic input filter for params - strips HTML and sanitizes each value
# a work in progress....

def input_filter
    params.each do |key,value|

        # if it's a hash, we need to check each value inside it...
        if value.is_a?(Hash)

            value.each do |hash_key,hash_value|
                if value.is_a?(String) || value.is_a?(Integer)
                    params[key][hash_key] = sanitize(strip_tags(value))
                end
            end

            params[key].symbolize_keys!

        elsif value.is_a?(String) || value.is_a?(Integer)

            params[key] = sanitize(strip_tags(value))

        end
    end

    params.symbolize_keys!

end


Feels messy. I'm very interested in finding a more elegant solution!

How about doing the sanitize step in the model - perhaps by overriding the 'attributes' method as suggested in this thread on RailsWeenie. Is this the right place to do my filtering? Has anyone tried this approach?

Re: Global filtering of GET and POST data?

I'm very excited about the whitelist plugin. I was looking around for something like that a week or two ago. It looks like exactly what I wanted and I can't wait to integrate it into my project.

The code that feels messy can be cleaned up by moving the functionality into each type. You might define a sanitize_self method for each type (a different name might avoid confusion here). Then a string would know how to sanitize itself, as would a hash, an array, and any other type. For example, the array sanitize_self method would iterate through its elements, calling sanitize_self on each. Each element would already know how to sanitize itself. String's sanitize_self would call sanitize on itself. In the end, you could simply call params.sanitize_self in your input_filter.

Re: Global filtering of GET and POST data?

Thanks for an excellent suggestion dkov. I've implemented your idea and it's working a treat.

For anyone who's interested, this is how I did it.

Extend String, Array and Hash with sanitize! and strip_html! methods

class String 

    include ActionView::Helpers::TextHelper

    # String already has a sanitize! method
   
    # strip HTML from string
    def strip_html!
        replace strip_tags(self)
    end

end

class Array

    include ActionView::Helpers::TextHelper
   
    # sanitize
    def sanitize!
        self.map! do |value|
            if value.respond_to? :sanitize!
                value.sanitize!
            else
                value
            end
        end
    end
   
    # strip HTML
    def strip_html!
        self.map! do |value|
            if value.respond_to? :strip_html!
                value.strip_html!
            else
                value
            end
        end
    end

end

class Hash

    include ActionView::Helpers::TextHelper
   
    # sanitize
    def sanitize!
        self.each do |key,value|
            if value.respond_to? :sanitize!
                self[key] = value.sanitize!
            end
        end
    end
   
    # strip HTML
    def strip_html!
        self.each do |key,value|
            if value.respond_to? :strip_html!
                self[key] = value.strip_html!
            end
        end
    end

end


Set up input filter in application.rb

class ApplicationController < ActionController::Base

  before_filter :input_filter 

  # basic input filter - sanitizes all strings and strips HTML
  def input_filter
      params.strip_html!
      params.sanitize!
  end

end

Re: Global filtering of GET and POST data?

I hate to resurrect an old post, but I'm working with the filtering method at the bottom of this post.

The thing that worries me is that when I submit data with this before_filter included in application.rb, the rendered value doesn't look any different than it does without that command.

For example, if I enter in a link with a javascript function inside it, the brackets and the quotes are all escaped as they sit in the database. Which, as far as I know, is secure as far as XSS is concerned. But this happens whether the before_filter is included or not.

I've attempted to test this in ruby/script console, but I keep getting the following error:

input_filter @provider.description
NoMethodError: undefined method `input_filter' for #<Object:0x2b24eff383f8>
        from (irb):2

I had tried the white_list plugin, but I had the same issue with it. I'm nervous about security with Rails, so I'd like to be able to know that whatever method I'm using is going to do what it needs to do.

Thanks for any thoughts.
Jonathan

Re: Global filtering of GET and POST data?

cdr wrote:

Thanks for an excellent suggestion dkov. I've implemented your idea and it's working a treat.

I don't know. But what about those cases when you don't want your params with html strings to be striped. Example: WYSIWYG textarea.

Re: Global filtering of GET and POST data?

Hi to all
Its nice to hear that you could implement it happycoder. I need the same functionality as the whitelist plugin. Please if you could provide me the exact steps to take and how to integrate the sanitize method in my rails project  it would be very nice. I put the code provided by cdr in my application controller and I get the error cannot find 'strip_html!' method.
Basically I want the <script> tag and the <style> tag stripped.