以下是否足以防止来自 HTML 元素内部的 XSS?
function XSS_encode_html ( $str )
{
$str = str_replace ( '&', "&", $str );
$str = str_replace ( '<', "<", $str );
$str = str_replace ( '>', ">", $str );
$str = str_replace ( '"', " "", $str );
$str = str_replace ( '\'', " '", $str );
$str = str_replace ( '/', "/", $str );
return $str;
}
Run Code Online (Sandbox Code Playgroud)
我没有使用 htmlspecialchars() 因为: -
/''(或')。根据 OWASP,'(单引号)应该变成'(叫我迂腐)并且
'不推荐,因为它不在 HTML 规范中
在元素的内容中,唯一可能有害的字符是开始标记分隔符,<因为它可能表示某些标记声明的开始,无论是开始标记、结束标记还是注释。所以那个字符应该总是被转义。
其他字符不一定需要在元素内容中转义。
引号只需要在标签内转义,特别是当用于包含在相同引号内或根本不引用的属性值时。类似地,标记声明关闭分隔符>只需要在标签内转义,这里仅当在未引用的属性值中使用时。但是,建议也转义普通的 & 符号,以避免它们被错误地解释为字符引用的开始。
现在至于替换的原因/,可能是由于 SGML 中的一个特性,标记语言 HTML 改编自,它允许所谓的空结束标记:
要了解空结束标签在实践中的工作原理,请考虑将其与可定义为的元素结合使用:
Run Code Online (Sandbox Code Playgroud)<!ELEMENT ISBN - - CDATA --ISBN number-- >而不是输入 ISBN 号:
Run Code Online (Sandbox Code Playgroud)<ISBN>0 201 17535 5</ISBN>我们可以使用 null end-tag 选项以缩短的形式输入元素:
Run Code Online (Sandbox Code Playgroud)<ISBN/0 201 17535 5/
但是,我从未见过任何浏览器实现过此功能。HTML 的语法规则一直比 SGML 语法规则更严格。
另一个更可能的原因是所谓的原始文本元素 ( scriptand style)的内容模型,它是具有以下限制的纯文本:
原始文本和 RCDATA 元素中的文本不得包含任何出现的字符串 "
</" (U+003C LESS-THAN SIGN, U+002F SOLIDUS) 后跟不区分大小写匹配元素标签名称的字符,后跟以下字符之一“制表符”(U+0009)、“LF”(U+000A)、“FF”(U+000C)、“CR”(U+000D)、U+0020 空格、“>”(U+003E) 或"/" (U+002F)。
这里说在原始文本元素中,例如script出现的</script/将表示结束标记:
<script>
alert(0</script/.exec("script").index)
</script>
Run Code Online (Sandbox Code Playgroud)
尽管 JavaScript 代码完全有效,但结束标记将用</script/. 但除此之外,/它不会受到任何伤害。而且,如果您只允许在 JavaScript 上下文中使用任意输入来转义 HTML,那您就已经注定要失败了。
顺便说一下,这些字符被转义为何种字符引用并不重要,无论是命名字符引用(即实体引用)还是数字字符引用,无论是十进制还是十六进制表示法。它们都引用了相同的字符。