所有文章 > 技术杂货铺 > Typescript跨站脚本指南:示例及预防
Typescript跨站脚本指南:示例及预防

Typescript跨站脚本指南:示例及预防

TypeScript 已经走过了漫长的道路,成为现代 Web 开发技术堆栈的一部分,无论是前端还是后端。转向 TypeScript 的开发人员几乎从不后悔!然而,即使你掌握了一门强大的编程语言,你也可能会遇到最基本的安全警告。 

TypeScript 是 React 和 Angular 等现代前端框架的强力补充。但是,它不会自动保护您的代码免受 DOM 漏洞的侵害。事实上,很多时候,开发人员没有充分利用 TypeScript,导致他们的代码库容易受到 DOM XSS 攻击。其他时候,他们只是不知道什么是 XSS,并成为恶意攻击者向他们的 DOM 注入恶意 JavaScript 的牺牲品。 

因此,在这篇文章中,我将讨论什么是 XSS 以及 XSS 攻击是如何发生的。然后,我将向您展示如何在 TypeScript 项目中防止 XSS 攻击。

什么是 XSS?

XSS 代表“跨站点脚本”。这是一种将外部 JavaScript 注入网站的技术。我们网站的大部分逻辑(包括动画和用户交互)都归属于我们网站的 JavaScript。即使您在运行时使用 TypeScript 来构建 React 或 Angular 项目,最终,所有这些 TypeScript 都会被编译为 JavaScript。

当您的应用程序留下漏洞,允许攻击者运行一些您未授权的 JavaScript 时,您的网站就会受到 XSS 攻击。该漏洞本身就是应用程序的 XSS 漏洞。但 XSS 漏洞是什么样子的?XSS 攻击究竟是如何发生的?

XSS 攻击是如何发生的?

让我们举一个简单的网站示例,您在其中填写表单。为简洁起见,我有一个简单的CodeSandbox 示例,它在页面上呈现一个输入字段和一个提交按钮。页面显示如下:

Typescript XSS 指南:示例及预防 - 图片 2

页面是什么样子的。

它的 HTML 内容如下:

<!DOCTYPE html>
<html>
<head>
<title>XSS Attack Example</title>
<meta charset="UTF-8" />
</head>

<body>
<div id="app">
<h1>Enter your name</h1>
<input type="text" />
<button>Greet Me!</button>
<div id="greeting"></div>
</div>

<script src="src/index.js"></script>
</body>
</html>

当用户输入姓名并按下“提交”按钮时,我们会运行一个简单的 JavaScript 函数。此函数会捕获输入字段中的值。然后它会在输入字段下方为用户生成问候语。因此,如果您输入姓名并点击“提交”,您将获得以下内容:

Typescript XSS 指南:示例及预防 - 图片 3 图片

您将看到的问候语示例。

现在,这看起来似乎很安全,对吧?让我们看一下执行所有这些操作的 JavaScript 代码:

import "./styles.css";

const input = document.querySelector("input");
const submitButton = document.querySelector("button");
const greetingBox = document.querySelector("#greeting");

function onClick() {
const name = input.value;
greetingBox.append(`Hey ${name}! A very good morning to you`);
}

submitButton.addEventListener("click", onClick);

如果仔细观察我们操作 DOM 的位置,就会发现我们正在使用append方法在 DOM 元素上附加一些新 HTML。这听起来安全吗?

其实不然!它是 XSS 漏洞的滋生地。所有这些 JavaScript 代码都可以通过浏览器供任何人使用,因此我可以继续修改该行,如下所示:

  greetingBox.append(alert("you are hacked! 🐱‍💻"));

现在,如果有人按下“提交”按钮,就会执行警报功能:

Typescript XSS 指南:示例及预防 - 图片 4 图片

您将看到的警报。

TypeScript 中的 XSS 示例

前面的示例是用 JavaScript 编写的,但其 TypeScript 对应部分也不会有太大不同。为了演示,我们以 React with TypeScript 项目为例,我们可以在其中复制上述场景。 

以下是供您参考的示例。我们只有一个简单的 React 应用程序,其中的App.ts文件中包含以下代码:

import "./styles.css";

export default function App() {
const handleSubmit = () => {
const inputDOM: HTMLElement | null = document.querySelector<
HTMLInputElement
>("input");
const inputVal: string = inputDOM?.value;
const greetingBox = document.getElementById<HTMLElement>("greeting");
greetingBox?.append(inputVal);
};
return (
<div className="App">
<h2>XSS in Typescript + React</h2>
<input />
<button onClick={handleSubmit}>Submit</button>
<div id="greeting"></div>
</div>
);
}

如果您查看我们所有的函数和 DOM 操作,就会发现我们正在使用完整的 TypeScript,而不是普通的旧 JavaScript!但是,我们操作 DOM 的方式仍然不正确。它仍然暴露了 DOM XSS 漏洞。这意味着仅使用 TypeScript 不会有帮助。 

在上面的代码库中,假设攻击者设法注入一个脚本并以编程方式执行该脚本:

...
greetingBox?.append(alert("you are hacked! 🐱‍💻"));
...

XSS 攻击很可能这样执行:

Typescript XSS 指南:示例及预防 - 图片 5 图片

您将看到的警报。

但上述问题的解决方案很简单:有一些糟糕的代码需要重构。现在让我们看看它。

防止 TypeScript 项目中出现 XSS

在原始 JavaScript 示例中,您需要进行以下更改。不要使用append方法将一些文本附加到 DOM,而是使用textContent ,如下所示: 

  greetingBox.textContent = `Hey ${name}! A very good morning to you`;

上述代码会产生相同的结果。如果攻击者试图向其中添加一些 JavaScript: 

  greetingBox.textContent = `alert('you are hacked!')`;

JavaScript 将在 HTML 页面上呈现为字符串,而不是被执行:

Typescript XSS 指南:示例及预防 - 图片 6 图片

攻击者将看到的文本。

现在让我们回到我们的 React 和 TypeScript 项目。有大量的错误代码。我们直接操作 DOM 而不使用stateref,这在这里确实很有用。

import "./styles.css";
import { useState } from "react";

export default function App() {
const [name, setName] = useState<String>("");

const handleSubmit = () => {
const inputDOM: HTMLElement | null = document.querySelector<
HTMLInputElement
>("input");
const inputVal: string = inputDOM?.value;
const greetingBox = document.getElementById<HTMLElement>("greeting");
setName(inputVal);
// greetingBox?.append(inputVal);
// greetingBox?.append(alert("you are hacked! 🐱‍💻"));
};

return (
<div className="App">
<h2>XSS in Typescript + React</h2>
<input />
<button onClick={handleSubmit}>Submit</button>
<div id="greeting">{name}</div>
</div>
);
}

我们不使用append方法,而是简单地将输入字段的值设置为状态的值。然后我们使用此状态在 DOM 上输出值。 

未清理的 HTML 可能导致 XSS 攻击

我们已经看到了一种解决基于 DOM 的 XSS 漏洞的方法。但是,如果您绝对需要在容器内设置 HTML,该怎么办?例如,您可以有一个富文本编辑器,它会将格式化的文本保存在数据库中。但是,当此文本返回时,它会附带相关的 HTML 标签。 

或者在其他情况下,您的服务器可能会返回 TypeScript 应用程序需要呈现的某些动态链接的 href。在这种情况下,您也需要以编程方式操作 DOM。 

为简洁起见,我们考虑这样一种场景:您的后端返回 Angular + TypeScript 应用程序呈现的链接的 href。以下是该组件的 HTML 部分:

<div>
<h3>
Welcome to XSS with Typescript in Angular!
</h3>
<a class="link">Click</a>
</div>

在其component.ts文件中,我们可以设置<a>标签的href属性。操作如下:

import { Component, Renderer2, ElementRef } from "@angular/core";

@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
constructor(private renderer: Renderer2, private el: ElementRef) {}
url: string = "https://google.com";
private get host(): HTMLElement {
return this.el.nativeElement;
}
ngOnInit() {
const link = this.getLink(".link");
this.renderer.setAttribute(link, "href", this.url);
}

private getLink(selector: string): HTMLAnchorElement {
return this.host.querySelector(selector);
}
}

如果您点击上述链接,您应该会被重定向到 google.com。但在这种情况下,想象一下 href 来自 API 请求。在这种情况下,攻击者可以轻松地将 URL 的 href 操纵为: 

  url: string = 'javascript:alert("you are hacked 🐱‍💻")';

现在我们又回到了原点!我们的 Angular + TypeScript 应用程序存在 XSS 漏洞。那么我们现在该怎么办?

净化 HTML 以防止 XSS 攻击

好了,我们应该清理一下 HTML!Angular 在其 platform-b​​rowser 模块中提供了一个名为 DomSanitizer 的库。我们可以像这样 将其导入到我们的component.ts文件中:

import { DomSanitizer } from "@angular/platform-browser";

在我们的构造函数中创建它的引用:

  constructor(
...
private DomSanitizer: DomSanitizer,
...
)
{}

现在,我们可以使用 DomSanitizer 根据特定规则清理任何 HTML。由于我们想要清理 HTML URL,因此可以使用 Angular 核心模块中的 SecurityContext 模块。

import { SecurityContext } from '@angular/core';

最后,我们现在可以像这样清理我们的 URL:

url: string =this.DomSanitizer.sanitize(SecurityContext.URL, 'javascript:alert("you are hacked 🐱‍💻")';

现在,如果您尝试单击该链接,则不会出现警报。如果您转到控制台,您将看到类似以下内容:

Typescript XSS 指南:示例及预防 - 图片 7

消毒后您将看到的警告。

这就是如何在 Angular + TypeScript 应用程序中清理未清理的 HTML,以保护此类用例免受致命的 XSS 攻击。您可以在我们关于该主题的指南中了解有关如何在 Angular 应用程序中防止 XSS 攻击的更多信息。

结论

XSS 漏洞最常出现在 DOM 操作中。如果您在操作 DOM 时非常谨慎,那么避免它们将轻而易举。在页面上直接输出 HTML 时也必须小心谨慎。开发人员经常会忘记清理这些 HTML,从而导致 XSS 漏洞,攻击者可能会利用这些漏洞对您的应用程序发起致命攻击。

文章来源:Typescript XSS Guide: Examples and Prevention

#你可能也喜欢这些API文章!