前端必須懂的計算機網絡知識—(XSS、CSRF和HTTPS)

前端必須懂的計算機網絡知識系列文章:

HTTP爲何不安全

  1. 可能被竊聽:
  • HTTP 自己不具有加密的功能,HTTP 報文使用明文方式發送
  • 因爲互聯網是由聯通世界各個地方的網絡設施組成,全部發送和接收通過某些設備的數據均可能被截獲或窺視。(例如你們都熟悉的抓包工具:Wireshark),即便通過加密處理,也會被窺視是通訊內容,只是可能很難或者沒法破解出報文的信息而已
  1. 認證問題
  • 沒法確認你發送到的服務器就是真正的目標服務器(可能服務器是假裝的)
  • 沒法肯定返回的客戶端是不是按照真實意圖接收的客戶端(多是假裝的客戶端)
  • 沒法肯定正在通訊的對方是否具有訪問權限,Web服務器上某些重要的信息,只想發給特定用戶即便是無心義的請求也會照單全收。沒法阻止海量請求下的 DoS 攻擊(Denial of Service,拒絕服務攻擊)。
  1. 可能被篡改
  • 請求或響應在傳輸途中,遭攻擊者攔截並篡改內容的攻擊被稱爲中間人攻擊(Man-in-the-Middle attack,MITM)。

XSS攻擊

XSS,即爲(Cross Site Scripting),中文名爲跨站腳本,跨站腳本的重點不在「跨站」上,而在於「腳本」上。大多數XSS攻擊的主要方式是嵌入一段遠程或者第三方域上的JS代碼,其實是在目標網站的做用域下執行了這段第三方域上的js代碼。php

反射型XSS(非持久型XSS)

特色:就像鏡子反射同樣,瀏覽器發射含XSS的url,服務器將其反射回來css

  1. 瀏覽器發生請求時,XSS代碼出如今請求URL中,做爲參數提交到服務器,
  2. 服務器解析並響應,響應結果中包含XSS代碼,
  3. 最後瀏覽器解析並執行。

案例:表單提交html

//test.html
<body>
    <textarea name="txt" id="txt" cols="80" rows="10">
    <button type="button" id="test">測試</button>
    <script>
        var test = document.querySelector('#test')
        test.addEventListener('click', function () {
            var url = `/test?test=${txt.value}`   //1.發送一個GET請求
            var xhr = new XMLHttpRequest()
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
                        // 3. 客戶端解析JSON,並執行
                        var str = JSON.parse(xhr.responseText).test
                        var node = `${str}`
                        document.body.insertAdjacentHTML('beforeend', node)
                    } else {
                        console.log('error', xhr.responseText)
                    }
                }
            }
            xhr.open('GET', url, true)
            xhr.send(null)
        }, false)
    </script>  
</body>
複製代碼
//server.js
var express = require('express');
var router = express.Router();
router.get('/test', function (req, res, next) {
 // 2.服務端解析成JSON後響應
    res.json({
        test: req.query.test
    })
})
複製代碼

如今咱們經過給textarea添加一段有攻擊目的的img標籤: 前端

反射型XSS1
點擊<測試>按鈕,一個XSS攻擊就發生了。下面圖片中是獲取了本地的部分cookie信息:
反射型XSS1
上面只是模擬攻擊,經過alert獲取到了我的的cookie信息。通常黑客會注入一段第三方的js代碼,而後將獲取到的cookie信息存到他們的服務器上,拿到咱們的身份認證作一些違法的事情了。

存儲型XSS(持久型XSS)

特色:黑客將XSS代碼發送給服務器,而後經過服務器散播node

  1. 黑客將XSS代碼發送到服務器(無論是數據庫、內存仍是文件系統等。)
  2. 其餘人請求頁面的時候就會帶上XSS代碼了。

案例:最典型的就是留言板XSS。ios

  • 黑客提交了一條包含XSS代碼的留言到數據庫。
  • 當目標用戶查詢留言時,那些留言的內容會從服務器解析以後加載出來。
  • 瀏覽器發現有XSS代碼,就當作正常的HTML和JS解析執行。XSS攻擊就發生了。

DOM型XSS

特色:DOM XSS代碼不須要服務器端的解析響應的直接參與,而是徹底經過瀏覽器端的DOM解析。web

  • 瀏覽器的代碼中含有eval,new Function等將字符串內容執行的代碼
  • 在執行的字符串中嵌入能夠執行XSS代碼字符串 案例:
test.addEventListener('click', function () {
  var node = window.eval(txt.value)
  window.alert(node)
}, false)

//txt中的代碼以下:
<img src='null' onerror='alert(123)' />
複製代碼

XSS危害

  • 經過document.cookie盜取cookie
  • 使用js或css破壞頁面正常的結構與樣式
  • 流量劫持(經過訪問某段具備window.location.href定位到其餘頁面)
  • Dos攻擊:利用合理的客戶端請求來佔用過多的服務器資源,從而使合法用戶沒法獲得服務器響應。
  • 利用iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻擊)用戶的身份執行一些管理動做,或執行一些通常的如發微博、加好友、發私信等操做。
  • 利用可被攻擊的域受到其餘域信任的特色,以受信任來源的身份請求一些平時不容許的操做,如進行不當的投票活動。

XSS防護

XSS攻擊能夠看出,不能原樣的將用戶輸入的數據直接存到服務器,須要對數據進行一些處理:算法

  • 過濾危險的DOM節點。如具備執行腳本能力的script, 具備顯示廣告和色情圖片的img, 具備改變樣式的link, style, 具備內嵌頁面的iframe, frame等元素節點。
  • 過濾危險的屬性節點。如on-, style, src, href等
  • 對cookie設置httpOnly,可是也會致使前臺沒法操做cookie,不太推薦。

CSRF

CSRF(Cross-site request forgery),中文名稱:跨站請求僞造,攻擊者盜用了你的身份,以你的名義發送惡意請求。 數據庫

CRFS
特色:

  1. 登陸受信任網站A,並在本地生成Cookie。
  2. 在不登出受信任網站A的狀況下,訪問危險網站B。
  3. 危險網站會向受信任A的網站發送請求,同時會攜帶受信任網站A本地生成Cookie(用同一個瀏覽器訪問同一個域的接口)

案例:express

//釣魚網站,利用用戶的cookie進行權限操做轉帳
<body onload="steal()">
    <iframe name="steal" display="none">
&emsp;&emsp;    <form method="POST"name="transfer"&emsp;action="http://www.myBank.com/Transfer.php">
&emsp;&emsp;&emsp;&emsp;    <input type="hidden" name="toBankId" value="11">
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;<input type="hidden" name="money" value="1000">
&emsp;&emsp;&emsp;&emsp;</form>
&emsp;&emsp;</iframe>
</body>
複製代碼

CSRF的危害

  1. 篡改目標網站上的用戶數據;
  2. 盜取用戶隱私數據;
  3. 做爲其餘攻擊向量的輔助攻擊手法;
  4. 傳播CSRF蠕蟲。

CSRF的防護

  1. 驗證碼,由於驗證碼必須在受信任的網站上發送給瀏覽器的,而且僞造的網站和受信任的網站非同源,因此沒有辦法獲取受信任網站發送的session,因此驗證碼是沒有辦法僞造的。
  2. refer,標識了當前請求的頁面的源,僞造網站能夠篡改爲受信任的網站源,並不保險
  3. token,因爲它是經過服務的發送給客戶端的令牌,而且存儲在瀏覽器的localstorage中,因爲同源策略,而且token還有校驗規則,因此token並不能輕易篡改。

Token和JWT

Token的特色

  1. session是經過cookie傳輸的,每次訪問網站都會自主的帶上,因此存在安全問題和浪費帶寬,token存儲在localstorage,能夠選擇性發送給後臺,因爲同源策略,安全性高
  2. session在集羣服務器中很難實現共享,服務器必須存在一份sessionq清單,token不須要存儲清單,共用一個密鑰,發送token能夠實現共享
  3. session銷燬後會從清單消失,token的註銷很差實現,沒有清單證實這個token不能用,因此得用一個黑名單來標註

JWT

jwt是實現token的一種方式,一個token分3部分,3部分之間用「.」號作分隔:

  1. header:頭部爲base64字符串
  2. payload:載荷爲base64字符串
  3. signature:簽證 hader+payload通過key加密得出

EXP:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

  • JWT原理:
let jwt = {
    //解碼
    decode(token,secret){
        let [header,content,sign] = token.split('.');
        let h = JSON.parse(this.formBase64ToString(header));
        let c = JSON.parse(this.formBase64ToString(content));
        if(sign !== this.sign([header,content].join('.'),secret){
            throw new Error ('Not allowd')
        }
        return c
    },
    //加碼
    encode(payload,secret){
        let header = this.toBase64(JSON.stringify({'type':'JWT',alg:'HS25' }));
        let content = this.toBase64(JSON.stringify(payload));
        let sign = this.sign([header,content].join('.'),secret);
        return [header,content,sign].jion('.');
    }
    //轉換爲base64
    toBase64(str){
        return Buffer.from(str).toString('base64');
    }
    //簽名
    sign(str,secret){
        return require('crypto').createHmac('sha256',secret).update(str);
    }
}

module.exports = jwt;
複製代碼
  • JWT後臺:
const express = require('express');
const bodyParser = require('body-parser')
const jwt = require('jwt-simple')
const userList=[
    {id:1,username:'kbz',password:'123456'}
]
const SECRET = 'MISS';
let app = express();
app.use(bodyParser.json);

//由於請求頭中有Authorization字段,這和跨域時要設置name傳參數同樣,能夠參考:
//前端必須懂的計算機網絡知識—(跨域、代理、本地存儲)
//https://juejin.im/post/5bb1cc2af265da0ae5052496
app.use(function(req,res,next){
    res.setHeader('Access-Control-Allow-Origin',"*");
    res.setHeader('Access-Control-Allow-Headers',"Content-Type,Authorization");
    res.setHeader('Access-Control-Allow-Methods',"GET,POST,OPTIONS");
    if(req.method === 'OPTIONS'){
        res.end();
    }
    next();
})

//登錄時發送token
app.post('/login',function(req,res,next){
    let user = req.body;
    userList.find(person=>(person.id === user.id));
    if(user){
        jwt.encode({
            id:user.id,
            username:user.username
        },SECRET)
        res.json({
            code:0,
            data:{
                token
            }
        })
    }else{
        res.json({
            code:1,
            data:'用戶不存在'
        })
    }
})

// 須要驗證權限,則取token驗證
// 請求頭Authorization:Bearer token
app.get('/order',function(req,res,next){
    let authorization = req.headers['authorization'];
    if(authorization){
        let token = authorization.split(' ')[1];
        try{
            let user = jwt.decode(token,SECRET);
            req.user = user;
        }catch(e){
            res.status(401).send('Not Allowed')
        }
    }else{
        res.status(401).send('Not Allowed')
    }

})
app.listen(3000);
複製代碼
  • JWT前臺
//login.html
<input type="text" id='username' class="form-control">
<input type="text" id='password' class="form-control">
<span onclick='login()'></span>
<scrpipt>
    axios.post('/user').then(res=>{
        localStorage.setItem('token',res.data.data.token)
        location.href='/order'
    })
</script>

//order.html
<scrpipt>
    axios.interceptors.request.use(function(config){
        let token = localStorage.getItem('token');
        if(token){
            config.headers.Authorization = 'Bearer '+ token
        }
    })
    axios.get('/order').then(res=>{
        console.log(res);
    })
</script>
複製代碼

HTTPS(HTTP+TLS/SSL)

TLS/SSL

TLS/SSL的功能實現主要依賴於三類基本算法:

  • 非對稱加密實現身份認證和密鑰協商
  • 對稱加密算法採用協商的密鑰對數據加密
  • 散列函數驗證信息的完整性,針對於密鑰泄露的不安全性
    SSL
    結合三類算法的特色,TLS 的基本工做方式:
  1. 客戶端使用非對稱加密與服務器進行通訊,實現身份驗證並協商對稱加密使用的密鑰
  2. 而後對稱加密算法採用協商密鑰對信息以及信息摘要進行加密通訊,不一樣的節點之間採用的對稱密鑰不一樣,從而能夠保證信息只能通訊雙方獲取

對稱加密

  • 相同的密鑰能夠用於信息的加密和解密,掌握密鑰才能獲取信息,可以防止信息竊聽,通訊方式是1對1(前提示密鑰不泄露)
  • 算法公開、計算量小、加密速度快、加密效率高
  • 客戶端、服務器雙方都須要維護大量的密鑰,維護成本很高
  • 因每一個客戶端、服務器的安全級別不一樣,密鑰容易泄露,交易雙方都使用一樣鑰匙,安全性得不到保證

非對稱加密

  • 非對稱加密算法的特色加密和解密分別使用不一樣的密鑰,客戶端用公鑰對請求內容加密,服務器使用私鑰對內容解密,反之亦然。
  • 相對來講加解密速度較慢,使用非對稱加密在數據加密解密過程須要消耗必定時間,下降了數據傳輸效率
  • 公鑰是公開的,因此針對私鑰加密的信息,黑客截獲後可使用公鑰進行解密,獲取其中的內容
  • 公鑰並不包含服務器的信息,使用非對稱加密算法沒法確保服務器身份的合法性,存在中間人攻擊的風險,服務器發送給客戶端的公鑰可能在傳送過程當中被中間人截獲並篡改

完整性驗證算法

  • 常見的有 MD五、SHA一、SHA256,該類函數特色是函數單向不可逆、對輸入很是敏感、輸出長度固定,針對數據的任何修改都會改變散列函數的結果,用於防止信息篡改並驗證數據的完整性
  • 在信息傳輸過程當中,散列函數不能單獨實現信息防篡改,由於明文傳輸,中間人能夠修改信息以後從新計算信息摘要,所以須要對傳輸的信息以及信息摘要進行加密

密鑰協商

密鑰協商
HTTPS

身份驗證

因爲非對稱加密沒法確保服務器身份的合法性,存在中間人攻擊的風險,例如:

  1. 客戶端 C 和服務器 S 進行通訊,中間節點 M 截獲了兩者的通訊
  2. 節點 M 本身計算產生一對公鑰pub_M和私鑰 pri_M
  3. C 向 S 請求公鑰時,M 把本身的公鑰pub_M發給了 C
  4. C 使用公鑰pub_M加密的數據可以被M解密,由於M掌握對應的私鑰pri_M,而C沒法根據公鑰信息判斷服務器的身份,從而 C 和 M 之間創建了「可信」加密鏈接
  5. 中間節點 M 和服務器S之間再創建合法的鏈接,所以 C 和 S 之間通訊被M徹底掌握,M 能夠進行信息的竊聽、篡改等操做。
    證書
  • 服務方 Server 向第三方機構CA提交公鑰、組織信息、我的信息(域名)等信息並申請認證;
  • CA經過線上、線下等多種手段驗證申請者提供信息的真實性,如組織是否存在、企業是否合法,是否擁有域名的全部權等;
  • 如信息審覈經過,CA會向申請者簽發認證文件-證書。證書包含如下信息:申請者公鑰、申請者的組織信息和我的信息、簽發機構CA的信息、有效時間、證書序列號等信息的明文,同時包含一個簽名; 簽名的產生算法:首先,使用散列函數計算公開的明文信息的信息摘要,而後,採用CA的私鑰對信息摘要進行加密,密文即簽名;
  • 客戶端 Client 向服務器 Server 發出請求時,Server 返回證書文件;
  • 客戶端 Client 讀取證書中的相關的明文信息,採用相同的散列函數計算獲得信息摘要,而後,利用對應 CA的公鑰解密簽名數據,對比證書的信息摘要,若是一致,則能夠確認證書的合法性,即公鑰合法;
  • 客戶端還會驗證證書相關的域名信息、有效時間等信息;客戶端會內置信任CA的證書信息(包含公鑰),若是CA不被信任,則找不到對應 CA的證書,證書也會被斷定非法。
  • 客戶端的證書從生產出來以後就內置在主機中

搭建一個HTTPS服務器

搭建一個HTTPS服務器

結語

前端必須懂的計算機網絡知識系列已經所有結束,歡迎你們研究討論!

相關文章
相關標籤/搜索