Validate field in multiple languages - ruby-on-rails

I have the next form:
<%= form_for :user, url: "#" do |f| %>
<%= f.text_field :name %>
<%= f.submit "send" %>
<% end %>
and I need to validate the name field, but the page is working in multiple languages: chinese, portuguese, spanish and so on.
then I can't restrict the field just to alphanumerical values.
how can I validate just the dangerous special characters?

Let me try to break it down to several problems
1) how can I validate just the dangerous special characters?
It depends on what you do with the input date. Do you build a SQL query with it, do you
show it on your web page, do you send it to 3rd party web app, do you run some command line tool on the server and pass the data to it as an argument.
All of these things may have different notion of "dangerous special characters" and handling them.
So, there is no one perfect answer.
Probably, you need to specify how do you use this data.
2) where can I get more information on all kind os such problems?
I really hope that you are asking this question, because if you protect your application from SQL injection, but left wide open some other usual security holes, it won't do you too much good.
There is a very good security good for rails app, which is must read for security conscious developer:
http://guides.rubyonrails.org/security.html
3) ok. How do I handle multi language page
The default encoding is UTF-8 for Ruby 2.0 and up (which most likely you are using). This mean that you don't have to do anything special to handle other characters(languages which use them). However, you are right, you will need to add some kind of escaping for special characters (which depends on question #1).

Related

Safely filter Active Storage file names?

The Securing Rails Applications rails guide (file uploads section) gives 4 great paragraphs on the dangers of blindly accepting files from users. Some highlights:
If you store file uploads at /var/www/uploads, and the user enters a file name like "../../../etc/passwd", it may overwrite an important file.
It is best to use a permitted list approach, which checks for the validity of a file name with a set of accepted characters. This is opposed to a restricted list approach which attempts to remove not allowed characters.
Suppose the developer has set up Active Storage in a minimal way to work with their application, how would they go about ensuring file names are correctly escaped/sanitized/rejected (open to recommendation on best policy here)
What I know so far
The rails guide shows this code, but gives it only as an example, without much commentary around whether it's best practice or not
def sanitize_filename(filename)
filename.strip.tap do |name|
# NOTE: File.basename doesn't work right with Windows paths on Unix
# get only the filename, not the whole path
name.sub! /\A.*(\\|\/)/, ''
# Finally, replace all non alphanumeric, underscore
# or periods with underscore
name.gsub! /[^\w\.\-]/, '_'
end
end
Is that code sufficient to protect against known file name exploits? Or is there a better way?
Example usage
I don't know exactly how to use the above method.
Suppose we have the following form to submit an image:
<%= f.label "Select one or more images" %>
<%= f.file_field :teacher_images, multiple: true %>
I am not sure exactly how sanitize_filename fits in to this
Its safe to say that it can be expected to be safe against that particular exploit which relies on .. being used to save the file in another directory. However there is no exclusive list of known exploits and it might not protect against potential vulnerabilities which can be specific to whatever backend is actually storing the file.
Like for example a malicious user could overwrite other users uploads if the are all stored in the same directory.
The only way to actually be 100% safe against known and future exploits is to not accept file names from the user and generate them on the server which is done by ActiveStorage.

Rails I18n: Better way of interpolating links?

Is there a cleaner, content_tag-ish way of doing this? (I don't want HTML in my YML)
en.yml:
expert_security_advice: "Go <a href='{{url}}'>here</a> for expert security advice."
layout.html.erb:
<%= t(:expert_security_advice, :url => "http://www.getsafeonline.org") %>
The best I could come up with:
en.yml:
expert_security_advice: "Go *[here] for expert security advice."
layout.html.erb:
<%= translate_with_link(:expert_security_advice, "http://www.getsafeonline.org") %>
application_helper.rb:
include ActionView::Helpers::TagHelper
def translate_with_link(key, *urls)
urls.inject(I18n.t(key)) { |s, url|
s.sub(/\*\[(.+?)\]/, content_tag(:a, $1, :href => url))
}
end
No, there isn't a cleaner way of dealing with this. If you want pull the url out of the string then you're stuck breaking the sentence into four pieces:
"Go.
...
'here'
'for expert security advice.'
These four pieces are easy to put back together in English but the order might change in other languages and that can change the capitalization of here and cause other problems. To get it right, you'd have to structure things like this:
here = "#{t(:expert_security_advice_here)}"
whole_thing = t(:expert_security_advice, :here => here)
and the two separate strings in your YAML:
expert_security_advice_here: "here"
expert_security_advice: "Go {{here}} for expert security advice."
You'd also have to tell the translators that those two pieces of text go together.
If that sort of thing seems cleaner to you then go for it but I wouldn't worry about small bits of HTML in text that needs to be translated, any translator worth talking to will be able to handle it. Never try to take shortcuts with I18N/L10N issues, they will always lead you astray and cause problems: non-DRY code (WET code?) is always better than broken code.
As an aside, I'd recommend that you drop the standard Rails I18N string handling tools in favor of gettext, keeping everything synchronized with gettext is much easier and the code ends up being much easier to read.

Advice on Rails sanitize() in the view or how secure is my code

I have a partial that contains this sanitize() code:
<%= sanitize comment.body,
:tags => %w(a b embed i img object p param),
:attributes => %w(allowfullscreen allowscriptaccess href name src type value) %>
I'd like users to be able to embed videos, links, pictures, use italics, bold, etc.
How unsafe is this and if I put this on a live website what should I expect or be prepared to deal with?
Note: this is assuming there is no sanitizing of input obviously.
Thanks for reading.
The tags you really have to watch out for is <script/> and <object/>.
If allowing videos, you should either validate against an acceptable object format that matches the expected values coming from YouTube and other systems OR (ideally) create a UI that handles the embedding for the user.
Last year I created a system that allowed video embedding by taking a YouTube URL and manually deriving the object embed code. It had the benefit of making the user experience pretty streamlined as well as protecting the system from a potential vector of attack.
Oh, and other thing - use strong an em, rather than b and i if you can.

How good is the Rails sanitize() method?

Can I use ActionView::Helpers::SanitizeHelper#sanitize on user-entered text that I plan on showing to other users? E.g., will it properly handle all cases described on this site?
Also, the documentation mentions:
Please note that sanitizing
user-provided text does not guarantee
that the resulting markup is valid
(conforming to a document type) or
even well-formed. The output may still
contain e.g. unescaped ’<’, ’>’, ’&’
characters and confuse browsers.
What's the best way to handle this? Pass the sanitized text through Hpricot before displaying?
Ryan Grove's Sanitize goes a lot farther than Rails 3 sanitize. It ensures the output HTML is well-formed and has three built-in whitelists:
Sanitize::Config::RESTRICTED
Allows only very simple inline formatting markup. No links, images, or block elements.
Sanitize::Config::BASIC
Allows a variety of markup including formatting tags, links, and lists. Images and tables are not allowed, links are limited to FTP, HTTP, HTTPS, and mailto protocols, and a attribute is added to all links to mitigate SEO spam.
Sanitize::Config::RELAXED Allows an even wider variety of markup than BASIC, including images and tables. Links are still limited to FTP, HTTP, HTTPS, and mailto protocols, while images are limited to HTTP and HTTPS. In this mode, is not added to links.
Sanitize is certainly better than the "h" helper. Instead of escaping everything, it actually allows the html tags that you specify. And yes, it does prevent cross-site scripting because it removes javascript from the mix entirely.
In short, both will get the job done. Use "h" when you don't expect anything other than plaintext, and use sanitize when you want to allow some, or you believe people may try to enter it. Even if you disallow all tags with sanitize, it'll "pretty up" the code by removing them instead of escaping them as "h" does.
As for incomplete tags: You could run a validation on the model that passes html-containing fields through hpricot, but I think this is overkill in most applications.
The best course of action depends on two things:
Your rails version (2.x or 3.x)
Whether your users are supposed to enter any html at all on the input or not.
As a general rule, I don't allow my users to input html - instead I let them input textile.
On rails 3.x:
User input is sanitized by default. You don't have to do anything, unless you want your users to be able to send some html. In that case, keep reading.
This railscast deals with XSS attacks on rails 3.
On rails 2.x:
If you don't allow any html from your users, just protect your output with the h method, like this:
<%= h post.text %>
If you want your users to send some html: you can use rails' sanitize method or HTML::StathamSanitizer

Sanitize output in Rails

What is the best solution to sanitize output HTML in Rails (to avoid XSS attacks)?
I have two options: white_list plugin or sanitize method from Sanitize Helper http://api.rubyonrails.com/classes/ActionView/Helpers/SanitizeHelper.html . For me until today the white_list plugin worked better and in the past, Sanitize was very buggy, but as part of the Core, probably it will be under development and be supported for a while.
I recommend http://code.google.com/p/xssterminate/.
I think the h helper method will work here:
<%= h #user.profile %>
This will escape angle brackets and therefore neutralize any embedded JavaScript. Of course this will also eliminate any formatting your users might use.
If you want formatting, maybe look at markdown.
Personally I think it's not a small decision to accept any HTML entry in any web app. You can test for white/blacklisted tags as much as you like, but unless you're testing for correct nesting, someone could enter a series of closing tags, for example
</td></tr></span></div>
and really mess with your layout.
I'd usually give people something like Textile to enter their markup, since I'd rather spend my time working on business logic than HTML parsing.
Of course, if this text entry is more fundamental to your app (as for example it is for stackoverflow) then you probably should give more attention to hand-rolling your own.

Resources