Prevent HTML escaping in a text area - ruby-on-rails

Realized that if I put HTML code in a rails text area, it will output the html.
For instance:
<b> Hello </b>
outputs as:
Hello
I thought rails 3 text inputs automatically escape HTML but whenever I output #variable.textarea, it still shows the bold text. Is it being selective about what HTML to input? And how do I make sure all HTML is always escape when I output the content of my textarea?
Thanks!

If <b>hello</b> comes out as hello, that means HTML escaping is already prevented.
Since you don't want users to be able to use HTML in their inputs, you want HTML to be escaped, so that <b>hello</b> comes out as <b>hello</b>.
In a Rails 3 app, html automatically gets escaped - but you can explicitly escape it using the h method:
<%= h my_string %>

Related

Displaying user input html with newlines

I have comments section in my application where users enter input in a text area. I want to prevent the line breaks they enter but also display html as a string. For example, if comment.body is
Hello, this is the code: <a href='foo'>foo</a>
Bye
I want it to be displayed just as above. The same with anything else, including iframe tags.
The closest I got is:
= simple_format(comment.body)
but it sanitizes html code and it's not displayed. Example: foo <iframe>biz</iframe> bar is displayed as:
foo biz bar
What should I do to achieve what I want?
Just use it without any method, it will be rendered as plain text:
= comment.body
Using your second example, the output will be:
foo <iframe>biz</iframe> bar
To make \n behave as <br>, you can use CSS:
.add-line {
white-space: pre-wrap;
}
And use it in your view:
.add-line = comment.body
Using your first example:
comment.body = "Hello, this is the code: <a href='foo'>foo</a>\n\nBye"
The output will be:
Hello, this is the code: <a href='foo'>foo</a>
Bye
Having done something similar in the past, I think you must first understand why HTML is sanitized from user input.
Imagine I wrote the following into a field that accepted HTML and displays this to the front page.
<script>alert('Hello')</script>
The code would execute for anyone visiting the front-page and annoyingly trigger a JS alert for every visitor.
Maybe not much of an issue yet, but imagine I wrote some AJAX request that sent user session IDs to my own server. Now this is an issue... because people's sessions are being hijacked.
Furthermore, there is a full JavaScript based exploitation framework called BeEF that relies on this type of website exploit called Cross-site Scripting (XSS).
BeEF does extremely scary stuff and is worth taking a look at when considering user generated HTML.
http://guides.rubyonrails.org/security.html#cross-site-scripting-xss
So what to do? Well if you checked in your DB you'd see that the tags are actually being stored, but like you pointed out aren't displayed.
You could .html_safe the content, but again I strongly advise against this.
Maybe instead you should write an alternative .html_safe method yourself, something like html_safe_whitelisted_tags.
As for removing newlines, you say you want to display as is. So replacing /n with <br>, as pointed out by Michael, would be the solution for you.
comment.body.gsub('\n', '<br />').html_safe_whitelisted_tags
HTML safe allows the html in the comment to be used as html, but would skip the newlines, so doing a quick replace of \n with <br /> would cover the new lines
comment.body.gsub("\n", "<br />").html_safe
If you want the html to be displayed instead of rendered then checkout CGI::escapeHTML(), then do the gsub so that the <br /> does not get escaped.
CGI::escapeHTML(comment.body).gsub("\n", "<br />")

Line breaks are not shown in heredoc

I have a heredoc string
html =<<EOF
<span>
Hello hello 123
</span>
<a>Link1</a>
<a>Link2Link2</a>
EOF
If I say puts html, it will give html as it is, meaning with new lines which is fine. If I call p html I'll get the html without line breaks.
However, what I really need to do is to convert this html into picture and it should have line breaks. Here is how I do that:
kit = IMGKit.new html, quality: 30
# using Magick::Image ......
# some code which is not important....
img.write("my_gif.gif")
It's almost fine except the fact that the result html, as I've already said, doesn't have line breaks, it has only one line:
<span>Hello hello 123</span><a>Link1</a><a>Link2Link2</a>
Of course, if I add <br /> tags, it all will be worked out. But I'm not able to do that for some reason, I want not to use <br /> and still have line breaks.
This is not the problem of IMGKit or Rmagic as I'm pretty sure.
So how do I achieve that?
I agree it is not a problem with IMGKit - it is doing what it is supposed to do - render the HTML. There is also nothing wrong with the heredoc, and nothing magical you can do with Ruby's representation of the HTML such that literal whitespace (spaces, tabs, newlines) in HTML source become visible when rendered.
The most common rendering of source whitespace by HTML viewers is that any length of pure whitespace (whether spaces, tabs, newlines or any combination) is rendered as a single space -> <- in the view. Additionally, whitespace between one element end and another starting is often completely ignored (although the rendering of the elements themselves may cause layout/spacing effects in the view).
You could, however, do something like this:
kit = IMGKit.new html.gsub(/\n/,"<br/>"), quality: 30
and have line breaks rendered without adding <br/> to your heredoc.

rails truncate method adds special characters

I have this html text:
<p> I'm a html text</p>
To show it on my web page, I first sanitize it and remove the tags:
sanitize(best_practice.milestone.description, :tags=>[])
I then shows ok, the is removed.
But if I decide to truncate the text like this:
sanitize(best_practice.milestone.description, :tags=>[]).truncate(30)
The is visible again on my web page. All the special chars will actually be visible.
What can I do to avoid truncate to make this special chars visible?
Dealing with sanitize helpers and truncation can be tricky. There are a lot of different sanitize helpers: h, CGI::escapeHTML, sanitize, strip_tags, html_safe, etc. Sanitization and truncation do not work well together if a string is truncated between an opening and a closing tag or right in the middle of a special HTML character.
The following statement seems to work
sanitize(text, :tags=>[]).truncate(30, :separator => " ").html_safe
The trick is to a pass a :separator option to truncate text at a natural break.

Rails is saving a title with 'Hello &' as 'Hello &' why?

I have a model with a title field. When I post to the server I see:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"3Le7aLitPd6MzWFeB0ofI9wk1IuhybNswjG9N+KgJJc=", "poll"=>{"title"=>"Hello &"}}
Problem is the DB is then saving as:
Hello &
So later when I output the field on the site it shows up as Hello &
What is the right way to handle this? I want entering & to be supported but at the same time not allow users to submit html or js tags.
Thanks
Sanitize.clean outputs HTML, not plain text so of course your ampersands are converted to their HTML entity form (i.e. &). For example, straight from the the fine manual:
Sanitize.clean(html, Sanitize::Config::RESTRICTED) # => '<b>foo</b>'
So you are, in fact, store HTML snippets rather than pieces of plain text. You should be using
<%= raw #thing.title %>
to display your titles as they have already been rendered HTML-safe by Sanitize.

HTML not interpreted with JQuery Mobile

I have some HTML-encodet text in a database, and when I retrieve it I HTML-decode it. The problem is that the HTML tags are not interpreted, but displayed.
If I have the following paragraph:
<p>
Hello World</p>
It will output:
<p> Hello World </p>
I output the code as following:
#Server.HtmlDecode(Model.Message)
What simple thing might I be missing?
You are missing the Html.Raw helper:
#Html.Raw(Model.Message)
Make sure that you have sanitized the input before since the Html.Raw helper will output the HTML as-is without encoding.

Resources