Sanity for free 6

Posted by pratik
on Sunday, October 05

Just an experiment.

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
require 'erb'

class ActionView::Base
  def _copy_ivars_from_controller_with_sanity
    variables = _copy_ivars_from_controller_without_sanity
    variables.each do |v|
      ivar = instance_variable_get(v)
      if ivar.is_a?(Array)
        values = ivar.map do |subivar|
          subivar.respond_to?(:to_sanity) ? subivar.to_sanity : subivar
        end
        instance_variable_set(v, values)
      elsif ivar.respond_to?(:to_sanity)
        instance_variable_set(v, ivar.to_sanity)
      end
    end
  end

  alias_method_chain :_copy_ivars_from_controller, :sanity
end

module Sanity
  class Cleaner
    Object.instance_methods.each do |m|
      delegate m, :to => :@model unless m =~ /^__/
    end
    
    def initialize(model)
      @model = model
    end

    def method_missing(method_id, *arguments, &block)
      if @model.class.sanitizable_columns.include?(method_id)
        value = @model.send(method_id)
        arguments.first == false ? value : ERB::Util.h(value)
      else
        @model.send(method_id, *arguments, &block)
      end
    end
  end

  module Model
    def self.included(base)
      base.send :include, InstanceMethods
      base.send :extend, ClassMethods
    end
    
    module InstanceMethods
      def to_sanity
        Cleaner.new(self)
      end
    end
    
    module ClassMethods
      def sanitizable_columns
        @sanitizable_columns ||= content_columns.find_all {|c| c.text? }.map(&:name).map(&:to_sym)
      end
    end
  end
end

ActiveRecord::Base.send :include, Sanity::Model

And then..

1
2
<%= @item.name # sanitized name %>
<%= @item.name(false) # unsanitized name  %>

I know, too many methods are missing, edge cases and what not. But hey, it’s just an idea/experiment.

CSRF protection for your existing rails application 4

Posted by pratik
on Friday, September 28

If you google for csrf attacks, you’ll find plenty of articles. But just for fun, here’s a simplest example : http://rubyurl.com/Liu Copy/Paste the link in a new window ( Don’t do it if you hate me/twitter )

Thanks to Rick, rails now has in built protection against such attacks, which is turned on by default for all new rails applications.

Here are some steps to make use of it for your existing rails application :

  • Add protect_from_forgery in your application.rb
1
2
3
4
class ApplicationController < ActionController::Base
  protect_from_forgery # Add :secret => 'some cryptic string' if not using cookie sessions
  # All your existing stuff
end
  • Turn off csrf protection in your test environment, unless you have time/energy/reasons to add csrf token to all your functional/integration tests that use post/put/delete methods.

To do so, add following in your test.rb environment file

1
2
# All your existing stuff
config.action_controller.allow_forgery_protection  = false
  • If you have cached any pages containing forms/buttons/links using post/put/delete method, make sure you clear your cache.

That’s all folks!

[WARNING] Don't trust strip_links()

Posted by pratik
on Wednesday, July 04

After coming across Ticket 8864 I tried to play around a bit more with link tags. And guess what, they’re more broken than I ever thought. And it’s not just rails, but firefox too.

For example consider the following html code
1
2
3
4
5
6
<html>
<head><title>Seriously, wtf !?</head>
<body>
  <href onMouseover="alert(document.location)">whatever
</body>
</html>

This actually work in Firefox. But it looks fine(blank) in Safari/IE ( No I don’t use Windows. I asked a friend to check it. )

Result ? Applications that depend on strip_links() for stripping link tags are open to XSS attacks.

I feel this is a critical issue in firefox and it’s not just related to rails. And in very special cases, it could be really risky.

I’ve submitted my modified version of strip_links() patch anyways.

Wait and watch.