常量
HTML_ESCAPE | = | { "&" => "&", ">" => ">", "<" => "<", '"' => """, "'" => "'" } |
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 & 3')
# => "1 < 2 & 3"
html_escape_once('<< Accept & Checkout')
# => "<< Accept & Checkout"
源代码: 显示 | 在 GitHub 上查看
# 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
操作,以便引号不会被转换为 "
实体。json_escape
不会自动将结果标记为 HTML 安全,因为原始值在 HTML 属性中使用是不安全的。
如果您的 JSON 被下游用于插入 DOM,请注意它是否通过 html()
插入。大多数 jQuery 插件都这样做。如果是这种情况,请确保对 JSON 返回的任何用户生成的内容进行 html_escape
或 sanitize
。
如果您需要在 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 的编码器)。
源代码: 显示 | 在 GitHub 上查看
# 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
源代码: 显示 | 在 GitHub 上查看
# 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