Когда вы вызываете .html_safe
для строки, вы фактически получаете объект, который ведет себя как строка, но является ActiveSupport::SafeBuffer
. Когда вы добавляете строку к ActiveSupport::SafeBuffer
, она автоматически экранируется. Допустим, вы хотите построить диапазон, в котором текст вводится пользователем:
'<span>'.html_safe + text +'</span>'.html_safe
В этом случае мы защищены от атаки XXS, поскольку исходный текст пользователя автоматически экранируется:
irb(main):004:0> "<span>".html_safe + "<script>alert('You have been haxxored!')</script>" + "</span>".html_safe
=> "<span><script>alert('You have been haxxored')</script></span>"
Вот что происходит автоматически, когда вы выводите переменную в своих представлениях, поскольку представление построено как ActiveSupport::SafeBuffer
. Всякий раз, когда вы выводите обычную строку, она автоматически экранируется, поэтому по умолчанию она защищена.
Конечно, всегда найдется огромное количество программистов, которые просто дадут возможность самим сделать XSS-уязвимость по незнанию:
# WAAAH! Rails is escaping my tags! Bad rails!
'<span>'+ text +'</span>'.html_safe
Другой способ решения этой проблемы - использовать помощники тегов, частичные или Nokogiri вместо использования конкатенации строк для создания HTML, что само по себе утомительно, не читается на границе и подвержено ошибкам.