I've just started using the brakeman gem to explore my rails app for security vulnerabilities.
I've managed to get everything tidy except for several cross site scripting warnings.
These all share the following in common:
They're all link_to tags
They all have instance variables in the class, alt or title
attributes
The instance variables all represent an active record query that
includes associated models
The instance variables are all "commentable". This describes a polymorphic association for user generated comments, similar in approach to the revised version of this Railscast.
e.g
<%= link_to "Click" , :class=> #model.association.attribute, :alt=> #model.association.attribute, :title=> #model.association.attribute, #model.association %>
where
#model = #commentable = Model.includes(:association1, association2: {:nested-association1, :nested-association2}).find(params[:id])
Is this something I need to be concerned about/ take action for? I thought Rails 3.2 escapes these by default.
I'd welcome advice to help me understand this issue better, and identify what steps I should take, if any.
I was unable to reproduce any warnings from the code you provided. What version of Brakeman are you using? What was the actual warning (redacted as necessary)?
I suspect you are getting warnings because user input is being detected in the href value of the link. See this pull request for more information about why this can be dangerous.
Unfortunately, without more information, I cannot tell if this is a false positive that needs to be fixed or a legitimate warning.
Edit:
Okay, now I am seeing the warning when testing with #model = #commentable = ... This is a problem with how Brakeman is handling the assignment.
If you are linking to an instance of a model, there should be no warning. If you are linking to a model attribute then this is counted as user input.
Yes, Rails will escape HTML, but it does not deal with links beginning with javascript: or data: which can be used for XSS.
Related
The form_with helper doesn't generate ids for form elements, and therefore doesn't generate for attributes either. This differs from the old form_tag and form_for helpers.
If you want to use form_with instead of the deprecated form_tag and form_for helpers, but you want ids to generate, you need to add this to your config:
config.action_view.form_with_generates_ids = true
id generation is useful in some cases because certain front-end things may require it. On top of that, it seems to me that not generating for attributes means that forms generated with form_with have less a11y.
I'm currently working in an older codebase where form element ids are required, and my knee-jerk reaction is to enable the above config setting so I can use form_with without having to manually set IDs for every element.
What is the reasoning for making form_with not generate ids by default? I'm concerned that I'm missing something here, since I assume there's a good reason for the decision.
From Rails 5.2 onwards, that actually is the default:
config.action_view.form_with_generates_ids = true
You can see it in the release notes, along with the commit that changed it. From the description of that commit:
When form_with was introduced we disabled the automatic
generation of ids that was enabled in form_for. This usually
is not an good idea since labels don't work when the input
doesn't have an id and it made harder to test with Capybara.
You can still disable the automatic generation of ids setting
config.action_view.form_with_generates_ids to false.
Doesn't seem like you're missing anything :D
I have a show route that displays the contents of my article
Controller:
def show
#article = Article.find(params[:id])
end
View:
...
<li class="content"><%= #article.content.html_safe %></li>
...
When running Brakeman, it flags the above as a potential Cross-Site Scripting (XSS) vulnerability
Unescaped model attribute near line 34: Article.find(params[:article_id]).content
I'm trying to figure out what XSS really is and what makes this vulnerable? If someone injected some malicious text or input into the params[:id] field in the route (e.g. /articles/BAD_INPUT) then Article.find() would not find the article and raise an error
The only way the view renders is if a valid Article record is found, right? How else can the user manipulate this?
Thanks!
Edit: I should definitely protect agains the case when an Article is not found and an error is raised, but I figured that's more of a bad design rather than a security vulnerability
Brakeman is warning because the code is taking information from the database and outputting it in a view without escaping it. By default, Brakeman treats values from the database as potentially dangerous. In this case, you probably know the article content is intended to be HTML and is safe to output without escaping it. If you wish to not warn about XSS with values from the database, you can use the --ignore-model-output option.
(The issue you linked in your answer is not really related. Brakeman is expected to warn about uses of raw/html_safe with potentially dangerous values.)
Ok found the answer after some digging.
It apparently has to do with html_safe and raw (which is just an alias for html_safe). The issue is specific to Brakeman and outlined here
That thread says the issue is acknowledged and solved, but it still didn't work for me using the latest version.
I solved it as follows
Controller:
def show
#article = Article.find(params[:id])
#article_content = view_context.raw(#article.content)
end
View:
...
<li class="content"><%= #article_content %></li>
...
Essentially we're marking the Article content as html_safe (using the alias raw()) beforehand so it doesn't cause an issue in the view.
Messier than I'd like, but it works
If you are storing html on your model and you are on Rails 4.2++, you could consider using the sanitize helper (docs).
For example, you can allow specific tags (e.g. links):
<%= sanitize #article.content, tags: %w(a), attributes: %w(href) %>
The docs have a lot of good examples.
Here's another write-up if you want some more information.
I am having difficulty understanding how to cause a View in ROR4 to have a param for a model. It shows up when I try to use strong parameters in a controller, specifically:
def model1_params
params.require(:model1).permit(:attr1,attr2)
end
Sometimes it works. Sometimes I get "param not found: model1"
My understanding is that it fails (when it does) because the web page being submitted doesn't have any param called "model1" and that it works (when it does) because something I have done has caused the web page submission to have this param. In the latter case, the param is a hash representing the fields of the model, with members for attr1, attr2, etc.
Does it work when I use "form_for" (which specifies a model) but not the other kind of form call, which is not tied to a model?
Note: I am writing because I've had this problem for several weeks with no progress. I have searched the Rails doc and lots of instructional examples on the web but with no luck. I know I'm being dense, but so far I've not found a real API reference document, nor a real API programmer's guide that covers strong parameters.
I've found lots of examples on strong parameters but none of them clearly explain how it works, that would let me figure out on my own what I am doing wrong.
Say your controller's method is associated to a route model1_controller_method_path.
Your method can be called from a link in a view, and if the model1 parameter is not present, yes, you will get a 'param not found' error. To avoid this, make sure to have your parameter passed from your link_to as in:
link_to model1_controller_method_path(:model1 => the_value_you_want)
I have looked around but I haven't really found an answer that seals the deal 100% for my individual situation.
In my Ruby app, I have a user share system where members can post 'stuff'. Well, sometimes members post links, and I have noticed as the site grows, more and more users are complaining about there not being clickable links.
How would I utilize regular expressions to match urls for links in posts. Furthermore, how would I apply this in my Model?
Thanks for you help, out of all my questions, this is a real important one for me ha!
EDIT
I suppose my init post was too vague...
I am more trying to figure out HOW to IMPLEMENT the use of regular expressions into my model instead of which regular expression to use.
The model is class Share. And the member's post is rendered as <%= share.content %> with content being a column in my Share table as well as an accessible attribute...
Thanks.
Try:
^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
from the IETF Specification on URLS. It matches ALL URLS including "ftp://..." so you may need to tweak it somewhat.
autolink will do it. It's been extracted into it's own gem...
https://github.com/tenderlove/rails_autolink
Example usage:
auto_link("Go to http://www.rubyonrails.org and say hello to david#loudthinking.com")
# => "Go to http://www.rubyonrails.org and
# say hello to david#loudthinking.com"
I'm pretty new at rails, so forgive me if I'm overlooking simple things or the rails way. My objective is to completely replace URLs of the form
/users/1
with
/username
for all purposes. (I think exposing IDs scaffolding publicly is like walking around with a bone sticking out of your arm.) But implementing seems a little more complicated than I expected. This seems to change the entire way rails indexes and looks up users, rather than just substituting a lookup method.
Although I've kind of gotten this to function using the to_param override in my user.rb file, I've read this means I'll have indexing problems down the road when using params([:username]), and I'm not sure how it will impact my
(a) session model at new user creation, and
(b) #User usage in the user/show.html.erb file.
So, I've either consulted the following pages (or asked the questions):
Ruby on rails routing matching username
customize rails url with username
Routing in Rails making the Username an URL:
routing error with :username in url
Correct routing for short url by username in Rails
rails3, clean url, friendly_id, sessions
The major issues I'd like to understand from this question:
What functionality do I lose by transitioning to this? That is, what things currently "just work" in rails that I'll have to address and rewrite if I pursue this replacement?
As a practice, is this something better to replace with friendly_id? My concern here is that creating a slug column in my DB identical to the username seems a little non-DRY and makes me uncomfortable, and I'd rather avoid dependencies on external gems where possible.
What does my users#show need to look like?
You should check out Friendly ID. Makes doing what you're trying to do incredibly easy.
https://github.com/norman/friendly_id
There's a Railscast for it, too.
http://railscasts.com/episodes/314-pretty-urls-with-friendlyid?view=asciicast
If your username contains a special characters like #, -, . and got an error that says "No route matches" then you need to filter its route. See below:
match "/user/:username" => 'users#show', :as => :profile, :username => /[\.a-zA-Z0-9_#-]+/
After working around this for a couple weeks, I'd say the best answer as of Aug 2, 2012 is that if you do this, you violate many rails conventions and rip apart the very fabric of time and space itself.
Ugly scaffolding in the URLs is a necessary part of rails' approach to RESTfulness.