Ruby on Rails:允许在使用sanitize辅助程序的代码块中包含小于号'<'

9

我正在尝试在Rails中避免用户生成的内容。我使用了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块中,它会删除小于号(<)之后的所有内容。

请帮我想出一种方法来实现这个功能。


我无法在控制台中重现您的问题。也许您应该展示一下您传递给“sanitize”的确切内容。此外,“<”不是一个标签,尽管将其包含在允许的标签列表中似乎不会引起问题。 - Dave Schweisguth
我认为这可能与数据库中数据存储的方式有关。你能建议一下最佳的存储和呈现源代码的方法吗? - mansoor.khan
渲染是你一直在询问的内容,但就存储而言,我不明白为什么你要使用比足够大的字符串类型更复杂的东西。如果你的数据库正在破坏你的内容,你应该能够通过比较前后来检测到这一点。 - Dave Schweisguth
让我理解一下,您想要能够在“<pre>”标签中保存类似于“mysql -u sat -p -h localhost database < data.sql”的内容,但是如果您使用它们,Rails会剥离其中的所有内容? - Gustavo Rubio
@gustavo-rubio 我之前的方法是错误的。现在我已经找到了答案,并提供了详细信息。 - mansoor.khan
显示剩余3条评论
6个回答

4

我不相信在Rails中使用默认的sanitize方法可以实现这一点。

相反,尝试使用Sanitize 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 %>

2
Rails 3为每个String实例添加了html_safe属性。除非将html_safe设置为true(简化),否则打印或插入到数据库中的每个字符串都将被转义。raw实际上是将html_safe设置为true。因此,您应该只传递已经安全/转义的字符串。
一个可能的解决方案可能如下所示:
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

问题在于我必须对用户输入进行清理,但是还要允许某些HTML标记,正如问题所述。问题在于清理操作也会移除小于号'<',因此无法按照问题中所述输出SQL代码。你现在明白了吗? - mansoor.khan
我已经更新了我的答案,并添加了一些更多的示例代码,仍然使用“sanitize”方法。因此,您可以以与问题中相同的方式添加允许的“tags”。 - Alex

2
似乎整个问题都出在数据库中数据存储的方式上。以前,小于号“<”被保存为它本身,但现在已经被转义了,所以“<”将被保存为&lt;,这似乎解决了问题。
我是在使用tinymce-rails所提供的所见即所得编辑器时意外地理解了这一点,该编辑器会自动转义“<”。
@kieran-johnson的答案可能也是这样做的,但tinymce-rails无需安装额外的gem就解决了这个问题。
感谢所有抽出时间帮助我的人。

1
这可能会有所帮助,清理器具有选项,可以提供需要在清理期间忽略的标签和属性的白名单。
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。

2
你将如何允许在MySQL查询中使用小于号“<”? - mansoor.khan
在我的一个应用程序中,我允许img、br、p元素和src、style属性的方式如下。由于'<'不是标准的HTML元素,因此清理器无法处理它。 你可以尝试一些解决方法,比如收集所有带有位置的'<'并从代码中删除,将代码传递给清理器,然后再将'<'添加到代码中。 - Satishakumar Awati
这正是我在问题描述中提到的允许标签的方式。如果我能“尝试一些变通方法”,我就不会在这里问这个问题了。 - mansoor.khan
@IslamWazery 确切无误 - Zia Ul Rehman Mughal

0

在运行 sanitize 方法之前,考虑将 "<" 替换为其 ASCII 字符 &#60;。它应该会被转换为 &lt;,然后呈现为 "<" 字符,而不是 HTML。


0

nokogiri gem 解决了问题:

gem 'nokogiri'

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接