公司将应用程序移动到Web上,以改善客户互动,降低业务处理成本并加快结果的速度。但是这样做也会增加漏洞-除非安全性是应用程序开发过程中不可或缺的组成部分。要了解有关在组织中创建安全文化的更多信息,请下载并阅读“安全Web应用程序:创建安全文化”。
在跨站点脚本(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; |
当网络浏览器遇到实体时,它们将被转换回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实体名称
在清单1的Java示例中,对于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 “”。使用以下步骤。
1、创建所有HTML实体及其十进制值的哈希图。该示例仅显示三个条目。您需要在此映射中映射所有HTML实体及其十进制值。表2显示了一些常用的实体及其十进制值。对于所有字符实体的完整参考,请参见HTML实体参考资源。
2、创建一个StringWriter1.5倍于输入字符串长度的缓冲区。
3、将此写程序和输入字符串都传递给该escape 方法,该方法一个接一个地拾取字符串的每个字符,并获取该字符的整数值。
将整数值传递给您在步骤1中创建的映射,获取实体名称,然后将此值写在writer上。
4、字符串的每个字符都将转换为其实体名称。
输出为
<script>alert("abc")</script>
// 正如上文所言当浏览器加载该结果时,会自动转化为<script>alert(\"abc\")</script>,但是并不会执行该脚本
跨站点脚本编写仍然是攻击用户计算机的最常用方法之一。但是,您可以在很大程度上消除攻击者使用恶意代码感染Web应用程序的能力。在编写应用程序时,请先对页面中的所有变量输出进行编码,然后再将其发送到最终用户的浏览器。
原文地址:https://www.ibm.com/developerworks/library/se-prevent/index.html