kivanio (owner)

Fork Of

gist: 208018 by postmodern A Rack middleware app to co...

Revisions

gist: 227933 Download_button fork
public
Public Clone URL: git://gist.github.com/227933.git
Embed All Files: show embed
referer_control.rb #
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
module Rack
  #
  # RefererControl is a Rack middleware app which restricts access to paths
  # based on the Referer header. Using RefererControl you can make sure
  # users follow the intended flow of a website. If a controlled path is
  # visited with an unacceptable Referer URI, then a simple 307 Redirect
  # response is returned.
  #
  # RefererControl should also make Cross Site Request Forgery (CSRF) a
  # little more difficult to exploit; but not impossible using JavaScript.
  #
  # MIT License - Hal Brodigan (postmodern.mod3 at gmail.com)
  #
  class RefererControl
 
    #
    # Initializes the RefererControl rules.
    #
    # @param [#call] app
    # The app to apply referer control rules to.
    #
    # @param [Hash] options
    # Additional options.
    #
    # @option options [String] :redirect
    # The URI to redirect bad requests to.
    #
    # @option options [String] :message ('')
    # Message to place in the redirect response.
    #
    # @option options [String] :content_type ('text/html')
    # The Content-Type of the redirect response.
    #
    # @option options [Hash{Array<String> => Array<String>}] :rules
    # The acceptable referer URIs mapped to the controlled paths.
    #
    # @example
    # use Rack::RefererControl,
    # :redirect => 'https://www.app.com/',
    # :rules => {
    # ['https://www.app.com/login'] => ['/sessions/new'],
    # ['https://www.app.com/payments'] => ['/payments/send'],
    # ['https://www.app.com/profile'] => ['/account/destroy']
    # }
    #
    def initialize(app,options={})
      @app = app
      @rules = {}
 
      options[:rules].each do |referers,paths|
        paths.each do |path|
          @rules[path] ||= []
          @rules[path] += referers
        end
      end
 
      @redirect = [
        307,
        {
          'Location' => options[:redirect],
          'Content-Type' => (options[:content_type] || 'text/html')
        },
        [options[:message] || '']
      ]
    end
 
    def call(env)
      path = env['PATH_INFO']
 
      puts env.inspect
 
      if @rules.has_key?(path)
        unless @rules[path].include?(env['HTTP_REFERER'])
          return @redirect
        end
      end
 
      @app.call(env)
    end
 
  end
end