Is rails devise's 'alert' safe from XSS? - ruby-on-rails

I've gone off and overridden devise's devise_error_messages! in the DeviseHelper module to return a differently formatted response as suggested here: rails - Devise - Handling - devise_error_messages
However part of what I did was to include the results of alert like so:
def devise_error_messages!
# if there aren't any errors, just return a blank string
return '' if (resource.errors.empty? && !alert)
# go through each of the messages and add a <br> onto the back of it
messages = resource.errors.full_messages.map { |msg| msg << "<br>" }.join
# if there are also alerts, add that to the end of messages
if alert
messages << alert
end
# add div around messages
messages = "<div class='errorbox'>" << messages << "</div>"
# return messages in an html safe format
messages.html_safe
end
This way I can have the devise_error_messages! in any page that needs them, and it'll just return the right answer. (E.g. devise's Sign Up form returns it's errors through devise_error_message! while the login form returns in through alert).
What I want to know is if I can be guaranteed that the output of alert won't lead to any Cross Site Scripting. I am assuming that the output of resource.errors.full_messages is safe since the original devise_error_messages! method returns messages.html_safe and I'd trust that they wouldn't let it be at risk of any XSS.
However since alert is suggested to be used in an erg output (e.g. <%= alert %>) where any injected code would be escaped by default, is there any occasion, where code could be injected in, thus making use of .html_safe potentially quite hazardous?
tl;dr - is it safe to use alert.html_safe?

Unless you're modifying Devise's messages to add in user-provided content, or specifying custom flash messages with user-provided content, there's nothing to worry about.
All of Devise's flash messages are stored in config/locales/devise.en.yml.

Not entirely an answer, since sevenseacat answered that it should be safe, though I was looking around a bit and found this quite relevant, hopefully it'll help people with similar problems.
If I were to be very pedantic about it, I could enclose alert inside h() like this:
if alert
messages << h(alert)
end
This would ensure that any html in alert would be escaped while I can be sure that the rest of messages is HTML safe.

Related

Sanitizing user input for a message box

I am developing a crypto-related application and since those people who deal in crypto will always try some sort of scam or script kiddie "hack" I'd like to figure out the best way to clean up content in user-to-user chat boxes and comments fields.
I don't want any HTML/CSS/JS in there.
I want to leave email addresses, URLs, phone numbers and "normal" text untouched.
Right now I am doing a .gsub(/[^0-9a-zA-Z\#\;\:\-\_\,\.\ ]/i, '') before_save but it removes the newlines.
I tried adding .gsub(/[^0-9a-zA-Z\R\#\;\:\-\_\,\.\ ]/i, '') to make it leave newlines alone but it does not seem to work.
Would prefer not having to add any gems.
Rails has an excellent sanitizer built in, that I would recommend you use instead of trying to figure out your own regular expressions.
See:
http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html
Before you render any user's input out the page wrap it in santize
<%= sanitize #comment.body %>
If you want to sanitize before saving to the database, you can include the helper into your controller
class MyController < ApplicationController
include ActionView::Helpers::SanitizeHelper
def create
content = sanitize(params[:content])
Thing.save(content: content)
end
end

Is string interpolating a redirect_to notice message a security risk?

I recently ran the Brakeman gem against my app, and one of its warnings was about a redirect line in my controller:
Confidence: High
Warning type: Redirect
Message: Possible unprotected redirect near line xx
In that line in my controller, my redirect notice message includes the name of the object uploaded by the user:
def update
parent_klass = params[:parent_type].constantize
#entity = parent_klass.find params[:parent_id]
authorize! :update, #entity
entity_param_key = params[:parent_type].downcase.to_sym
#entity.update_attributes params[entity_param_key]
cache_path = begin
if parent_klass == Clinic
clinic_path(#entity)
else
specialist_path(#entity)
end
end
expire_fragment cache_path
redirect_to #entity, :notice => "Successfully updated #{#entity.name}."
end
In this controller, #entity.name is a form value that is defined by the user, meaning someone in theory could try to put malicious code into this field. However I'm unsure if using that parameter to generate a notice presents as a security risk.
Flash notice messages get presented in the view as such (in HAML):
#body.container
.row
#content.span12
#container
- flash.each do |type, msg|
.alert.alert-success= msg
= yield
Is this controller pattern a security risk, and if so, how can I prevent it from being a security risk while still keeping a customized notice message?
The warning is not about the flash message. I am not sure what report format you are viewing, but in the default text output you would see the dangerous value highlighted with + like this:
redirect_to(+params[:parent_type].constantize.find(params[:parent_id])+ ...
in the JSON report it says
"user_input": "params[:parent_type].constantize.find(params[:parent_id])",
The safety of the redirect relies on how well the authorize! method validates the params[:parent_type].constantize results in a valid model and (I assume) the current user is allowed to modify it. If it really results in a model, the redirect is safe.
However, the possible open redirect is the least of your worries in this method.
These lines allow an attacker to call find on an arbitrary class with an arbitrary argument:
parent_klass = params[:parent_type].constantize
#entity = parent_klass.find params[:parent_id]
While it's unlikely a find method would be that dangerous, consider the multitude of code likely included in the application and whether or not there may be some class somewhere with a find method that you really don't want an attacker to call.
The next bit looks like potential mass assignment:
entity_param_key = params[:parent_type].downcase.to_sym
#entity.update_attributes params[entity_param_key]
Given the lack of a permit call here, I can assume this application is not using strong parameters. Hopefully it is whitelisting the keys available for mass assignment using attr_accessible.
Also params[:parent_type].downcase.to_sym is a potential memory leak from the symbol creation. Normally that really isn't a huge deal in modern applications, but in this case the conversion is unnecessary since you can access params with symbols or strings.

What is flash hash in ruby on rails

I am an experienced PHP developer but new to RoR and trying to understand how every thing works. I know how to use flash hash i.e in my action method, I'll set
flash[:notice] = 'some message'
and in my view, i'll display that.
This mechanism is also implemented in Yii framework. I understand how it works there. The thing that I don't understand is how it actually works here in RoR. flash is just a local variable then how can I access it in my views?
flash is actually a method. It's not in your controller, but the Rails controller delegates it to the request object. So the flash method is defined in the request object, but you can access it from your controllers, and from the view.
Check the link to the ActionDispatch::Request code. The flash is actually stored inside the session when set. The next time the user requests a page, the flash is accessible for use in the views.
In your view you can just access it like this:
<%= flash[:notice] %>
Or in a aesthetically more pleasant way (this can only be done with notice and alert since they're so frequently used):
<%= flash.notice %>
See the documentation for more information.
'flash' is not a local variable. It is part of session like 'session' hash. What this implies is that session hashes (flash, session, cookies) are shared values between ActionController::Base and ActionView::Base. Therefore session hashes are accessible from controllers and from views.In order to access flash in views, just use it as you would use it in controller. Referring to your earlier code , you would print notice like this:
<% if flash[:notice] %>
<p><%= flash[:notice] %></p>
<% end %>
For further reference on this topic please checkout: guides
The flash hash is basically a variable which is populated with each controller/action request, and then is reset after the request has been performed. As Adilbiy Kanzitdinov has mentioned - it's set in the session hash :
The flash provides a way to pass temporary objects between actions.
Anything you place in the flash will be exposed to the very next
action and then cleared out. This is a great way of doing notices and
alerts, such as a create action that sets flash[:notice] = "Post
successfully created" before redirecting to a display action that can
then expose the flash to its template. Actually, that exposure is
automatically done.
You need to remember that ROR is full-stack, meaning it has a bunch of middleware it uses to create the most efficient responses for your users. This allows you to set local variables (session, params, flash are 3 I can think of)
To call from a view, you just need to reference this local variable, as below:
<%= flash[:key] %>

How can you (and should you) access flash, session, and controller instance variables from a view?

I should start of by saying that this started from helpful messages like the one you get when you set up Devise (as of v. 2.2.3):
Ensure you have flash messages in app/views/layouts/application.html.erb
For example:
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
There are at least three ways you can get information into a view from a controller. You can put things in the session, put then in the flash, or set an instance variable in the controller. I see examples where both the flash and the session are accessed with a bare variable in the view, which opens up the possibility of a collision. For example, I could have a controller like this:
class PerverseController < ApplicationController
def index
#msg = 'Message 1'
session[:msg] = 'Message 2'
# Note - this is where a real concern comes in, the previous page could
# have done anything! Though here I use flash.now to illustrate the point.
flash.now[:msg] = 'Message 3'
end
Then, if I had the following in a view:
<%= msg %>
It would seem that any of those three values might be referenced. In fact, code like the above in a view is an error for me (on Rails 3.2). You need to actually use '#' or 'flash' or 'session' explicitly.
I can't find any clear documentation on this - books and tutorials mostly reference the flash and the session as an afterthought, so I imagine it might change in future versions. But, I'd love to see a pointer to references, and a suggestion of what I should do to avoid breakage in the future while keeping my code as clear / concise as possible.
And for now, I want to make sure I integrate properly with Devise.

Any danger in calling flash messages html_safe?

I want a flash message that looks something like:
"That confirmation link is invalid or expired. Click here to have a new one generated."
Where "click here" is of course a link to another action in the app where a new confirmation link can be generated. Two drawbacks: One, since link_to isn't defined in the controller where the flash message is being set, I have to put the link html in myself. No big deal, but kind of messy.
Number two: In order for the link to actually display properly on the page I have to html_safe the flash display function in the view, so now it looks like (using Haml):
- flash.each do |name, message|
= content_tag :div, message.html_safe
This gives me pause. Everything else I html_safe has been HTML I've written myself in helpers and whatnot, but the contents of the flash hash are stored in a cookie client-side, and could conceivably be changed. I've thought through it, and I don't see how this could result in an XSS attack, but XSS isn't something I have a great understanding of anyway.
So, two questions:
1. Is there any danger in always html_safe-ing all flash contents like this?
2. The fact that this solution is so messy (breaking MVC by using HTML in the controller, always html_safe-ing all flash contents) make me think I'm going about this wrong. Is there a more elegant, Rails-ish way to do this?
I'm using Rails 3.0.0.beta3.
It depends on how sure you are where the contents for the message come from. If there is any possibility that any user could manipulate that message, then you should not do this!
I wouldn't do it either way. Because it could happen that you now know that every string is safe, but than you change one controller and add a message which could contain user input, than you have a possible vulnerability.
I would set any message html_safe when it is added to the flash and you know for sure it is safe.
For example
class SomeController < ApplicationController
def some_action
flash[:info] = 'Some safe text!'.html_safe
flash[:unsecure] = User.find(1).signature #//evil code
end
end
And in your view you can do it like this:
- flash.each do |name, message|
= content_tag :div, message
This way you make sure that if you add a new flash message that isn't safe, it would be made safe in the view by mistake.
In this case the flash[:info] message is printed as html_safe and flash[:unsecure] will be escaped, so the user evil javascript code will not be executed.
If you know there is no possibility that there is any unfiltered user input in the message it should be safe to use html_safe on the flash messages.
I didn't want to tempt fate by html_safe-ing all flash messages universally, so I decided to just redirect failed confirmation link attempts directly to the url I would have linked them to anyway. It's a simpler, more elegant solution, I think.

Resources