跨站脚本攻击(XSS)
概述
在Web应用程序中,有一些程序会处理用户输入内容或HTTP头信息,并将其作为Web页面输出,例如搜索关键词显示屏幕、个人信息注册确认屏幕、论坛、Web日志统计屏幕等。在这里,如果Web页面的输出处理存在问题,那么脚本等内容就可能被嵌入到该Web页面中。这个问题被称为“跨站脚本漏洞”,利用这个问题的攻击手段被称为“跨站脚本攻击”。跨站脚本攻击的影响不是针对网站本身,而是针对正在浏览该网站页面的用户。
可能发生的威胁
跨站脚本攻击可能带来的威胁如下:
在真实网站上显示虚假页面
- 通过传播虚假信息造成混乱
- 通过钓鱼诈骗泄露重要信息等
浏览器中保存的Cookie被获取
- 如果Cookie中存储了会话ID,可能会导致对用户的身份冒充
- 如果Cookie中存储了个人信息等,这些信息可能会泄露
任意Cookie被保存在浏览器中
- 会话ID被发送给用户,可能被用于“会话ID固定化”攻击
需要注意的网站特征
无论网站的运营主体或性质如何,这都是所有网站都需要关注的问题。特别是使用Cookie进行登录会话管理的网站以及容易成为钓鱼诈骗攻击目标的页面(登录页面、个人信息输入页面等)的网站需要特别注意。
容易出现这种漏洞的页面功能示例
- 显示输入内容以供确认的页面(会员注册、问卷调查等)
- 在要求重新输入错误信息时,显示先前输入内容的页面
- 搜索结果显示
- 错误显示
- 评论反馈(博客、论坛等)等
关于对策
针对跨站脚本漏洞的对策,根据Web应用程序的性质,可以分为以下三类:
1)不允许输入HTML文本的情况下的对策
适用于不允许输入HTML文本的Web应用程序的例子包括搜索功能和个人信息注册等,这 些应用程序不需要允许使用HTML标签等进行输入。大多数Web应用程序应该属于这一类。
2)允许输入HTML文本的情况下的对策
适用于允许输入HTML文本的Web应用程序的例子包括自由度较高的论坛和博客等。例如,为了实现用户可以指定输入字符的颜色和大小等功能,可能需要允许输入HTML文本。
3)适用于所有Web应用程序的通用对策
第三类对策是适用于1)和2)两种情况的Web应用程序的共同需要的措施。
不允许输入HTML文本的情况下的对策
根本解决方案
对所有输出到网页的元素进行转义处理
对于组成网页的元素,如网页正文和HTML标签的属性值等,对所有输出元素进行转义处理。转义处理包括将影响网页显示的特殊符号字符(如<
、>
、&
等)替换为HTML实体(如<
、>
、&
等)。此外,在输出HTML标签时,请确保始终用"
(双引号)括起属性值。然后,将包含在"
中的属性值中的"
转义为HTML实体"
。
从防止漏洞的角度来看,需要进行转义处理的包括外部传递给Web应用程序的“输入值”字符串、从数据库或文件中读取的字符串以及通过某种字符串操作生成的字符串等。然而,无论是必需的还是不必需的,对所有输出的文本进行一致的转义处理,可以防止策略遗漏。
需要注意的是,需要处理的输出不仅限于HTTP响应。在使用JavaScript的document.write方法或innerHTML属性等动态更改网页内容时,也需要进行类似的处理。
输出URL时,只允许以 “http://” 或 “https://” 开头的URL
URL不仅包括以http://
或https://
开头的,还包括以javascript:
格式开头的。如果输出到网页的链接或图片的URL依赖于外部输入而动态生成,当URL中包含脚本时,可能会发生跨站脚本攻击。例如,将用户输入的链接URL<a href="链接URL">
的格式输出到Web应用程序的网页,如果链接URL指定以javascript:
等开头的字符串,可能会被嵌入脚本。请使用“白名单方式”实施,仅允许链接URL以http://
或https://
开头的字符串。
不要动态生成<script>...</script>
元素的内容
如果输出到网页的<script>...</script>
元素内容依赖于外部输入而动态生成,可能会嵌入任意脚本。虽然可以考虑排除危险脚本的方法,但确定一个脚本是否危险是很困难的,因此建议避免动态生成<script>...</script>
元素内容的设计。
不允许从任意站点导入样式表
样式表中可以使用expression()等方式编写脚本。因此,如果设计允许从任意站点导入样式表,生成的网页可能会嵌入脚本。虽然可以检查导入的样式表内容并排除危险脚本,但确保完全排除是困难的,因此,避免从外部指定样式表的设计是可取的。
保险性措施
对输入值进行内容检查
对所有输入值进行处理,检查它们是否符合Web应用程序的规范。如果输入值不符合规范,则阻止进程继续进行,并要求重新输入。然而,这种措施的有效性是有限的。例如,如果应用程序的要求允许广泛的字符输入,则此措施将不起作用,因此不建议依赖此方法。
如果这种措施起作用的话,应用程序需要英文字母和数字输入,对于这种规范的输入内容检查,可以防止跨站脚本攻击的可能性较高。但是,在这种情况下,即使输入值通过了检查过程,仍然需要考虑到字符串操作结果可能会形成脚本字符串,因此仍然不是完全的解决方案。
允许HTML文本输入的措施
根本解决
对输入的HTML文本进行语法解析,并仅提取采用“白名单方式”的允许元素。然而,这要求复杂的编码,并对处理产生负担,因此实施前需要充分考虑。
保险措施
从输入的HTML文本中排除相应脚本字符串
从输入的HTML文本中提取与脚本相关的字符串并排除。建议将提取的字符串替换为无害字符串。例如,将<script>
或javascript:
替换为无害字符串,如<xscript>
和xjavascript:
,在字符串中添加适当的字符。还可以删除字 符串,但删除后可能会产生危险字符串,因此不建议。
需要注意的是,这种措施难以完全提取危险字符串。因为某些Web浏览器可能将java script:
或java(换行符)script:
等字符串解释为javascript:
,所以简单的模式匹配无法提取危险字符串。因此,不建议仅依赖这种“黑名单方式”的措施。
针对所有Web应用程序的通用措施
根本解决方案
在HTTP响应头的Content-Type字段中指定字符编码(charset)
在HTTP响应头的Content-Type字段中,可以指定字符编码(charset),例如:“Content-Type: text/html; charset=UTF-8”。如果省略此指定,浏览器将使用自己的方法推测字符编码,并根据推测的字符编码处理屏幕显示。例如,一些浏览器中已知的行为是,当HTML文本开头部分等包含特定字符串时,始终将其处理为特定字符编码。
如果在Content-Type字段中省略字符编码的指定,攻击者可能利用这种行为,故意嵌入 使浏览器选择特定字符编码的字符串,以及在以该字符编码解释时成为脚本标签的字符串。
例如,具体来说,可以考虑HTML文本中嵌入+ADw-script+AD4-alert(+ACI-test+ACI-)+ADsAPA-/script+AD4-
这样的字符串。在这种情况下,某些浏览器将其识别为用“UTF-7”字符编码编码的字符串。当这个字符串以UTF-7显示在屏幕上时,它会被处理为<script>alert('test');</script>
,因此脚本将被执行。
即使Web应用程序正确实施了转义处理,也可以应对跨站点脚本(XSS)漏洞,但如果原始目标字符被处理为UTF-8、EUC-JP、Shift_JIS等字符编码,那么“+ADw-”等字符串将不会被“转义处理”。
解决此问题的方案之一是,在“转义处理”过程中也应用UTF-7处理,但仅考虑UTF-7并不能保证万无一失。此外,基于UTF-7进行“转义处理”的结果可能导致有效字符串(例如,“+ADw-”字符串)变为另一个字符串,从而导致原始功能出现故障。
因此,解决此问题的方法是在输出Content-Type时始终指定charset,而不是省略它。请务必在Content-Type的charset中指定Web应用程序在输出HTML时所预期的字符编码。