h
helper, because rails will always do it for you.In the example above, we have several different cases involving the use of HTML tags. In the first case, Rails should not filter the<strong></strong>!
<%= tag(:p, some_text) %>
<%= some_text %>
<strong>
that surrounds the word
, because The result is clearly not what the user entered. In the second case, Rails should filter some_text
inside the <p>
(but not the whole <p>
). Finally, in the third case, some_text
in some parent tag must be filtered.some_text
looks like the result will be:<strong></strong>!
<p><script>evil_js</script></p>
<script>evil_js</script>
In order for this to work everywhere in Rails applications, we have implemented a new approach called html_safe
. So, if the string is html_safe
(as determined by calling the html_safe?
method html_safe?
On the string), the ERB leaves it untouched. If the string is not html_safe
, the ERB will filter it before inserting it into the page.def tag(name, options = nil, open = false, escape = true)
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
end
Here, Rails creates the tag, teg_options
filter the contents, and then marks the entire body of the tag as safe. As a result, <p>
and </p>
will remain untouched, while user-inserted content will be subject to filtering.+
and <<
methods so that, if the line was changed, it marked the resulting one accordingly.<%= %>
in the template, i.e. large templates did not absorb the cost (as if it were one call <%= %>
per template), but only increased it.ActiveSupport::SafeBuffer
. SafeBuffer is inherited from String
'a, overriding +
, concat
and <<
in such a way that:html_safe
on a simple string returns a SafeBuffer
wrapper. Since SafeBuffer
inherited from the timeline, Ruby creates a wrapper extremely efficiently (only by sharing the internal storage char*
).buffer << other_string.html_safe
Here, Rails creates a new SafeBuffer
for other_string
, then passes it to the <<
source SafeBuffer
's method, which (method) checks if the new SafeBuffer
safe. For such cases, safe_concat
was written - a new method for the buffer, which uses the original concat method, eliminating the need to create a new SafeBuffer
and check it for security.safe_concat
in ActionView
are proxies for concat and safe_buffer
over the buffer, so you can use safe_concat in the helper if you have HTML text that needs to be combined with the buffer without checking and filtering.safe_concat
everywhere on the template outside the <% %>
safe_concat
<% %>
tags. This means that, in my today's commit, the XSS protection code does not affect the performance in such cases (i.e., scanning, in fact, all your plain text).raw
helper, so if you write something like <%= raw some_stuff %>
, ERB quietly uses safe_concat
, skipping the creation of SafeBuffer
'a and html_safety
checks.<%= %>
, Rails will always filter itSafeBuffer
is served in <%= %>
, Rails does not filter it. To get SafeBuffer
from a string, you need to call the html_safe
method on it. Does the XSS protection system have a very small impact on speed, limited only by the html_safe?
method html_safe?
raw
helper in <%= %>
, then Rails will detect this at the stage of compiling the template, without affecting the performance (i.e. in this case, no html_safe
checks html_safe
)<% %>
, since it copes with this at compile time, resulting, again, in the absence of an impact on performance+
for strings; influenced even if the application used raw
helper, or any other concatenation outside <% %>
inside the template.Source: https://habr.com/ru/post/82726/
All Articles