为什么要进行特殊字符转义及编码?
在 HTML 中,有一些特殊字符不可直接使用,需要使用转义字符或实体编码来表示。这是为了避免这些字符与 HTML 标签和语法产生冲突。同时,也是为了防范前端 XSS。
例如,有些特殊字符(如 <
和 >
)作为 HTML 标签的一部分,要是没有被特殊处理可能被恶意 XSS。
前端 XSS 的危害及转义用处
HTML 的特殊字符转义及编码在防范跨站脚本攻击(Cross-Site Scripting, XSS)方面起到关键作用。XSS 是一种常见的安全漏洞,攻击者通过在受信任网站上插入恶意脚本,使其在用户浏览器中执行。
HTML 的特殊字符转义及编码的作用如下:
(1)阻止脚本注入:
假设一个博客网站允许用户发表评论,并将评论内容直接显示在页面上。如果没有进行转义或编码处理,攻击者可以在评论中插入恶意脚本。例如:
用户评论:<script>alert('XSS Attack');</script>
如果评论内容未经过转义或编码,这段恶意脚本将在其他用户浏览该页面时被执行。
接下来以 XSS-Labs 靶场为例,成功执行 XSS 时将弹窗 “完成的不错”
由于后端无任何过滤及转义处理,可以看到,XSS 语句执行成功:
然而,通过将特殊字符转义为实体编码,将评论内容显示为普通文本,如下所示:
<script>alert('XSS Attack');</script>
这样,评论内容不再被解释为可执行的脚本,保护了页面和用户的安全。
(2)防止 HTML 标签和属性的滥用:
假设一个社交媒体网站允许用户在个人简介中添加自我介绍。如果用户输入的内容未经过转义或编码处理,并且在个人简介页面上直接显示,那么攻击者可以在自我介绍中插入恶意 HTML 标签或属性。例如:
用户输入:<img src="javascript:alert('XSS Attack');" />
如果该内容未经过任何处理,则图像标签会被解释并执行其中的 JavaScript 代码。
举个例子:
通过将特殊字符转义为实体编码,将自我介绍内容显示为普通文本,如下所示:
<img src="javascript:alert('XSS Attack');" />
这样,HTML 标签和属性不再被解析为可执行的代码,保护了页面和用户的安全。
同时,我们可以看到,在一些程序中,输入 XSS 语句之后并不会被转义,也不会被执行:
这是运用了更高级 XSS 防护技术的缘故。
(3)防止 URL 注入:
假设一个电子商务网站允许用户在评论中包含链接,并直接将这些链接显示在页面上。如果 URL 未经过适当的编码处理,攻击者可以在 URL 中注入恶意脚本或其他恶意内容。例如:
用户评论:https://www.example.com?param=<script>alert('XSS Attack');</script>
如果该评论未经过任何处理,链接将会被解释并执行其中的 JavaScript 代码。
通过对 URL 进行编码,如下所示:
https://www.example.com?param=%3Cscript%3Ealert('XSS%20Attack')%3C/script%3E
这样,URL 中的特殊字符被转义为实体编码,防止了恶意代码的执行。
(4)XSS 过滤器的辅助作用:
例如,当浏览器检测到页面中的特殊字符被正确转义或编码时,它们会将其视为纯文本,不会将其解析为 HTML 标签或脚本。这有助于识别和阻止潜在的 XSS 攻击。
下面列举两个常见的浏览器 XSS 过滤器:
1.Chrome 浏览器:
- XSS Auditor:Chrome 浏览器内置了名为 XSS Auditor 的过滤器,它尝试检测和阻止反射型 XSS 攻击。
- Sanitizer:Chrome 还使用了一种 HTML Sanitizer 来处理和过滤用户输入,以防止 XSS 攻击。
2.Firefox 浏览器:
- Content Security Policy (CSP):Firefox 支持 Content Security Policy,这是一种通过声明策略限制内容加载和执行的机制。CSP 可用于阻止 XSS 攻击。
- 部分自动 XSS 过滤:Firefox 也提供了一些内置的自动 XSS 过滤功能,用于检测和阻止潜在的 XSS 攻击。
如何进行特殊字符转义及编码?
(1)使用内置函数或方法:
大多数编程语言和框架提供了内置的函数或方法来进行字符转义和编码。例如:
- 在 JavaScript 中,可以使用
encodeURIComponent()
或encodeURI()
来对 URL 进行编码,使用innerHTML
或innerText
属性来进行 HTML 转义。 - 在 PHP 中,可以使用
htmlspecialchars()
或htmlentities()
来进行 HTML 转义。 - 在 Java 中,可以使用
URLEncoder.encode()
来对 URL 进行编码,使用StringEscapeUtils.escapeHtml()
来进行 HTML 转义。
举个使用内置函数或方法的例子(JavaScript):
// URL编码
let url = 'https://www.example.com/?param=' + encodeURIComponent('<script>alert("XSS Attack");</script>');
console.log(url);
// 输出:https://www.example.com/?param=%3Cscript%3Ealert(%22XSS%20Attack%22);%3C/script%3E
// HTML转义
let userInput = '<script>alert("XSS Attack");</script>';
let escapedHtml = document.createElement('div');
escapedHtml.textContent = userInput;
console.log(escapedHtml.innerHTML);
// 输出:<script>alert("XSS Attack");</script>
(2)使用专门的编码库:
有一些专门用于字符转义和编码的开源库,可以提供更强大和全面的功能。例如:
- OWASP Java Encoder:适用于 Java 的开源库,提供各种编码器和解码器,用于对 URL、HTML、JavaScript 等进行编码和解码。
- PHP HTML Purifier:适用于 PHP 的开源库,用于过滤和转义 HTML,以防止 XSS 攻击。
- Python Bleach:适用于 Python 的开源库,提供 HTML 标签过滤、标签属性过滤和标签内容转义等功能。
举个例子(Java):
import org.owasp.encoder.Encode;
// URL编码
String url = "https://www.example.com/?param=" + Encode.forUriComponent("<script>alert(\"XSS Attack\");</script>");
System.out.println(url);
// 输出:https://www.example.com/?param=%3Cscript%3Ealert(%22XSS%20Attack%22);%3C/script%3E
// HTML转义
String userInput = "<script>alert(\"XSS Attack\");</script>";
String escapedHtml = Encode.forHtml(userInput);
System.out.println(escapedHtml);
// 输出:<script>alert("XSS Attack");</script>
(3)手动实现转义规则:
可以创建自定义的转义表或函数来执行特殊字符的转义。这需要仔细研究和了解特殊字符的转义规则,并编写相应的代码来替换字符。
转义时应考虑多重编码:当字符传输经过多个层级或环节时,确保在每个层级或环节上都进行了正确的编码和转义处理。
常见的特殊字符转义及编码
- 小于号
<
:
- 转义形式:
<
- 实体编码:
<
- 大于号
>
:
- 转义形式:
>
- 实体编码:
>
- 和符号
&
:
- 转义形式:
&
- 实体编码:
&
- 双引号
"
:
- 转义形式:
"
- 实体编码:
"
- 单引号
'
:
- 转义形式:
'
- 实体编码:
'
- 版权符号
©
:
- 转义形式:
©
- 实体编码:
©
- 注册商标符号
®
:
- 转义形式:
®
- 实体编码:
®
- 省略号
…
:
- 转义形式:
…
- 实体编码:
…
- 非断空格(不换行空格):
- 转义形式:
- 实体编码:
 
- 破折号
–
:
- 转义形式:
–
- 实体编码:
–
在 HTML 中,使用转义字符或实体编码确保这些字符正确地显示而不会被解析为 HTML 标签或语法。