原文:https://jakearchibald.com/201…
翻譯:瘋狂的技術宅
本文首發微信公眾號:jingchengyideng
歡迎關注,每天都給你推送新鮮的前端技術文章
前一段時間,有很多關於用CSS構建的“鍵盤記錄器”的討論(原始碼見:https://github.com/maxchehab/…)。
有些人要求瀏覽器“修復”它。 另有一些人挖掘得更深一些,發現它隻影響使用React及類似框架編寫的網站,併為此指責React。 不過真正的問題在於第三方內容是不是“安全的”。
下面我們逐一分析這些第三方內容。
第三方圖片
<img src="https://example.com/kitten.jpg">
如果因為我信任example.com
,就在自己的程式碼中包含上述內容。那麼 他們可能會刪除資源,從而給我返回一個404,使我的網站看起來支離破碎,從而辜負了這種信任。同時他們也有可能會用一些不恰當的內容取代原來的圖片。
不過影像的影響僅限於元素本身的內容框。 我可以向自己的使用者解釋“這是來自example.com
的內容,如果它變冒犯了你,那是他們的錯,可別來找我”,並寄希望於使用者們能夠相信我。 但是這種事肯定不會影響我資料庫中密碼欄位之類的東西。
第三方指令碼
<script src="https://example.com/script.js"></script>
與圖片相比,第三方指令碼有更多的控制權。 如果我的程式碼中包含上述內容,就會給example.com
完全控制自己的網站的機會。 他們能:
- 讀取/更改頁面內容。
- 監控使用者互動的每一個步驟。
- 執行計算量很大的程式碼(比如用你的瀏覽器挖礦)。
- 盜取使用者的cookie向我的來源發出請求,並轉發響應資料。
- 讀取/更改原始儲存。
- 幾乎可以做任何他們想做的事。
“原始儲存”位非常重要。 如果指令碼影響了IndexedDB或快取儲存API,即使你把指令碼刪掉,攻擊也可能會仍然繼續。
如果你在自己的程式碼中引用了來自其他來源的指令碼,那麼必須絕對信任它們,並保證其安全性。
如果遇到惡意指令碼,則應使用 Clear-Site-Data
標頭清除所有站點資料。
第三方CSS
<link rel="stylesheet" href="https://example.com/style.css">
CSS的作用更接近於指令碼而不是影像。和指令碼一樣,它適用於整個頁面。 它可以:
- 刪除/新增/修改頁面內容。
- 根據頁面內容發出請求。
- 對許多使用者互動作出響應。
CSS不能修改原始儲存,你不能用CSS寫一個挖礦程式(也有可能,或許我還不知道),但惡意CSS仍然可以造成很大的破壞。
鍵盤記錄器
我們們從最開始的那個問題開始
input[type="password"][value$="p"] {
background: url(`/password?p`);
}
如果輸入的 value
屬性以 p
結尾,上面的程式碼將觸發對 /password?p
的請求。 對每個字元都會執行此操作,這樣你會獲得大量鍵盤輸入的資料。
預設情況下,瀏覽器不會將使用者輸入的值儲存在 value
屬性中,因此攻擊往往在同步這些值的內容時發生,例如React。
為了緩解這種情況,React可以使用另一種同步密碼欄位的方法,或者瀏覽器可以限制與密碼欄位的 value
屬性匹配的選擇器,但這僅僅是一種虛假的安全感。 你只不過是解決了一個特定的問題,但其他情況下一切照舊。
如果 React 切換到使用data-value
屬性,則上述手段將失敗。如果站點將輸入更改為type ="text"
,那麼使用者可以看到他們正在輸入的內容,則這種手段失敗。 如果站點建立<better-password-input>
並將值作為屬性公開,同樣上述手段失敗。
此外,還有許多基於CSS的攻擊:
消失的內容
body {
display: none;
}
html::after {
content: `HTTP 500 Server Error`;
}
這是一個極端的例子,但想象一下,如果第三方程式碼為你的一小部分使用者做了這種事,會出現什麼樣的後果:將會侵蝕掉使用者對你的信任,同時很難排查問題到底出在何處。
更加腹黑的黑客可能會偶爾刪除“購買”按鈕,或著重新排列內容中的段落。
新增內容
.price-value::before {
content: `1`;
}
哎呀,你這麼快就漲價了!
移除內容
delete-everything-button {
opacity: 0;
position: absolute;
top: 500px;
left: 300px;
}
把一個有“刪庫跑路”功能的按鈕設為不可看,然後再把它放在使用者可能會點選的地方。
值得慶幸的是,如果按鈕執行的是後果非常嚴重的操作,該網站可能會首先顯示確認對話方塊。 沒關係,只需使用更多的CSS來誘騙使用者單擊“是的我確定!”按鈕而不是“哦天吶!不是!”按鈕。
想象一下,如果瀏覽器確實試圖消除“鍵盤記錄”這種小伎倆的影響。攻擊者還可以在頁面上放一個非密碼文字輸入框(可能是搜尋欄位)並將其覆蓋在密碼輸入框之上,呵呵,現在他們又回來了。
讀取屬性
你擔心的可不僅僅是密碼。 一些私有內容可能會儲存在屬性中:
<input type="hidden" name="csrf" value="1687594325">
<img src="/avatars/samanthasmith83.jpg">
<iframe src="//cool-maps-service/show?st-pancras-london"></iframe>
<img src="/gender-icons/female.png">
<div class="banner users-birthday-today"></div>
所有這些都可以被CSS選擇器設為目標,並且可以把結果發到某個伺服器上。
監控互動
.login-button:hover {
background: url(`/login-button-hover`);
}
.login-button:active {
background: url(`/login-button-active`);
}
可以將hover和active等動作傳送回伺服器。 適當的使用CSS,你可以很好地瞭解使用者想要幹什麼。
讀取文字
@font-face {
font-family: blah;
src: url(`/page-contains-q`) format(`woff`);
unicode-range: U+71;
}
html {
font-family: blah, sans-serif;
}
在這種情況下,如果頁面包含q
,將傳送請求。 你可以為不同的文字建立大量的這種請求,並可以定位特定的元素。 字型還可以包含連字,因此還可以檢測字元序列。 你甚至可以將字型技巧與滾動條檢測相結合,從而能推斷出更多相關內容的資訊。
結論:第三方內容並不安全
這些只是我所知道的一些技巧,我相信還會有更多類似的小技巧。
第三方內容在其沙箱中具有很高的影響力。 雖然影像或沙盒iframe有著非常小的沙箱,但指令碼和樣式的作用範圍卻影響你的整個頁面,甚至是整個站點。
如果你擔心使用者會欺騙你的網站去載入第三方資源,可以使用CSP(內容安全策略)保證安全,從而限制從中獲取影像,指令碼和樣式的位置。
還可以使用子資源完整性來確保指令碼/樣式的內容與特定的雜湊匹配,否則將無法執行。
如果你對這種安全技術感興趣,包括滾動條技巧的更多細節,可以去看看Mathias Bynens在2014年的演講,Mike West在2013年的演講,或Mario Heiderich等人的2012年論文。 沒錯,這些技術並不是最新的。
本文首發微信公眾號:jingchengyideng
歡迎關注,每天都給你推送新鮮的前端技術文章