使用Sanitize将变压器中的节点列入白名单

时间:2011-03-31 17:57:56

标签: ruby-on-rails ruby nokogiri sanitize

我在使用适用于Ruby的Sanitize库创建变换器lambda的this example时遇到了一些麻烦。

我已经完成了一个简单的脚本,它试图清理我的options[:content]变量中的任何内容,但是尽管遇到了包含一个名为node_whitelist的节点数组的哈希,但似乎不知何故我的节点没有制作白名单。

这是我的代码:

#!/usr/bin/ruby

require 'rubygems'
require 'sanitize'

options = { :content => "<p>Here is my content. It has a video: <object width='480' height='390'><param name='movie' value='http://www.youtube.com/v/wjthx1GKhUI?fs=1&amp;hl=en_US'></param><param name='allowFullScreen' value='true'></param><param name='allowscriptaccess' value='always'></param><embed src='http://www.youtube.com/v/wjthx1GKhUI?fs=1&amp;hl=en_US' type='application/x-shockwave-flash' allowscriptaccess='always' allowfullscreen='true' width='480' height='390'></embed></object></p>" }

# adapted from example at https://github.com/rgrove/sanitize/
video_embed_sanitizer = lambda do |env|
  node      = env[:node]
  node_name = env[:node_name]

  puts "[video_embed_sanitizer] Starting up"
  puts "[video_embed_sanitizer]   node is #{node}"
  puts "[video_embed_sanitizer]   node.name.to_s.downcase is #{node.name.to_s.downcase}"

  # Don't continue if this node is already whitelisted or is not an element.
  if env[:is_whitelisted] then
    puts "[video_embed_sanitizer]   Already whitelisted"
  end
  return nil if env[:is_whitelisted] || !node.element?

  parent = node.parent

  # Since the transformer receives the deepest nodes first, we look for a
  # <param> element or an <embed> element whose parent is an <object>.
  return nil unless (node.name.to_s.downcase == 'param' || node.name.to_s.downcase == 'embed') &&
    parent.name.to_s.downcase == 'object'

  if node.name.to_s.downcase == 'param'
    # Quick XPath search to find the <param> node that contains the video URL.
    return nil unless movie_node = parent.search('param[@name="movie"]')[0]
    url = movie_node['value']
  else
    # Since this is an <embed>, the video URL is in the "src" attribute. No
    # extra work needed.
    url = node['src']
  end

  # Verify that the video URL is actually a valid YouTube video URL.
  puts "[video_embed_sanitizer]   URL is #{url}"
  return nil unless url =~ /^http:\/\/(?:www\.)?youtube\.com\/v\//

  # We're now certain that this is a YouTube embed, but we still need to run
  # it through a special Sanitize step to ensure that no unwanted elements or
  # attributes that don't belong in a YouTube embed can sneak in.
  puts "[video_embed_sanitizer]   Node before cleaning is #{node}"
  Sanitize.clean_node!(parent, {
    :elements => %w[embed object param],

    :attributes => {
      'embed'  => %w[allowfullscreen allowscriptaccess height src type width],
      'object' => %w[height width],
      'param'  => %w[name value]
    }
  })
  puts "[video_embed_sanitizer]   Node after cleaning is #{node}"

  # Now that we're sure that this is a valid YouTube embed and that there are
  # no unwanted elements or attributes hidden inside it, we can tell Sanitize
  # to whitelist the current node (<param> or <embed>) and its parent
  # (<object>).
  puts "[video_embed_sanitizer]   Marking node as whitelisted and returning"
  {:node_whitelist => [node, parent]}
end

options[:content] = Sanitize.clean(options[:content], :elements => ['a', 'b', 'blockquote', 'br', 'em', 'i', 'img', 'li', 'ol', 'p', 'span', 'strong', 'ul'],
                                    :attributes => {'a' => ['href', 'title'], 'span' => ['class', 'style'], 'img' => ['src', 'alt']},
                                    :protocols => {'a' => {'href' => ['http', 'https', :relative]}},
                                    :add_attributes => { 'a' => {'rel' => 'nofollow'}},
                                    :transformers => [video_embed_sanitizer])
puts options[:content]

这是正在生成的输出:

[video_embed_sanitizer] Starting up
[video_embed_sanitizer]   node is <param name="movie" value="http://www.youtube.com/v/wjthx1GKhUI?fs=1&amp;hl=en_US">
[video_embed_sanitizer]   node.name.to_s.downcase is param
[video_embed_sanitizer]   URL is http://www.youtube.com/v/wjthx1GKhUI?fs=1&hl=en_US
[video_embed_sanitizer]   Node before cleaning is <param name="movie" value="http://www.youtube.com/v/wjthx1GKhUI?fs=1&amp;hl=en_US">
[video_embed_sanitizer]   Node after cleaning is <param name="movie" value="http://www.youtube.com/v/wjthx1GKhUI?fs=1&amp;hl=en_US">
[video_embed_sanitizer]   Marking node as whitelisted and returning
[video_embed_sanitizer] Starting up
[video_embed_sanitizer]   node is <param name="allowFullScreen" value="true">
[video_embed_sanitizer]   node.name.to_s.downcase is param
[video_embed_sanitizer] Starting up
[video_embed_sanitizer]   node is <param name="allowscriptaccess" value="always">
[video_embed_sanitizer]   node.name.to_s.downcase is param
[video_embed_sanitizer] Starting up
[video_embed_sanitizer]   node is <embed src="http://www.youtube.com/v/wjthx1GKhUI?fs=1&amp;hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="390"></embed>
[video_embed_sanitizer]   node.name.to_s.downcase is embed
[video_embed_sanitizer]   URL is http://www.youtube.com/v/wjthx1GKhUI?fs=1&hl=en_US
[video_embed_sanitizer]   Node before cleaning is <embed src="http://www.youtube.com/v/wjthx1GKhUI?fs=1&amp;hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="390"></embed>
[video_embed_sanitizer]   Node after cleaning is <embed src="http://www.youtube.com/v/wjthx1GKhUI?fs=1&amp;hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="390"></embed>
[video_embed_sanitizer]   Marking node as whitelisted and returning
[video_embed_sanitizer] Starting up
[video_embed_sanitizer]   node is <object width="480" height="390"></object>
[video_embed_sanitizer]   node.name.to_s.downcase is object
[video_embed_sanitizer] Starting up
[video_embed_sanitizer]   node is <p>Here is my content. It has a video: </p>
[video_embed_sanitizer]   node.name.to_s.downcase is p
<p>Here is my content. It has a video: </p>

我做错了什么?

2 个答案:

答案 0 :(得分:2)

我也遇到了YouTube示例的问题。以下是我如何允许脚本标记,但仅适用于Ooyala视频播放器:

  1. 将'script'添加到:elements
  2. 添加'script'=&gt; ['src'] to:attributes
  3. 使用:transformers =&gt; lambda {| env |除非env [:node_name] =='script';除非(env [:node] ['src']&amp;&amp; env [:node] ['src']。include?('http://player.ooyala.com')); Sanitize.clean_node!(env [:node],{});结束; nil}
  4. 我也通过创建自己的初始化程序配置来极大地清理了一些东西:

    class Sanitize
      module Config
        ULTRARELAXED = {
          :elements => [
            'a', 'b', 'blockquote', 'br', 'caption', 'cite', 'code', 'col',
            'colgroup', 'dd', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
            'i', 'img', 'li', 'ol', 'p', 'pre', 'q', 'small', 'strike', 'strong',
            'sub', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'u',
            'ul', 'object', 'embed', 'param', 'iframe', 'script'],
    
          :attributes => {
            'a'          => ['href', 'title'],
            'blockquote' => ['cite'],
            'col'        => ['span', 'width'],
            'colgroup'   => ['span', 'width'],
            'img'        => ['align', 'alt', 'height', 'src', 'title', 'width'],
            'ol'         => ['start', 'type'],
            'q'          => ['cite'],
            'table'      => ['summary', 'width'],
            'td'         => ['abbr', 'axis', 'colspan', 'rowspan', 'width'],
            'th'         => ['abbr', 'axis', 'colspan', 'rowspan', 'scope',
                             'width'],
            'ul'         => ['type'],
            'object' => ['width', 'height'],
            'param'  => ['name', 'value'],
            'embed'  => ['src', 'type', 'allowscriptaccess', 'allowfullscreen', 'width', 'height', 'flashvars'],
            'iframe' => ['src', 'width', 'height', 'frameborder'],
            'script' => ['src']
          },
    
          :protocols => {
            'a'          => {'href' => ['ftp', 'http', 'https', 'mailto', :relative]},
            'blockquote' => {'cite' => ['http', 'https', :relative]},
            'img'        => {'src'  => ['http', 'https', :relative]},
            'q'          => {'cite' => ['http', 'https', :relative]}
          },
    
          :transformers => lambda { |env| next unless env[:node_name] == 'script'; unless (env[:node]['src'] && env[:node]['src'].include?('http://player.ooyala.com')); Sanitize.clean_node!(env[:node], {}); end; nil }
        }
      end
    end
    
    Sanitize.clean(html, Sanitize::Config::ULTRARELAXED)
    

答案 1 :(得分:0)

有时会出现一些错误,请确保您使用的是最新版本。

这是我为youtube iframe工作的(我认为)。在其他地方禁止iframe,然后:

T_YOUTUBE_IFRAME = lambda do |env|
node      = env[:node]
return nil unless env[:node_name] == 'iframe'

if node['src'] =~ /^http:\/\/www.youtube.com\/embed\//
  node['src'] += "?test" 

  return {:node_whitelist => [node]}
end
end