跨站脚本攻击漏洞(编码)
注意:请参考教程“保护应用程序免受跨站点脚本(XSS)攻击”以使用开发人员沙箱。 该教程中的代码段向您展示了如何使用转义序列,以使任何注入的代码都无法运行。
跨站点脚本攻击
在跨站点脚本(XSS)攻击中,攻击者将恶意代码注入到合法的网页中,然后该网页运行恶意的客户端脚本。 当用户访问受感染的网页时,脚本将下载到用户的浏览器并从其运行。 此方案有很多变体。 恶意脚本可能访问浏览器cookie,会话令牌或浏览器保留的其他敏感信息。 但是,所有XSS攻击都遵循图1所示的模式。
图1.典型的XSS攻击
XSS漏洞
在典型的XSS攻击中,攻击者找到了一种在服务器的网页中插入字符串的方法。 假设攻击者向网页中注入了以下字符串: <script>alert("attacked")</script>
。 最终用户每次访问此页面时,其浏览器都会下载此脚本并在呈现页面时运行该脚本。 在这种情况下,脚本将运行,并且用户会看到一个弹出警报,提示“已攻击”。
XSS的影响
当攻击者成功利用Web应用程序中的XSS漏洞时,他们可以插入脚本,使他们能够访问最终用户的帐户凭据。 攻击者可以执行各种恶意活动,例如:
- 劫持帐户
- 传播网络蠕虫
- 访问浏览器历史记录和剪贴板内容
- 远程控制浏览器
- 扫描和利用Intranet设备和应用程序
防止XSS攻击
为了帮助防止XSS攻击,应用程序需要确保将页面中的所有变量输出编码后再返回给最终用户。 编码变量输出用称为实体的替代表示替代HTML标记。 浏览器显示实体,但不运行它们。 例如, <script>
转换为<script>
。
表1显示了一些常见HTML字符的实体名称。
表1. HTML字符的实体名称
结果 | 描述 | 实体名称 | 实体编号 |
---|---|---|---|
不间断空间 | &nbsp; | &#160; | |
< | 少于 | &lt; | &#60; |
> | 比...更棒 | &gt; | &#62; |
和 | &符 | &amp; | &#38; |
¢ | 分 | &cent; | &#162; |
£ | 磅 | &磅; | &#163; |
¥ | 日元 | &日元; | &#165; |
欧元 | &欧元; | &#8364; | |
§ | 部分 | &教派; | &#167; |
© | 版权 | &复制; | &#169; |
® | 注册商标 | &reg; | &#174 |
™ | 商标 | &trade; | &#8482; |
当Web浏览器遇到这些实体时,它们将被转换回HTML并打印出来,但是将不会运行。 例如,如果攻击者将<script>alert("you are attacked")</script>
注入服务器网页的变量字段中,则服务器将使用此策略返回<script>alert("you are attacked")</script>
。
当网络浏览器下载编码脚本时,它将编码脚本转换回<script>alert("you are attacked")</script>
并将该脚本显示为网页的一部分,但浏览器不会运行该脚本。
将HTML代码添加到服务器端Java应用程序
为确保恶意脚本代码不会作为页面的一部分输出,您的应用程序需要对所有可变字符串进行编码,然后才能在页面上显示它们。 编码只是将每个字符转换为其HTML实体名称,如清单1中的Java代码示例所示。
清单1.将字符转换为HTML实体名称
public class EscapeUtils {
public static final HashMap m = new HashMap();
static {
m.put(34, """); // < - less-than
m.put(60, "<"); // < - less-than
m.put(62, ">"); // > - greater-than
//User needs to map all html entities with their corresponding decimal values.
//Please refer to below table for mapping of entities and integer value of a char
}
public static String escapeHtml() {
String str = "<script>alert(\"abc\")</script>";
try {
StringWriter writer = new StringWriter((int)
(str.length() * 1.5));
escape(writer, str);
System.out.println("encoded string is " + writer.toString() );
return writer.toString();
} catch (IOException ioe) {
ioe.printStackTrace();
return null;
}
}
public static void escape(Writer writer, String str) throws IOException {
int len = str.length();
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
int ascii = (int) c;
String entityName = (String) m.get(ascii);
if (entityName == null) {
if (c > 0x7F) {
writer.write("&#");
writer.write(Integer.toString(c, 10));
writer.write(';');
} else {
writer.write(c);
}
} else {
writer.write(entityName);
}
}
}
}
在清单1的Java示例中,对于HTML编码,输入为String "<script>alert(\"abc\")</script>"
。 使用以下步骤。
- 创建所有HTML实体及其十进制值的哈希图。 该示例仅显示三个条目。 您需要在此映射中映射所有HTML实体及其十进制值。 表2显示了一些常用的实体及其十进制值。 对于所有字符实体的完整参考,请参见HTML实体参考资源 。
- 创建缓冲区的
StringWriter
,其大小为输入字符串长度的1.5倍。 - 将此写程序和输入字符串都传递给
escape
方法,该方法逐一拾取字符串中的每个字符并获取该字符的整数值。 - 将整数值传递给您在步骤1中创建的映射,获取实体名称,然后将此值写在writer上。
字符串的每个字符都将转换为其实体名称。
输出是<script>alert("abc")</script>
。
表2将HTML实体映射到其十进制值。
表2. HTML实体的十进制值
小数 | 实体 | 描述 |
---|---|---|
160 | &nbsp; | 不间断空间 |
60 | &lt; | 少于 |
62 | &gt; | 比...更棒 |
38 | &amp; | &符 |
162 | &cent; | 分 |
163 | &磅; | 磅 |
165 | &日元; | 日元 |
8364 | &欧元; | 欧元 |
167 | &教派; | 部分 |
169 | &复制; | 版权 |
174 | &reg; | 注册商标 |
8482 | &trade; | 商标 |
结论
跨站点脚本编写仍然是攻击用户计算机的最常用方法之一。 但是,您可以在很大程度上消除攻击者使用恶意代码感染Web应用程序的能力。 在编写应用程序时,请先对页面中的所有变量输出进行编码,然后再将其发送到最终用户的浏览器。
翻译自: https://www.ibm.com/developerworks/security/library/se-prevent/index.html
跨站脚本攻击漏洞(编码)