XSS (Cross-Site Scripting) — одна из самых распространённых уязвимостей веб-приложений, позволяющая злоумышленникам внедрять вредоносный код в страницы. Rails предоставляет встроенные механизмы защиты, но даже они иногда дают сбой. Разберёмся, как ERB и Rails борются с XSS, и где разработчики сами открывают двери для атак.
🔒 Как Rails защищает от XSS по умолчанию
Автоматическое экранирование в ERB
Rails использует ERB (Embedded Ruby) для шаблонов, и по умолчанию все строки экранируются:
<%= @user_input %> <!-- Безопасно: < превратится в < -->
Это работает благодаря методу html_escape, который вызывается автоматически для всех строк, не помеченных как “безопасные”.
raw и html_safe: когда осторожность отключается
Но если явно указать, что строка “безопасна”, экранирование отключается:
<%= raw @user_input %> <!-- Опасно! -->
<%= @user_input.html_safe %> <!-- Тоже опасно! -->
Пример уязвимости:
# Контроллер
def show
@comment = params[:comment]
end
<!-- Вьюха -->
<div class="comment">
<%= raw @comment %> <!-- XSS-атака возможна! -->
</div>
💥 Где чаще всего ошибаются
1. JSON в JavaScript
<script>
var data = <%= raw @user_data.to_json %>; <!-- Уязвимость! -->
</script>
Решение: Используйте json_escape или to_json.html_safe с осторожностью.
2. Динамические CSS/JavaScript
<style>
.profile { background: url(<%= @user_background %>); }
</style>
Атака: @user_background = 'red;}</style><script>alert(1)</script><style>'.
3. Ошибки в хелперах
def custom_link(text, url)
"<a href='#{url}'>#{text}</a>".html_safe
end
Проблема: Не экранируются text и url.
🛡️ Как защититься: лучшие практики
1. Всегда экранируйте по умолчанию
<%= @user_input %> <!-- Так правильно -->
2. Используйте sanitize для HTML
<%= sanitize @user_html, tags: %w[a b i], attributes: %w[href] %>
3. Content Security Policy (CSP)
Добавьте в config/initializers/content_security_policy.rb:
Rails.application.config.content_security_policy do |policy|
policy.default_src :self
policy.script_src :self, :https
end
4. Проверяйте данные перед вставкой в JavaScript
<script>
var data = <%= @user_data.to_json.html_escape %>;
</script>
🧪 Тестируем защиту
Тест на уязвимость в RSpec
describe "CommentsController" do
it "экранирует HTML в комментариях" do
post :create, params: { comment: '<script>alert(1)</script>' }
expect(response.body).not_to include('<script>')
end
end
Используйте Brakeman
Добавьте в Gemfile:
gem 'brakeman', require: false
И запустите:
brakeman -q -w2
🎤 Что сказать на собеседовании
— Как Rails защищает от XSS?
— ERB автоматически экранирует все строки, но разработчик может отключить защиту через raw или html_safe. Важно избегать вставки непроверенных данных в JavaScript/CSS и использовать CSP.
🧾 Вывод
Rails даёт отличные инструменты для защиты от XSS, но они требуют осознанного использования. Автоматическое экранирование — не волшебная палочка, а html_safe — не “удобная фича”, а потенциальная дыра. Проверяйте данные, используйте CSP и помните: безопасность — это процесс, а не разовая настройка.