跳至内容 跳至搜索
方法
H
J
X

常量

HTML_ESCAPE = { "&" => "&amp;", ">" => "&gt;", "<" => "&lt;", '"' => "&quot;", "'" => "&#39;" }
 
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
 
INVALID_TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_FOLLOWING_CODEPOINTS}]/
 
INVALID_TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_CODEPOINTS}]/
 
SAFE_XML_TAG_NAME_REGEXP = /\A[#{TAG_NAME_START_CODEPOINTS}][#{TAG_NAME_FOLLOWING_CODEPOINTS}]*\z/
 
TAG_NAME_FOLLOWING_CODEPOINTS = "#{TAG_NAME_START_CODEPOINTS}\\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}"
 
TAG_NAME_REPLACEMENT_CHAR = "_"
 
TAG_NAME_START_CODEPOINTS = "@:A-Z_a-z\u{C0}-\u{D6}\u{D8}-\u{F6}\u{F8}-\u{2FF}\u{370}-\u{37D}\u{37F}-\u{1FFF}" \ "\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \ "\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
 

遵循 XML 规范: www.w3.org/TR/REC-xml/#NT-Name

类公开方法

html_escape_once(s)

一个用于转义 HTML 而不影响现有转义实体的实用方法。

html_escape_once('1 < 2 &amp; 3')
# => "1 &lt; 2 &amp; 3"

html_escape_once('&lt;&lt; Accept & Checkout')
# => "&lt;&lt; Accept &amp; Checkout"
# File activesupport/lib/active_support/core_ext/erb/util.rb, line 63
def html_escape_once(s)
  ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE).html_safe
end

json_escape(s)

一个用于转义 JSON 字符串中 HTML 实体的实用方法。具体来说,&、> 和 < 字符被替换为其等效的 Unicode 转义形式 - u0026、u003e 和 u003c。Unicode 序列 u2028 和 u2029 也被转义,因为它们在一些 JavaScript 引擎中被视为换行符。这些序列在 JSON 字符串的上下文中与原始字符具有相同的含义,因此假设输入是一个有效的、格式良好的 JSON 值,输出在解析时将具有等效的含义。

json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
# => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"

json_escape(json)
# => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"

JSON.parse(json) == JSON.parse(json_escape(json))
# => true

此方法的预期用例是在将 JSON 字符串包含在脚本标签内之前对其进行转义,以避免 XSS 漏洞。

<script>
  var currentUser = <%= raw json_escape(current_user.to_json) %>;
</script>

有必要对 json_escape 的结果进行 raw 操作,以便引号不会被转换为 &quot; 实体。json_escape 不会自动将结果标记为 HTML 安全,因为原始值在 HTML 属性中使用是不安全的。

如果您的 JSON 被下游用于插入 DOM,请注意它是否通过 html() 插入。大多数 jQuery 插件都这样做。如果是这种情况,请确保对 JSON 返回的任何用户生成的内容进行 html_escapesanitize

如果您需要在 HTML 中的其它地方输出 JSON,您可以像这样操作,因为任何不安全的字符(包括引号)都会自动为您转义。

<div data-user-info="<%= current_user.to_json %>">...</div>

警告:此帮助程序仅适用于有效的 JSON。在非 JSON 值上使用它会导致严重的 XSS 漏洞。例如,如果您将上面示例中的 current_user.to_json 替换为用户输入,浏览器将很乐意将该字符串作为 JavaScript 进行 eval()

此方法执行的转义与 ActiveSupport.escape_html_entities_in_json 设置为 true 时 Active Support JSON 编码器执行的转义相同。由于此转换是幂等的,即使 ActiveSupport.escape_html_entities_in_json 已经为 true,也可以应用此帮助程序。

因此,当您不确定 ActiveSupport.escape_html_entities_in_json 是否已启用,或者不确定 JSON 字符串的来源时,建议您始终应用此帮助程序(其他库,例如 JSON gem,默认情况下不提供这种保护;此外,一些 gem 可能会覆盖 to_json 以绕过 Active Support 的编码器)。

# File activesupport/lib/active_support/core_ext/erb/util.rb, line 124
def json_escape(s)
  result = s.to_s.dup
  result.gsub!(">", '\u003e')
  result.gsub!("<", '\u003c')
  result.gsub!("&", '\u0026')
  result.gsub!("\u2028", '\u2028')
  result.gsub!("\u2029", '\u2029')
  s.html_safe? ? result.html_safe : result
end

xml_name_escape(name)

一个用于转义标签的 XML 名称和属性名称的实用方法。

xml_name_escape('1 < 2 & 3')
# => "1___2___3"

它遵循规范的要求: www.w3.org/TR/REC-xml/#NT-Name

# File activesupport/lib/active_support/core_ext/erb/util.rb, line 142
def xml_name_escape(name)
  name = name.to_s
  return "" if name.blank?
  return name if name.match?(SAFE_XML_TAG_NAME_REGEXP)

  starting_char = name[0]
  starting_char.gsub!(INVALID_TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)

  return starting_char if name.size == 1

  following_chars = name[1..-1]
  following_chars.gsub!(INVALID_TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)

  starting_char << following_chars
end