| Module | Crumblr::InstanceMethods |
| In: |
vendor/plugins/crumblr/lib/crumblr.rb
|
Issue a crumb to verify at the receiving end of the form submission that the request came from a trusted source.
issue_crumb is intended to be used by view helper crumb_tags only. It calculates the value for the hidden tag _crumb that crumb_tags renders.
This value is the SHA1 hash of the following values concatenated:
| request.remote_ip: | The IP address of the remote client |
| timestamp: | The timestamp at which the crumb was issued |
| cookies[:_session_id]: | The session‘s ID |
| crumb_scope: | A class attribute in the ActionController where crumblr is used. |
| session[:crumb_secret]: | A random string acting as salt |
# File vendor/plugins/crumblr/lib/crumblr.rb, line 60
60: def issue_crumb(timestamp)
61: session[:crumb_secret] = String.rand(6) unless session[:crumb_secret]
62: signature = "#{request.remote_ip}#{timestamp}#{cookies[:_session_id]}#{@@crumb_scope}#{session[:crumb_secret]}"
63: logger.debug("_session_id = #{cookies[:_session_id]}
64: signature = #{signature}")
65: OpenSSL::Digest::SHA1.hexdigest(signature)
66: end
Verify that a crumb is valid. A crumb consists of query parameters _crumb and _timestamp, both if which are rendered by view helper crumb_tags. There is no validation on http GET as GET is commonly used w/o form submission.
Verify_crumb lets the request through if the crumb is valid. The client will be redirect back to where it came from when the crumb is not valid and the request includes an HTTP referer. Requests with invalid crumbs and no HTTP referer receive a 404.
# File vendor/plugins/crumblr/lib/crumblr.rb, line 78
78: def verify_crumb
79: if (request.post? || request.put? || request.delete?) then
80: logger.debug("Crumb window = #{@@crumb_window}\nCrumb flash msg = #{@@crumb_flash_msg}")
81: if (defined?(params[:_crumb]) &&
82: defined?(params[:_timestamp]) &&
83: Time.at(params[:_timestamp].to_i) + @@crumb_window > Time.now &&
84: (params[:_crumb] == OpenSSL::Digest::SHA1.hexdigest("#{request.remote_ip}#{params[:_timestamp]}#{cookies[:_session_id]}#{@@crumb_scope}#{session[:crumb_secret]}"))) then
85: return true
86: else
87: logger.warn("Invalid crumb:
88: _crumb = #{params[:_crumb]}
89: _timestamp = #{params[:_timestamp]}
90: remote_ip = #{request.remote_ip}
91: _session_id = #{cookies[:_session_id]}
92: scope = #{@@crumb_scope}
93: crumb_secret = #{session[:crumb_secret]}
94: digest = #{OpenSSL::Digest::SHA1.hexdigest("#{request.remote_ip}#{params[:_timestamp]}#{cookies[:_session_id]}#{session[:crumb_secret]}")}")
95: # Return the visitor to the origin of the request. Most
96: # often this will be local URL and this redirect will
97: # re-issue new crumbs. No harm done if the referrer is an
98: # external site. Crumblr's goal is to only accept requests
99: # from specific local origins.
100: if request.env['HTTP_REFERER']
101: flash[:warning] = @@crumb_flash_msg
102: redirect_to request.env['HTTP_REFERER']
103: else
104: # Return standard 404 message. Let the ActionController's
105: # rescue mechanisme handle this routing error rather then
106: # explicitly returning the default public/404.html
107: # file. Only report the lowest stack level in the error
108: # log.
109: raise ActionController::RoutingError, "Invalid crumb: #{params[:_crumb]}", caller(0)[0]
110: end
111: end
112: else
113: return true
114: end
115: end