日在公眾號中挖掘到了一個 XSS 安全漏洞,具體復現流程如下:
以下是復現漏洞的視頻
視頻鏈接
如果視頻又打不開了,可以去我公眾號的文章里看。
現在我們來分析下這個漏洞的產生過程。
首先標題中存在 HTML <input onfocus="alert('1')">,在網頁中如果不對這部分文本做轉義的話,就會正常渲染為 HTML。
在文章詳情中其實我們并沒有發現這個問題,也就說明了在該頁面中開發者是做了文本轉義的。
但是在留言頁面中卻出現了該問題,也就是說開發者并沒有做標題的轉義,因此導致了這個問題的發生。
雖然這個問題觸發條件不是那么容易,但是對于微信這樣億級日活的產品出現這樣低級的安全問題實屬沒想到。
我們把這樣的安全問題稱之為 XSS 攻擊。根據攻擊的來源,我們可以將此類攻擊分為三種,分別為:
在這個案例中我們遇到的是存儲型 XSS 攻擊。此類攻擊是攻擊者將惡意代碼提交至服務器并保存在數據庫中,用戶訪問該頁面觸發攻擊行為。這種類型的攻擊常見于保存用戶編輯數據的場景下,比如案例中的發表文章,亦或者評論場景等等。
防范存儲型 XSS 攻擊的策略就是不相信一切用戶提交的信息,比如說用戶的評論、發表的文章等等。對于這些信息一律進行字符串轉義,主要是引號、尖括號、斜杠
function escape(str) { str = str.replace(/&/g, '&') str = str.replace(/</g, '<') str = str.replace(/>/g, '>') str = str.replace(/"/g, '&quto;') str = str.replace(/'/g, ''') str = str.replace(/`/g, '`') str = str.replace(/\//g, '/') return str } // "<script>alert(1)</script>" escape('<script>alert(1)</script>') 復制代碼
但是在顯示富文本的場景下其實不能把所有的內容都轉義了,因為這樣會把需要的格式也過濾掉。對于這種情況,通??紤]采用白名單過濾的辦法。
// 使用 js-xss 開源項目 const xss = require('xss') let html = xss('<h1 id="title">XSS</h1><script>alert("xss");</script>') // -> <h1>XSS</h1><script>alert("xss");</script> console.log(html) 復制代碼
在白名單的情況下,h1 標簽不會被轉義,但是 script 能被正常轉義。
日常開發中,為了方便數據的輸入和輸出,JavaScript提供了一些常用的輸入輸出語句,具體如表1-3所示。
表1常用的輸入輸出語句
類型 | 語句 | 說明 |
輸入 | prompt() | 用于在瀏覽器中彈出輸入框,用戶可以輸入內容 |
輸出 | alert() | 用于在瀏覽器中彈出警告框 |
document.write() | 用于在網頁中輸出內容 | |
console.log() | 用于在控制臺中輸出信息 |
接下來將分別演示document.write0、console.log0和promptO的使用。
1. document.write()
document.write0的輸出內容中如果含有HTML標簽,會被瀏覽器解析。下面利用documenL.write0在頁面中輸出“我是document.write0語句!”,示例代碼如下。
document.write('我是document.write()語句!');
2. console.log()
利用console.log0語句在控制臺輸出“我是console.log0語句!”,示例代碼如下。
console.log('我是console.log()語句!');
console:.log0的輸出結果需要在瀏覽器的控制臺中查看。在Chrome 瀏覽器中按“F12”鍵(或在網頁空白區域右擊,在彈出的菜單中選擇“檢查”)啟動開發者工具,然后切換到“Console”(控制臺)面板,即可看到console.log0的輸出結果。
3.prompt()
利用prompt0語句實現在頁面中彈出一個帶有提示信息的輸入框,示例代碼如下。
prompt(請輸入姓名:');
上述示例代碼運行后,將在頁面中彈出一個輸人框并提示用戶“請輸人姓名:”提示框。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus?"> <meta name="Author" content=""> <meta name="Keywords" content=""> <meta name="Description" content=""> <title>細說JavaScript中常用的幾種對話框</title> <script type="text/javascript">javascript> //第一種 最簡單的提示框alert(彈出對話框輸出自定義的提示信息) alert("此處填寫自定義的提示信息!!"); //第二種 帶確認和取消的詢問提示框confirm 它的返回值為真true/假false if(confirm("請問您確認提交嗎")) { alert("您點擊了確定按鈕"); }else { alert("您點擊了取消按鈕"); } //第三種帶輸入的提示對話框prompt,返回值為 對話框中輸入的內容 //這里需要注意的是,prompt有兩個參數,前面是提示的話,后面是當對話框出來后,在對話框里的默認值 var name = prompt("請輸入您的名字", ""); //將輸入的內容賦給變量 name , if (name)//如果返回的有內容 { alert("歡迎您:" + name) } </script> </head> <body> </body> </html>
*請認真填寫需求信息,我們會在24小時內與您取得聯系。