
掌握ChatGPT插件與自定義GPT
頁面是什么樣子的。
它的 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 函數。此函數會捕獲輸入字段中的值。然后它會在輸入字段下方為用戶生成問候語。因此,如果您輸入姓名并點擊“提交”,您將獲得以下內容:
您將看到的問候語示例。
現在,這看起來似乎很安全,對吧?讓我們看一下執行所有這些操作的 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! ?????"));
現在,如果有人按下“提交”按鈕,就會執行警報功能:
您將看到的警報。
前面的示例是用 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 攻擊很可能這樣執行:
您將看到的警報。
但上述問題的解決方案很簡單:有一些糟糕的代碼需要重構。現在讓我們看看它。
在原始 JavaScript 示例中,您需要進行以下更改。不要使用append方法將一些文本附加到 DOM,而是使用textContent ,如下所示:
greetingBox.textContent =
Hey ${name}! A very good morning to you
;
上述代碼會產生相同的結果。如果攻擊者試圖向其中添加一些 JavaScript:
greetingBox.textContent =
alert('you are hacked!')
;
JavaScript 將在 HTML 頁面上呈現為字符串,而不是被執行:
攻擊者將看到的文本。
現在讓我們回到我們的 React 和 TypeScript 項目。有大量的錯誤代碼。我們直接操作 DOM 而不使用state和ref,這在這里確實很有用。
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 上輸出值。
我們已經看到了一種解決基于 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!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 ?????")';
現在,如果您嘗試單擊該鏈接,則不會出現警報。如果您轉到控制臺,您將看到類似以下內容:
消毒后您將看到的警告。
這就是如何在 Angular + TypeScript 應用程序中清理未清理的 HTML,以保護此類用例免受致命的 XSS 攻擊。您可以在我們關于該主題的指南中了解有關如何在 Angular 應用程序中防止 XSS 攻擊的更多信息。
XSS 漏洞最常出現在 DOM 操作中。如果您在操作 DOM 時非常謹慎,那么避免它們將輕而易舉。在頁面上直接輸出 HTML 時也必須小心謹慎。開發人員經常會忘記清理這些 HTML,從而導致 XSS 漏洞,攻擊者可能會利用這些漏洞對您的應用程序發起致命攻擊。
文章來源:Typescript XSS Guide: Examples and Prevention