一個簡單的腳本——一個微不足道的視覺效果——會為你的應用程式帶來風險嗎?
哦,是的。而且你可能根本意識不到是怎麼回事。
更糟的是,看似不起眼的小程式碼片段,竟然可以變成閃閃發光的計時炸彈。這怎麼可能?
讓我告訴你一個假設的故事。
想像一下,你開發了一個網站、一個網店或一個網頁應用程式。
十二月來臨了。到處都是彩燈、聖誕樹和裝飾品。節日的氣氛開始瀰漫開來。
您(或您的某個利害關係人)要求加入一些當季的小裝飾。
「也許會下雪?」❄️
你很興奮,立刻投入這項極具創意的任務。
但是等等。
積壓的工作堆積如山,截止日期迫在眉睫。突然,你想起了一件重要的事:
你太懶了。 😉
你顯然不會從零開始寫這篇文章。
所以你就做了我們所有人都會做的事:
你打開 CodePen、GitHub,或是 Stack Overflow……然後複製一段隨機的程式碼片段。
<script>
/**
* ❄️ Simple snow effect
* Source: random blog / CodePen
*/
const snowflakes = ["❄️", "❅", "❆"];
for (let i = 0; i < 40; i++) {
const el = document.createElement("div");
el.className = "snowflake";
// ❌ copied straight from the internet
el.innerHTML =
snowflakes[Math.floor(Math.random() * snowflakes.length)];
el.style.left = Math.random() * 100 + "vw";
el.style.fontSize = 12 + Math.random() * 24 + "px";
el.style.animationDuration = 5 + Math.random() * 5 + "s";
document.body.appendChild(el);
}
</script>
五分鐘後——砰——美麗的雪花飄落效果就出現了。

你甚至都沒把它提交上來進行正規的程式碼審查。
或者有人會匆匆瞥一眼,因為——這只是視覺效果,對吧?
安全測試?
誰會去測試飄落的雪花呢?
問題就在這裡:
el.innerHTML = snowflake;
XSS(跨站腳本攻擊)是指將不受信任的資料以允許其作為 HTML 或 JavaScript 執行的方式註入 DOM 中。
重要澄清:目前,這段程式碼還不是活躍的 XSS 漏洞,因為snowflake來自一個硬編碼的、完全可信的陣列。
然而,危險的模式已經形成——這使得它變成了一顆定時炸彈。
目前來看,一切平安無事。
一切看起來都正常。
一月到了。管理階層決定是時候關閉視覺特效了。
“但別把它拿走!”
“我們明年就需要它了!”
或許更早──春天就要來了,所以與其飄落雪花,不如讓花瓣飄落吧🌸。
一項新任務被加入到待辦事項清單中。
另一位開發者拿起它,心想:
“我不會每隔幾個月就切換一次這個設定。”
讓管理層自己掌控——甚至可以讓他們選擇圖標。 」
所以他們新增了配置項。
或許透過內容管理系統(CMS),或許透過遠端端點。
function fetchSeasonalConfig() {
return Promise.resolve({
enabled: true,
snowflake: "❄️"
});
}
fetchSeasonalConfig().then(config => {
if (!config.enabled) return;
for (let i = 0; i < 30; i++) {
const el = document.createElement("div");
el.className = "snowflake";
// ❌ still innerHTML
el.innerHTML = config.snowflake;
document.body.appendChild(el);
}
});
現在大門已經敞開了。
此時,該值跨越了信任邊界:它不再來自程式碼中定義的常數,而是來自可以獨立於應用程式邏輯而改變的外部來源。
攻擊者不需要任何花俏的東西:
CMS帳戶被盜用
角色配置錯誤
以及一個所見即所得編輯器
從 Notion 或電子郵件複製的片段
被攔截或修改的 API 回應
例如:
snowflake: '<img src=x onerror="alert(\'XSS 🎄\')">'
就這樣。
您的應用程式存在完整的 XSS 漏洞。
你們當中有些人現在可能在想:
“拜託。這適用於舊的 jQuery 網站。”
我使用現代框架——React/Angular/Vue——它可以保護我免受XSS攻擊。
事實並非如此。
React 和 Angular 預設會對內容進行轉義——但僅限於它們的渲染系統內部。
你使用時的那一刻:
innerHTML
dangerouslySetInnerHTML (React)
[innerHTML]或bypassSecurityTrustHtml (Angular)
或在框架之外執行的純 JS 腳本
……你只能靠自己了。
你猜怎麼著?
那個雪景腳本?
它通常位於框架之外,在index.html中,作為“小型視覺效果”加載。
框架不會對隨機的 JavaScript 檔案進行沙盒隔離。
這一切原本都可以透過一個簡單的改變來避免:
el.textContent = snowflake;
或透過:
明確建立 DOM 節點,而不是注入 HTML
使用維護良好的程式庫(例如 DOMPurify,並進行正確配置,設定嚴格的允許清單)對 HTML 進行清理。
明確界定安全邊界:所有外在事物均不可信。
將「小型使用者介面功能」與核心功能採取相同的安全策略
內容安全策略 (CSP) 等縱深防禦措施也可以減少影響,但它們無法修復不安全的 DOM API。
這件事真的發生過嗎?
不 😉
我聽過幾十個非常相似的例子嗎?
絕對地。
記住:任何功能都不能忽略程式碼審查和安全測試。
細節決定成敗。
祝您假期快樂平安!
只要稍微注意一下從網路上複製的內容,就能為自己帶來這種好處❄️✨
原文出處:https://dev.to/sylwia-lask/a-five-minute-ui-feature-that-became-an-xss-time-bomb-f5i