你應該知道的前端安全性

本文不是一個大而全的課程,只是咱們平常中常見的問題,由於網絡安全是一個很大的話題,咱們這裏只介紹前端工程師應知應會的東西。大概包括 XSS, CSRF, 點擊劫持,SQL注入,OS注入,請求劫持,DDOS,以及簡單的防範策略。javascript

1.XSS

XSS的英文是Cross Site Scripting也就是常說的跨站腳本***,由於縮寫和CSS重疊,因此只能叫XSS,跨站腳本***是指經過存在安全漏洞的Web網站註冊用戶的瀏覽器內運行非法的HTML標籤或JavaScript進行的一種***。html

那麼XSS通常是如何進行***的呢?假設咱們頁面中存在一個input或者textarea用來收集用戶輸入的數據,正常狀況下不會有什麼問題,假設用戶輸入的內容爲 <script>alert(1)</script>。當咱們將用戶輸入的這段內容經過innnerHTML添加到頁面中時,就會運行該段代碼,彈出alert。前端

document.body.innerHTML = inputValue;複製代碼

能夠發現,用戶輸入的js腳本是能夠被執行的,這樣的話就造成了一個安全漏洞,不少***都是先經過alert的方式先去試驗網站是否能夠被XSS,這也就意味着能夠運行js裏面的任何腳本。用戶在不知情的狀況下輸入的帳號密碼會被***記錄發送給本身,也能夠經過js改寫頁面顯示非法圖片,將用戶的登陸狀態複製到***的電腦上***可使用用戶的身份進行操做等等。vue

通常XSS的***方式有兩種,一種是上面介紹的經過input輸入的方式進行***叫作存儲型,就是用戶輸入的內容會存儲到數據庫,每次打開頁面都會執行,另外一種是經過url參數***叫作反射型,假設咱們網站url中攜帶的內容會渲染到頁面。java

http://localhost:8080/index.html?name=yd複製代碼

***能夠發送以下的連接給用戶,用戶一旦打開就會執行腳本。mysql

http://localhost:8080/index.html?name=<script>alert(123)</script>複製代碼

XSS的危害有哪些,簡單來講javascript能作什麼,他就能夠作什麼。react

1.獲取頁面數據jquery

2.獲取Cookiesgit

3.修改前端邏輯程序員

4.發送請求

5.獲取用戶的信息和登陸態

6.欺騙用戶

如何防止XSS***呢?

  1. 能夠在header中設置響應頭 X-XSS-Protection,默認狀況下禁止XSS***的,若是檢測到url中存在XSS***,頁面是拒絕訪問的。可是他對存儲型的***是無效的,只能攔截url中存在注入***的狀況。
ctx.set('X-XSS-Protection', 0); // 容許XSS***複製代碼

值有以下4種:

  • 0 容許XSS***

  • 1 禁止XSS***。若是檢測到跨站腳本***,瀏覽器將清除頁面(刪除不安全的部分)

  • 1;mode=block 啓用XSS過濾,若是檢測到***,瀏覽器將不會清除頁面,而是阻止頁面加載。

  • 1report= 啓用XSS過濾,若是檢測到跨站腳本***,瀏覽器將清除頁面並使用CSP report-uri 指令的功能發送違規報告。

一般狀況下瀏覽器會默認設置爲1,禁止XSS***。

  1. CSP

內容安全策略(CSP Content Security Policy) 是一個附加的安全層,用於幫助檢測和緩解某些類型的***,包括XSS和數據注入等***。這些***可用於實現從數據竊取到網站破壞或做爲惡意軟件分發版本等用途。

CSP本質上就是創建白名單,開發者明確告訴瀏覽器哪些外部資源能夠加載和執行,咱們只須要配置規則,如何攔截是瀏覽器本身實現的,咱們能夠經過這種方式來儘可能減小XSS***。

這個策略他有以下幾種方式:

// 只容許加載本站資源Content-Security-Policy: default-src 'self'// 只容許加載HTTPS協議圖片Content-Security-Policy: img-src https://*// 不容許加載任何來源框架Content-Security-Policy: child-src 'none'複製代碼

通常被***是咱們的網站執行了其餘網站的js腳本,注入了***的js代碼。假設咱們的網站設置了只容許加載本身網站的代碼,那麼注入的js腳本就沒辦法執行了。

// 設置只容許執行本身網站的js腳本,ctx.set('Content-Security-Policy', "default-src 'self'")// 瀏覽器打開鏈接時4000端口的外部資源不能被加載https://127.0.0.1:3000?from=<script src="http://127.0.0.1:4000/hack.js"></script>複製代碼
  1. 轉譯字符

用戶輸入永遠不可信任的,最廣泛的作法就是轉譯輸出的內容,對於引號,尖括號,斜槓進行轉譯,好比經過以下的函數,對用戶輸入的內容進行轉譯。

function escape(str) {
    str = str.replace(/&/g, '&amp;');
    str = str.replace(/</g, '&lt;');
    str = str.replace(/>/g, '&gt;');
    str = str.replace(/"/g, '&quto;');
    str = str.replace(/'/g, '&#39;');
    str = str.replace(/`/g, '&#96;');
    str = str.replace(/\//g, '&#x2F;');return str;
}escape('<script>alert(123)</script>'); // &lt;script&gt;alert(123)&lt;&#x2F;script&gt;複製代碼

這種轉譯叫作黑名單注意,就是把不安全的東西進行轉譯,好比說<>, 可是有一種狀況是不能進行黑名單轉譯的。

有時咱們要處理一些富文本,顯然不能經過上面的辦法來轉譯全部字符,由於這樣會把須要的格式也過濾掉,對於這種狀況,一般採用白名單過濾的辦法,固然也能夠經過黑名單過濾,可是考慮到須要過濾的標籤和標籤屬性實在太多,更加推薦使用白名單的方式。

白名單的方式就是容許一部分安全的字符經過,其餘的字符所有轉譯,這裏推薦使用xss的npm包來處理。

// 引入xssconst xss = require('xss');let html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss")</script>');// <h1 id="title">XSS Demo</h1>&lt;script&gt;alert("xss")&lt;/script&gt;console.log(html);複製代碼

能夠看到這裏xss保留了h1標籤,由於他是安全的,對script標籤進行了轉譯,由於他是不全安的。

通常狀況用戶輸入的數據或者從url中獲取的參數咱們不建議直接使用innnerHTML插入到頁面中,除了xss模塊和escape方法還能夠引入html模板,常見的是ejs模板。react,vue,angular等框架默認已經幫咱們處理了xss。

// 轉譯 inputValue 內容<%= inputValue %>// 不轉移 inputValue 內容<%- inputValue %>複製代碼
  1. HttpOnly Cookie

爲何用戶的cookie能夠被調取,緣由是js是能夠獲取cookie的,咱們能夠經過禁止js訪問cookie的方式防範這種***。

這是預防XSS***竊取用戶cookie最有效的防護手段,Web應用程序在設置cookie時,將其屬性設爲HttpOnly, 就能夠避免該網頁的cookie被客戶端惡意javaScript竊取,保護用戶cookie信息。也就是服務在設置cookie的時候跟上HttpOnly便可。

response.addHeader('Set-Cookie', 'uid=112; path/; HttpOnly')複製代碼

這樣設置的cookie,js就沒辦法訪問到了。

以上說的就是一些基本的防護XSS***的手段。CSP,字符轉譯,HttpOnly Cookie。

2.CSRF

CSRF( Cross Site Request Forgery),即跨站請求僞造,是一種常見的web***,它利用用戶已登陸的身份,在用戶絕不知情的狀況下,以用戶的名義來完成非法操做。簡單來講***步驟也很簡單。

用戶已經登陸了站點A, 而且在A站點記錄了登陸狀態(cookie),再次進來不須要登陸了。在用戶沒有登出站點A的狀況下,也就是登陸態還有效時,訪問了惡意***者提供的引誘危險站點B, B站點調用A站點的某個接口,好比說提交接口。若是A站點沒有作任何的CSRF防護,就會被***。

原理也很簡單,由於B站點調用了A站點的提交接口,根據cookie匹配原則,調用哪一個站點的接口就會攜帶哪一個站點的cookie,攜帶的就是用戶存在A站點的cookie,這個時候提交接口傳遞的參數其實是B站點提供的。在用戶無心識的狀況下以用戶的身份調用了接口。

不少人可能會以爲,B站點調用A站點的接口跨域了啊,那怎麼行。這沒什麼,跨域只是一種說法而已通常的跨域是前端拿不到接口的返回值,但不表明請求發不出去,這種***只要請求發出去了就達到***的目的了,返回值什麼的都無所謂了。

防護CSRF的手段有三種。

第一個是禁止第三方網站攜帶Cookie,可是有兼容性問題,第二個方式是驗證請求傳遞過來的referrer,判斷是否是一個合法的referrer。其實不少的防盜鏈都是驗證referrer的方式。

referrer就是發送請求的那個前端頁面地址,能夠經過referrer的方法進行屏蔽和過濾,可是他也有一個問題https是不發送referrer的,因此也算是兼容性的問題。

目前最有效的方式仍是驗證碼的方式或者人機交互的方式,之前能夠經過CSRF調取用戶資金,由於轉帳比較簡單,但如今基本轉帳都會發送驗證碼之類的驗證。

3.點擊劫持

點擊劫持是一種視覺欺騙的***手段,***者將須要***的網站經過iframe嵌套的方式嵌入本身的網頁中,並將iframe設置爲透明,在頁面中透出一個按鈕誘導用戶點擊。

當你點擊這個按鈕的時候其實是點擊到了iframe中的某個按鈕上,觸發iframe嵌入網站的功能,好比想要給一個頁面點贊,就能夠把這個頁面經過iframe假裝。

要防護這個其實很簡單,只須要設置X-FRAME-OPTIONS響應頭,X-FRAME-OPTIONS是一個http響應頭,在如今瀏覽器有一個很好的支持,這個http響應頭就是爲了防護用iframe嵌套的點擊劫持***。

該響應頭有三個值可選分別是

DENY 表示頁面不容許經過iframe的方式展現

SAMEORIGIN 表示頁面能夠在相同域名下經過iframe的方式展現

ALLOW-FROM 表示頁面能夠在指定來源的iframe中展現

ctx.set('X-FRAME-OPTIONS', 'DENY')複製代碼

也可直接經過js判斷是否在iframe中,不過該方法也有問題,跨域狀況下內層的頁面是沒法操做外層的location的。

if (self !== top) {
    top.location.href = self.location.href; // 將外層的location修改成內層的locationdocument.body.innnerHTML = ''; // 清除頁面內容}複製代碼

4.SQL注入

SQL注入是比較常見的網絡***方式之一,它不是利用操做系統的BUG來實現***,而是針對程序員編寫時的疏忽,經過SQL語句,實現無帳號登陸,甚至篡改數據庫。SQL注入***比較偏向後端,前端同窗瞭解便可。

假設咱們的sql是下面這個樣子的,查詢數據庫用戶表中是否存在用戶名爲userName變量,密碼爲password變量的用戶。

const sql = 'select * from user_table where username= "'+ userName +'" and password = "' + password + '"';複製代碼

當用戶輸入了正確的用戶名和密碼的時候不會有什麼問題

const userName = 'yd';const password = '123456';const sql = 'select * from user_table where username= "'+ userName +'" and password = "' + password + '"';// select * from user_table where username= "yd" and password = "123456"複製代碼

可是若是***輸入的密碼是1"or"1"="1 就會出現問題, 這是一條永遠能夠執行成功的sql。username等於yd ,password等於或者1=1;恆成立的sql。

const userName = 'yd';const password = '1"or"1"="1';const sql = 'select * from user_table where username= "'+ userName +'" and password = "' + password + '"';// select * from user_table where username= "yd" and password = "1" or"1"="1"複製代碼

通常狀況下咱們是不容許拼接sql的,全部的查詢語句建議使用數據庫提供的參數化查詢接口,參數化的語句使用參數而不是將用戶輸入變量嵌入到SQL語句中,既不要直接拼接SQL語句,例如Node.js中的mysqljs庫中的query方法。

const sql = ` SELECT * user_table WHERE username = ? AND password = ?`res = await mysql.query(sql, [ctx.request.body.username, ctx.request.body.password]);複製代碼

除此以外,要嚴格限制web應用的數據庫的操做權限,給此用戶提供僅僅可以知足其工做的最低權限,從而最大限度的減小注入***對數據庫的危害,後端代碼檢查輸入的數據是否符合預期,嚴格限制變量的類型,例如使用正則表達式進行一些匹配處理。對進入數據庫的特殊字符(',",,<,>,&,*,;)等,進行轉譯處理,或編碼轉換**。基本上全部的後端語言都有對字符串進行轉譯處理的方法,好比lodash的lodash._escapehtmlchar庫。

5.OS命令注入

OS命令注入和SQL注入差很少,只不過SQL注入的是針對數據庫的,而OS命令注入是針對操做系統的,OS命令注入***指經過web應用,執行非法的操做系統命令達到***的目的,只要在能調用shell函數的地方就有存在被***的風險,假若調用shell時存在疏漏,就能夠執行插入的非法命令。

以Node.js爲例,加入在接口中須要從 github 下載用戶指定的項目

const exec = require('mz/child_process').exec;const params = { /* 用戶輸入的參數 */};
exec(`git clone ${params.repo}/some/path`);複製代碼

若是傳入的參數以下會怎樣

https://github.com/xx/xx.git && rm -rf /* &&複製代碼

這個時候若是用戶的權限很大的話,就會執行rm -rf /*, 刪掉服務器中全部內容。

6.請求劫持

下面這種不是咱們前端的概念,可是很經常使用,這裏也說一下,瞭解一下便可。

請求劫持分爲兩種,一種是DNS劫持,一種是HTTP劫持。

DNS服務器也就是域名服務器,他會把域名轉換爲ip地址,若是這個被篡改了,那跳轉的網站就不是意向中的網站了。咱們電腦中以一個host文件,那就是本地DNS,若是遇到DNS劫持能夠查看本地host文件是否被篡改了。

HTTP劫持比較常見,HTTP自己是明文傳輸,而且傳輸的工程中極可能中間的某一環節被篡改。好比咱們常常遇到這樣的狀況,咱們再火車站連接了火車站的wifi,這個時候咱們不管打開什麼頁面出現的都是登陸wifi的頁面。這個其實就是在路由器層對你訪問的站點作了篡改,都沒到運營商那一環。

HTTP劫持只能升級HTTPS了,由於他自己就是明文傳輸。

7.DDOS

這裏參考了阮一峯老師的博客[DDOS ***的防範教程]。

DDOS不是一種***,而是一大類***的總稱,他有幾十種類型,新的***方法還在不斷髮明出來,網站運行的各個環節,均可以是***目標。只要把一個環節攻破,使得整個流程跑不起來,就達到了癱瘓服務的目的。

其中比較常見的一種***是CC***。他就是簡單粗暴的送來大量正常的請求,超出服務器的最大承受量,致使宕機。

我遭遇的就是CC***,最多的時候全世界大概20多個IP地址輪流發出請求,每一個地址的請求在每秒200 ~ 300次,我看訪問日誌的時候,就以爲那些請求像洪水同樣涌來,一眨眼就是一大堆,幾分鐘的時間,日誌文件的體積就大了100MB。

說實話,這是能算小***,可是個人我的網站沒有任何防禦,服務器仍是跟其餘人共享的,這種流量一來馬上就下線了。

如今的這種DDOS***方式通常是不會到達你的服務器自己的,由於大量的請求來了之後極可能在機房路由器中就所有佔滿了,請求已經到不了服務器層了,通常這種狀況運營商直接就會把服務器下線掉了。因此服務器層基本不容易作控制。

咱們能夠備份網站,就是你要有一個備份網站,或者最低限度有一個臨時主頁。生產服務器萬一下線了,能夠馬上切換到備份網站,不至於毫無辦法。

備份網站不必定是全功能的,若是能作到全靜態瀏覽,就能知足需求。最低限度應該能夠顯示公告,告訴用戶,網站出了問題,正在全力搶修。這種臨時主頁建議放到帶寬大,能夠應對***的網站上。

還能夠經過HTTP請求的攔截,若是惡意請求有特徵,對付起來很簡單:直接攔截它就好了,能夠在硬件,服務器,防火牆中進行攔截。

HTTP 攔截有一個前提,就是請求必須有特徵。可是,真正的 DDOS ***是沒有特徵的,它的請求看上去跟正常請求同樣,並且來自不一樣的 IP 地址,因此無法攔截。這就是爲何 DDOS 特別難防的緣由。

DDOS ***的成本仍是比較高的,咱們能夠經過寬帶擴容 + CDN的方式來提升***成本。

8 .爬蟲

爬蟲能夠爬取網站中的內容,Node中可使用cheerio和https模塊進行演示。

const cheerio = require('cheerio');const https = require('https');let html = '';const $ = '';

https.get('url', res => {
    res.on('data', data => {
        html += data; // 保存返回的數據});
    res.on('finish', () => {
        $ = cheerio.load(html); // cheerio解析數據// $就是拿到的dom樹, 想jq同樣。})
})複製代碼

cheerio用法相似於jquery,https能夠發送https請求。在finish方法中表示獲取到了頁面的html。

防護爬蟲的方式比較多樣。好比說驗證瀏覽器的UA,referrer 或者驗證碼。還有好比查看單位時間的訪問次數,訪問量。

還能夠進行關鍵信息使用圖片混淆,好比說有些文字咱們直接讓接口返回圖片進行渲染。自己SPA單頁面就是一種反爬取的手段,不過他最大的一個缺點就是對搜索引擎不友好。搜索引擎用的就是爬蟲技術。因此後面又推出了***渲染來解決這個問題。

還有一些比較高級的防護手段,就是前端的一些技術限制。

字體亂序法,服務返回給前端的html中,文字和用戶實際看到的不一致,好比說服務返回的div總內容是4998,而頁面真正展現的是1995,他的作法也很簡單,使用一個特殊的字體庫,由於字體渲染的時候會去查找字體庫,以字體庫的樣子渲染。在這個字體庫中,4對應1,8對應5,就能夠了。

還能夠將網站重要的字體,生成圖片,經過iconfont的方式來渲染。

還有一種canvas指紋反爬方法,canvas指紋的含義是,由於不一樣硬件對canvas支持不一樣,所以你只要畫一個很複雜的canvas,那麼得出的image,老是存在像素級別的偏差。考慮到爬蟲代碼都是統一的,就算起selenium,也是ghost的,所以指紋通常都是一致的,所以繞過概率很是低。但事實上並非如此,國內公司一般是IT統一裝機,不管是軟件仍是硬件都驚人的一致。因此canvas指紋類似度特別高。

最後你們能夠自行了解一下無頭瀏覽器, 這東西真的是個神器。


歡迎關注,更多內容持續更新

相關文章
相關標籤/搜索