Cross-site scripting(XSS)

Cross-site scripting(XSS) 跨網站指令碼

 クロスサイトスクリプティング

去年在考IPA的情報セキュリティマネジメント試験時,常常看到這個關鍵字,XSS的中文是跨網站指令碼是一種網路攻擊,攻擊者會利用漏洞將惡意程式碼(HTML或是JavaScript或PHP等等)注入到網頁上,然後利用釣魚郵件或是留言板之類的社群軟件當作媒介,第三者在閱覽這些帶有惡意指令碼的網頁時就有可能受到攻擊。

XSS Attacks (HTML)

HTML的例子(1)

在留言板寫下HTML的程式碼

按下submit後真的會執行html的程式碼讓程式碼變紅色

HTML的例子(2)

在輸入框就算用空一行輸入,得到的結果也是在同一排,也無法顯示為2排。

這張圖片的 alt 屬性值為空,它的檔案名稱為 image-2.png這張圖片的 alt 屬性值為空,它的檔案名稱為 image-8.png

 

這張圖片的 alt 屬性值為空,它的檔案名稱為 image-4.png這張圖片的 alt 屬性值為空,它的檔案名稱為 image-5.png

 

textContent和innerHTML

  • innerHTML目的在於取得在一個節點內的全部樣式
  • textContent 目的在於取得在一個節點內的文字(換行)

innerHTML

首先試看看Javascript用innerHTML的結果

 btn.addEventListener("click",function(){
        article.innerHTML = article.innerHTML + `
        <div class ="article" >
            <p>${content.value}</p>
        </div>
        `;
        content.value ="";     
    })

用留言板的漏洞來注入貓咪圖片

結果會顯示一張貓的圖片

textContent

如果Javascript用textContent的話呢?

btn3.addEventListener("click",function(){
        outcome3.textContent = con3.value;
    })

則會顯示輸入文字而不會顯示圖片

innerText也是一樣的結果唷

XSS Attacks (Javascript)

如果前端可以輸入<script></script>去執行Javascript的腳本的話,那就可以做更多壞事了..

但HTML5 似乎把<script></script標籤插在innerHTML的這個漏洞給擋掉了

以下輸入起不到任何作用

但我在github看到一個利用加載圖片發生錯誤時執行javascript的方法可以鑽漏洞。onerror 事件

github : caike /攻擊.md

target.innerHTML = “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

target.innerText= “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

target.textContent = “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

 

 

接下來用這段來試看看吧。

這次跟剛剛一樣,用textContent和innerHTML,再加上一個innerText來試看看好了。

innerHTML

首先試看看Javascript用在innerHTML的結果

 btn.addEventListener("click",function(){
        article.innerHTML = article.innerHTML + `
        <div class ="article" >
            <p>${content.value}</p>
        </div>
        `;
        content.value ="";     
    })

target.innerHTML = “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

target.innerText= “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

target.textContent = “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

 

只要輸入以上三條都會出現alert

很有趣的是,就算我下一行輸入其他字串,如圖 你好啊你好啊的字串,按下按鈕後還是會出現一次alert

因為會讀到之前的article.innerHTML而在執行一次,若前面有兩條

target.innerHTML = “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;紀錄的話

則會出現2次alert

 btn.addEventListener("click",function(){
        article.innerHTML = article.innerHTML + `
        <div class ="article" >
            <p>${content.value}</p>
        </div>
        `;
        content.value ="";     
    })

 

innerText

試看看Javascript用在innerText的結果

function Messagecontent2(){ 
    let con2 = Messagecontentform.content2.value;
    let content2_html = document.getElementById("contentdisplay");
    content2_html.innerText = con2;
    Messagecontentform.content2.value =" ";
    } 

target.innerHTML = “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

target.innerText= “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

target.textContent = “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

輸入以上三條都沒有出現alert,下面顯示文字訊息

textContent

試看看Javascript用在textContent的結果

btn3.addEventListener("click",function(){
        outcome3.textContent = con3.value;
    })

target.innerHTML = “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

target.innerText= “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

target.textContent = “<img src=x onerror=”alert(‘XSS Yoy have been hacked’)” >”;

輸入以上三條都沒有出現alert,下面顯示文字訊息

 

結論

根據上述,我們在寫前端時應該避免使用innerHTML,因為innerHTML有可能會遭收到xss攻擊,我們可以使用textContent或innerText代替innerHTML

參考 mozilla網站內有關Element.innerHTML安全性的資料

我的測試腳本

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Message</h1>

    <p>Message content</p>
    <textarea id="content" rows="8" ></textarea>
    <br>
    <br>
    <button id="btn"> submit</button>

    <div class="article"  id="article">
        <p>メッセージを入力してください</p>
    </div>

    <form name="Messagecontentform" >
        內容&nbsp&nbsp<input type="text" style="width:200px; height:20px;" name="content2" />
        <br/>
        <br/>
        <input type="button" id="btn2" name="btn2" value="更新" onclick="Messagecontent2()"/>
    </form>
    <br>
    <br>
    <div id="contentdisplay"></div>
    <br>
    <br>
    <form name="Messagecontentform_dangerous" >
        &nbsp&nbsp<input type="text" style="width:1000px; height:100px;" id="content3" />
        <br/>
        <br/>
        <input type="button" id="btn3" name="btn3" value="更新"/>
    </form>
    <br>
    <br>
    <div id="outcome3"></div>
    <br>
    <br>
    

    
    <script>
    let content = document.getElementById("content");
    let btn = document.getElementById("btn");
    let article = document.getElementById("article");

    btn.addEventListener("click",function(){
        article.innerHTML = article.innerHTML + `
        <div class ="article" >
            <p>${content.value}</p>
        </div>
        `;
        content.value ="";     
    })

    function Messagecontent2(){ 
    let con2 = Messagecontentform.content2.value;
    let content2_html = document.getElementById("contentdisplay");
    content2_html.innerText = con2;
    }
    
    let con3 = document.getElementById("content3");
    let btn3 = document.getElementById("btn3");
    let outcome3 = document.getElementById("outcome3");
    btn3.addEventListener("click",function(){
        outcome3.textContent = con3.value;
    })
    </script>


</body>
</html>