Ruby on Rails:允许使用清理助手在代码块内使用小于号“<”

Ruby on Rails: Allow less than sign '<' inside code block with sanitize helper

我正在尝试转义 Rails 中用户生成的内容。我使用 raw 和 sanitizeraw 助手来过滤这样的内容:

raw(sanitize(code, :tags =>   ['<', 'h2','h3','p','br','ul','ol','li','code','pre','a'] ))

允许在内容中提及的标签列表。

问题是当我尝试使用这样的 sql 查询来测试它时:

mysql -u sat -p -h localhost database <  data.sql

precode 块中删除小于号 (<) 后的所有内容。

请帮我想想办法。

Rails 3 为每个 String 实例添加了 html_safe 属性。除非 html_safe 设置为 true(简化),否则打印或插入数据库的每个字符串都将被转义。 raw 所做的,实际上是将 html_safe 设置为 true。所以你应该只传递一个已经是 safe/escaped.

的字符串

可能的解决方案如下所示:

strip_tags(code).html_safe

您可能需要根据您的用例添加额外的检查/字符串替换。

根据您的评论,您可能需要更复杂的版本。您可以尝试替换您希望允许的所有字符,清理字符串,然后反转替换以避免清理方法清理的次数超出您的实际需要。尝试这样的事情:

code = "mysql -u sat -p -h localhost database < data.sql"

ALLOWED_SIGNS = {
  :lower_than => "<".html_safe
}

s = code.dup
ALLOWED_SIGNS.each { |k, v| s.sub!(v, "%{#{k}}") }
sanitize(s) % ALLOWED_SIGNS

这可能会有所帮助,消毒剂可以选择提供在消毒过程中需要忽略的标签和属性的白名单

ActionView::Base.full_sanitizer.sanitize(html_string) #Basic Syntax

标签和属性的白名单可以如下指定

ActionView::Base.full_sanitizer.sanitize(html_string, :tags => %w(img br p), :attributes => %w(src style))

以上语句允许标签:img、br 和 p 以及属性:src 和 style。

我认为使用 Rails 中的默认清理方法是不可能的。

改为尝试使用清理 gem (https://github.com/rgrove/sanitize)

require 'sanitize'

allowed_elements = ['h2','h3','p','br','ul','ol','li','code','pre','a']
code             = "<pre>mysql -u sat -p -h localhost database < data.sql</pre>"

Sanitize.fragment(code, elements: allowed_elements)
# => <pre>mysql -u sat -p -h localhost database &lt; data.sql</pre>

要使用它来将经过清理的内容保存到数据库中,请向您的模型添加一个 before_save 过滤器,该过滤器对用户生成的内容运行清理并存储结果,例如

class MyModel < ActiveRecord::Base 
  ALLOWED_ELEMENTS = ['h2','h3','p','br','ul','ol','li','code','pre','a']

  before_save :sanitize_code

  private

  def sanitize_code
    self.code = Sanitize.fragment(code, elements: ALLOWED_ELEMENTS)
  end
end

当您输出内容时,您只需要使用原始视图助手,例如

<%= raw @instance.code %>

似乎整个问题都与数据在数据库中的存储方式有关。以前,一个小于号 '<' 被按原样保存,但现在它被转义,所以 '<' 将被保存为 &lt; 这似乎已经解决了问题。

我在使用 tinymce-rails 所见即所得编辑器时意外地理解了这一点,该编辑器会自动转义“<”。

@kieran-johnson 的回答可能会做同样的事情,但 tinymce-rails 解决了它而没有安装额外的 gem.

感谢所有抽出时间提供帮助的人。

nokogiri gem 解决问题:

gem 'nokogiri'

Nokogiri::HTML::DocumentFragment.parse('<b>hi</b> x > 5').text
 => "hi x > 5" 

考虑通过清理方法在 运行 之前用其 ASCII 字符 &#60; 替换“<”。它应该被转换成 &lt; 然后呈现为“<”字符,而不是 html.