五年面試,三年模擬

css部分

rem原理

  • rem佈局的本質是等比縮放,通常是基於寬度,假設將屏幕寬度分爲100份,每份寬度是1rem,1rem的寬度是屏幕寬度/100,,而後子元素設置rem單位的屬性,

經過改變html元素的字體大小,就能夠設置子元素的實際大小。javascript

  • rem佈局加載閃爍的問題
    • 解決方案,媒體查詢設置根元素字體大小,好比設計稿是750px;對應的開發方式是1rem=100px,那375px的font-size 大小就是50px(具體方法能夠百度一下)
  • 比rem更好的方案(缺點兼容很差)
    • vw(1vw是視口寬度的1%,100vw就是視口寬度),vh(100vh就是視口高度)

實現三欄佈局(兩側定寬,中間自適應)

  1. 採用了 absolute,致使父元素脫離了文檔流,那全部的子元素也須要脫離文檔流。若是頁面複雜,那開發的難度可想而知
  2. 利用浮動 當中間內容高於兩側時,兩側高度不會隨中間內容變高而變高
  3. 彈性盒子佈局(flex)
  4. 利用負邊距和浮動,實現起來比較複雜
  5. 利用網格佈局
.container {
    display: grid;
    grid-template-columns: 100px auto 200px;
}
複製代碼

BFC(塊級格式化上下文)

  • BFC 的原理

其實也就是 BFC 的渲染規則(能說出如下四點就夠了)。包括: 1. BFC 內部的子元素,在垂直方向,邊距會發生重疊。 2. BFC在頁面中是獨立的容器,外面的元素不會影響裏面的元素,反之亦然。 3. BFC區域不與旁邊的float box區域重疊。(能夠用來清除浮動帶來的影響)。 4. 計算BFC的高度時,浮動的子元素也參與計算。php

  • 如何生成BFC
    • 方法1:overflow: 不爲visible,可讓屬性是 hidden、auto。【最經常使用】
    • 方法2:浮動中:float的屬性值不爲none。意思是,只要設置了浮動,當前元素就建立了BFC。
    • 方法3:定位中:只要posiiton的值不是 static或者是relative便可,能夠是absolute或fixed,也就生成了一個BFC。
    • 方法4:display爲inline-block, table-cell, table-caption, flex, inline-flex
  • BFC應用
    • 阻止margin重疊
    • 能夠包含浮動元素 —— 清除內部浮動(清除浮動的原理是兩個div都位於同一個 BFC 區域之中)
    • 自適應兩欄佈局
    • 能夠阻止元素被浮動元素覆蓋

flex(面試常問,略)

盒子模型

  1. css的盒模型由content(內容)、padding(內邊距)、border(邊框)、margin(外邊距)組成。
  2. 在w3c盒模型中,設置的width/height是content的寬度/高度,在怪異模式中width/height設置的是content+padding+border寬度/高度。
  3. 在w3c盒子模型中盒子的大小由content、padding、border決定,在在怪異模式中盒子大小由width和height決定。

js部分

call, apply, bind區別? 怎麼實現call,apply方法

Function.prototype.myBind = function(content) {
    if(typeof this !='function'){
        throw Error('not a function')
    }
    let _this = this;
    let args = [...arguments].slice(1) 
    let resFn=function(){
        return _this.apply(this instanceof resFn?this:content,args.concat(...arguments))
    }
    return resFn
};
 
 /** * 每一個函數均可以調用call方法,來改變當前這個函數執行的this關鍵字,而且支持傳入參數 */
Function.prototype.myCall=function(context=window){
      context.fn = this;//此處this是指調用myCall的function
      let args=[...arguments].slice(1);
      let result=content.fn(...args)
      //將this指向銷燬
      delete context.fn;
      return result;
}
/** * apply函數傳入的是this指向和參數數組 */
Function.prototype.myApply = function(context=window) {
    context.fn = this;
    let result;
    if(arguments[1]){
        result=context.fn(...arguments[1])
    }else{
        result=context.fn()
    }
    //將this指向銷燬
    delete context.fn;
    return result;
}
複製代碼

函數柯里化

js繼承,構造函數,原型鏈,構造函數、原型鏈組合式繼承,寄生式組合繼承,Object.create polyfill;

數組去重

[...new Set(arr)]
複製代碼
var arr = [1,2,1,2,3,5,4,5,3,4,4,4,4],
    init=[]
var result = arr.sort().reduce((init, current)=>{
    console.log(init,current)
    if(init.length===0 || init[init.length-1]!==current){
        init.push(current);
    }
    return init;
}, []);
console.log(result);//1,2,3,4,5
複製代碼

防抖節流

var deBounce=function(fn,wait=300){
    let timer
    return function(){
      if(timer){
          clearTimeOut(timer)
      }
      timer=setTimeOut(()=>{
          fn.apply(this,arguments)
      },wait)
    } 
}
 var throttle = function (fn, wait = 300) {
        let prev = +new Date();
        return function () {
          const args = argument,
          now = +new Date();
          if (now > prev + wait) {
            prev = now;
            fn.apply(this, args)
          }
        }
     }
複製代碼

實現Promise思路

//0 pending,1 resolve,2 reject 

function Promise(fn) {...
	this._state = 0 // 狀態標記
	doResolve(fn, this)
}

function doResolve(fn, self) {
	var done = false // 保證只執行一個監聽
	try {
		fn(function(value) {
			if (done) return
			done = true
			resolve(self, value)
		}, function(reason) {
			if (done) return;
			done = true
			reject(self, value)
		})
	} catch (err) {
		if (done) return
		done = true
		reject(self, err)
	}
}

function resolve(self, newValue) {
	try {
		self._state = 1;
		...
	} catch (err) {
		reject(self, err)
	}
}

function reject(self, newValue) {
	self._state = 2;
	...
	if (!self._handled) {
		Promise._unhandledRejectionFn(self._value);
	}
}
複製代碼

實現深拷貝

funtion deepCopy(obj){
    let result;
   if(typeofObj=='object'){
       //複雜數據類型
       result=obj.constructor==Array?[]:{}
       for (let i in obj){
           result[i]=typeof obj[i]=='object'?deepCopy(obj[i]):obj[i]
       }
   }else{
       //簡單數據類型
       result=obj
   }
   return result
}
複製代碼

正則實現千位分隔符

function commafy(num) {
        return num && num
            .toString()
            .replace(/(\d)(?=(\d{3})+\.)/g, function($0, $1) {
                return $1 + ",";
            });
    }
 console.log(commafy(1312567.903000))
複製代碼

js事件循環

javascript是單線程語言,任務設計成了兩類,同步任務和異步任務 同步和異步任務分別進入不一樣的執行「場所」,同步進入主線程,異步進入Event Table並註冊函數。當指定的事情完成時,Event Table會將這個函數移入Event Queue。主線程內的任務執行完畢爲空,回去了Event Queue讀取對應的函數,進入主線程。 上述過程會不斷重複,也就是常說的Event Loop(事件循環)。 可是,JS異步還有一個機制,就是遇到宏任務,先執行宏任務,將宏任務放入event queue,而後再執行微任務,將微任務放入eventqueue,可是,這兩個queue不是一個queue。當你往外拿的時候先從微任務裏拿這個回調函數,而後再從宏任務的queue拿宏任務的回調函數 宏任務通常包括:總體代碼script,setTimeout,setInterval。 微任務:Promise,process.nextTickcss

事件流機制,事件委託 event.targe和event.currentTarget的區別

  • 事件冒泡和事件捕獲
  • 事件流分爲:冒泡和捕獲,順序是先捕獲再冒泡。
  • 事件冒泡:子元素的觸發事件會一直向父節點傳遞,一直到根結點中止。此過程當中,能夠在每一個節點捕捉到相關事件。能夠經過stopPropagation方法終止冒泡。
  • 事件捕獲:和「事件冒泡」相反,從根節點開始執行,一直向子節點傳遞,直到目標節點。
  • 事件捕獲階段

addEventListener給出了第三個參數同時支持冒泡與捕獲:默認是false,事件冒泡;設置爲true時,是事件捕獲。html

  • 事件委託 事件委託是指將事件綁定目標元素的到父元素上,利用冒泡機制觸發該事件前端

    • 能夠減小事件註冊,節省大量內存佔用能夠將事件應用於動態添加的子元素上
  • event.target返回觸發事件的元素vue

  • event.currentTarget返回綁定事件的元素java

new的過程以及實現new

//方法1
function create(){
   //1.建立一個空對象
   let obj={}
   //2.獲取構造函數
   let Con=[].shift.call(arguments)
   //3.設置空對象的原型
   obj._proto_=Con.prototype
   //4.綁定this並執行構造函數,給新對象添加屬性和方法
   let result=Con.apply(obj,arguments)
   //5.確保返回值爲對象
   return result instanceof Object?result:obj
}
//方法2
//經過分析原生的new方法能夠看出,在new一個函數的時候,
// 會返回一個func同時在這個func裏面會返回一個對象Object,
// 這個對象包含父類func的屬性以及隱藏的__proto__
function New(f) {
    //返回一個func
    return function () {
        var o = {"__proto__": f.prototype};
        f.apply(o, arguments);//繼承父類的屬性

        return o; //返回一個Object
    }
}
複製代碼

封裝ajax

/* 封裝ajax函數 * @param {string}opt.type http鏈接的方式,包括POST和GET兩種方式 * @param {string}opt.url 發送請求的url * @param {boolean}opt.async 是否爲異步請求,true爲異步的,false爲同步的 * @param {object}opt.data 發送的參數,格式爲對象類型 * @param {function}opt.success ajax發送並接收成功調用的回調函數 */
function myAjax(opt){
     opt = opt || {};
     opt.method = opt.method.toUpperCase() || 'POST';
     opt.url = opt.url || '';
     opt.async = opt.async || true;
     opt.data = opt.data || null;
     opt.success = opt.success || function () {}
     let xmlHttp = null;
     if (XMLHttpRequest) {
        xmlHttp = new XMLHttpRequest();
     }else{
         xmlHttp =new ActiveXObject('Microsoft.XMLHTTP')
     }
     let params;
    for (var key in opt.data){
        params.push(key + '=' + opt.data[key]);
    }
    let postData = params.join('&');
    if (opt.method.toUpperCase() === 'POST') {
        xmlHttp.open(opt.method, opt.url, opt.async);
        xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
        xmlHttp.send(postData);
    }else if (opt.method.toUpperCase() === 'GET') {
        xmlHttp.open(opt.method, opt.url + '?' + postData, opt.async);
        xmlHttp.send(null);
    } 
     xmlHttp.onreadystatechange= function () {
            if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                opt.success(xmlHttp.responseText);//若是是json數據能夠在這使用opt.success(JSON.parse( xmlHttp.responseText))
            }
     };
}
複製代碼

url拿參數

var url = "http://www.taobao.com/index.php?key0=0&key1=1&key2=2";
function parseQueryString(url){
    var str = url.split("?")[1],    //經過?獲得一個數組,取?後面的參數
        items = str.split("&");    //分割成數組
    var arr,name,value;

    for(var i=0; i<items.length; i++){
        arr = items[i].split("=");    //["key0", "0"]
        name = arr[0];
        value = arr[1];
        this[name] = value;
    }
}

var obj = new parseQueryString(url);
alert(obj.key2)
複製代碼

HTTP部分

http協議

HTTP協議(超文本傳輸協議)react

  • 1.0 協議缺陷:
  • 沒法複用連接,完成即斷開,從新慢啓動和 TCP 3次握手
  • head of line blocking: 線頭阻塞,致使請求之間互相影響

1.1 改進:面試

  • 長鏈接(默認 keep-alive),複用
  • host 字段指定對應的虛擬站點
  • 新增功能:
    • 斷點續傳
    • 身份認證
    • 狀態管理
    • cache 緩存
      • Cache-Control
      • Expires
      • Last-Modified
      • Etag
  • 2.0:
  • 多路複用
  • 二進制分幀層: 應用層和傳輸層之間
  • 首部壓縮
  • 服務端推送

HTTP之請求消息Requestajax

  1. 請求行(request line)、請求頭部(header)、空行和請求數據四個部分組成。
  2. 請求行,用來講明請求類型,要訪問的資源以及所使用的HTTP版本.
  3. 請求頭部,緊接着請求行(即第一行)以後的部分,用來講明服務器要使用的附加信息
  4. 空行,請求頭部後面的空行是必須的
  5. 請求數據也叫主體,能夠添加任意的其餘數據。

HTTP之響應消息Response

HTTP響應也由四個部分組成,分別是:狀態行、消息報頭、空行和響應正文。

  1. 狀態行,由HTTP協議版本號, 狀態碼, 狀態消息 三部分組成。
  2. 消息報頭,用來講明客戶端要使用的一些附加信息
  3. 第三部分:空行,消息報頭後面的空行是必須的
  4. 第四部分:響應正文,服務器返回給客戶端的文本信息。

在瀏覽器地址欄鍵入URL,按下回車以後會經歷如下流程:

  1. 瀏覽器向 DNS 服務器請求解析該 URL 中的域名所對應的 IP 地址;
  2. 創建TCP鏈接(三次握手);
  3. 瀏覽器發出讀取文件(URL 中域名後面部分對應的文件)的HTTP 請求,該請求報文做爲 TCP 三次握手的第三個報文的數據發送給服務器;
  4. 服務器對瀏覽器請求做出響應,並把對應的 html 文本發送給瀏覽器;
  5. 釋放 TCP鏈接(四次揮手);
  6. 瀏覽器將該 html 文本並顯示內容;

三次握手

SYN (同步序列編號)ACK(確認字符)

  1. 第一次握手:Client將標誌位SYN置爲1,隨機產生一個值seq=J,並將該數據包發送給Server,Client進入SYN_SENT狀態,等待Server確認。
  2. 第二次握手:Server收到數據包後由標誌位SYN=1知道Client請求創建鏈接,Server將標誌位SYN和ACK都置爲1,ack=J+1,隨機產生一個值seq=K,並將該數據包發送給Client以確認鏈接請求,Server進入SYN_RCVD狀態。
  3. 第三次握手:Client收到確認後,檢查ack是否爲J+1,ACK是否爲1,若是正確則將標誌位ACK置爲1,ack=K+1,並將該數據包發送給Server,Server檢查ack是否爲K+1,ACK是否爲1,若是正確則鏈接創建成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨後Client與Server之間能夠開始傳輸數據了。

四次揮手

  1. 第一次揮手:Client發送一個FIN,用來關閉Client到Server的數據傳送,Client進入FIN_WAIT_1狀態。
  2. 第二次揮手:Server收到FIN後,發送一個ACK給Client,確認序號爲收到序號+1(與SYN相同,一個FIN佔用一個序號),Server進入CLOSE_WAIT狀態。
  3. 第三次揮手:Server發送一個FIN,用來關閉Server到Client的數據傳送,Server進入LAST_ACK狀態。
  4. 第四次揮手:Client收到FIN後,Client進入TIME_WAIT狀態,接着發送一個ACK給Server,確認序號爲收到序號+1,Server進入CLOSED狀態,完成四次揮手。

爲何創建鏈接是三次握手,而關閉鏈接倒是四次揮手呢?

這是由於服務端在LISTEN狀態下,收到創建鏈接請求的SYN報文後,把ACK和SYN放在一個報文裏發送給客戶端。而關閉鏈接時,當收到對方的FIN報文時,僅僅表示對方再也不發送數據了可是還能接收數據,己方也未必所有數據都發送給對方了,因此己方能夠當即close,也能夠發送一些數據給對方後,再發送FIN報文給對方來表示贊成如今關閉鏈接,所以,己方ACK和FIN通常都會分開發送。

網頁生成的過程,大體能夠分爲五步:

  1. html代碼轉化爲dom
  2. css代碼轉化爲cssom
  3. 結合dom和cssom,生成一顆渲染樹
  4. 生成佈局layout,即將全部的渲染樹的節點進行平面合成
  5. 將佈局繪製paint在屏幕上(能夠拓展講一下減小瀏覽器渲染的迴流和重繪)

HTTPS的工做原理

非對稱加密與對稱加密雙劍合璧,使用非對稱加密算法傳遞用於對稱加密算法的密鑰,而後使用對稱加密算法進行信息傳遞。這樣既安全又高效

瀏覽器緩存

當瀏覽器再次訪問一個已經訪問過的資源時,它會這樣作:

  1. 看看是否命中強緩存,若是命中,就直接使用緩存了。
  2. 若是沒有命中強緩存,就發請求到服務器檢查是否命中協商緩存。
  3. 若是命中協商緩存,服務器會返回 304 告訴瀏覽器使用本地緩存。
  4. 不然,返回最新的資源。
  5. 強緩存
    • Expires
    • Cache-control
  6. 協商緩存
    • Last-Modified/If-Modified-Since
    • Etag/If-None-Match

vue&react

Virtual DOM

其實 VNode 是對真實 DOM 的一種抽象描述,它的核心定義無非就幾個關鍵屬性,標籤名、數據、子節點、鍵值等,其它屬性都是都是用來擴展 VNode 的靈活性以及實現一些特殊 feature 的。因爲 VNode 只是用來映射到真實 DOM 的渲染,不須要包含操做 DOM 的方法,所以它是很是輕量和簡單的。 Virtual DOM 除了它的數據結構的定義,映射到真實的 DOM 實際上要經歷 VNode 的 create(用JS對象模擬DOM樹)、diff(比較兩棵虛擬DOM樹的差別)、patch(把差別應用到真正的DOM樹上) 等過程。

diff算法

  • diff算法比較新舊節點的時候,比較只會在同層級比較,不會跨層級比較
  • 當數據發生變化的時候會生成一個新的VNode,而後新VNode和oldNode作對比,發現不同的地方直接修改在真實的dom上,比較新舊節點,一邊比較一邊給真是的dom打補丁
  • 節點設置key能夠高效的利用dom(key最好不要設置成index索引)
  • 虛擬DOM diff算法主要就是對如下三種場景進行優化:
  1. tree diff

對樹進行分層比較,兩棵樹只會對同一層次的節點進行比較。(由於 DOM 節點跨層級的移動操做少到能夠忽略不計) 若是父節點已經不存在,則該節點及其子節點會被徹底刪除掉,不會用於進一步的比較。 注意: React 官方建議不要進行 DOM 節點跨層級的操做,很是影響 React 性能。 在開發組件時,保持穩定的 DOM 結構會有助於性能的提高。例如,能夠經過 CSS 隱藏或顯示節點,而不是真的移除或添加 DOM 節點。

  1. component diff

若是是同一類型的組件,按照原策略繼續比較 virtual DOM tree(tree diff)。 對於同一類型的組件,有可能其 Virtual DOM 沒有任何變化,若是可以確切的知道這點那能夠節省大量的 diff 運算時間,所以 React 容許用戶經過 shouldComponentUpdate() 來判斷該組件是否須要進行 diff。 若是不是,直接替換整個組件下的全部子節點。

  1. element diff

對處於同一層級的節點進行對比。 這時 React 建議:添加惟一 key 進行區分。雖然只是小小的改動,性能上卻發生了翻天覆地的變化! 如: A B C D --> B A D C 添加 key 以前: 發現 B != A,則建立並插入 B 至新集合,刪除老集合 A;以此類推,建立並插入 A、D 和 C,刪除 B、C 和 D。 添加 key 以後: B、D 不作任何操做,A、C 進行移動操做,便可。 建議:在開發過程當中,儘可能減小相似將最後一個節點移動到列表首部的操做,當節點數量過大或更新操做過於頻繁時,在必定程度上會影響 React 的渲染性能。

  1. 總結
  • React 經過制定大膽的 diff 策略,將 O(n3) 複雜度的問題轉換成 O(n) 複雜度的問題;
  • React 經過分層求異的策略,對 tree diff 進行算法優化;
  • React 經過相同類生成類似樹形結構,不一樣類生成不一樣樹形結構的策略,對 component diff 進行算法優化;
  • React 經過設置惟一 key的策略,對 element diff 進行算法優化;
  • 建議,在開發組件時,保持穩定的 DOM 結構會有助於性能的提高;
  • 建議,在開發過程當中,儘可能減小相似將最後一個節點移動到列表首部的操做,當節點數量過大或更新操做過於頻繁時,在必定程度上會影響 React 的渲染性能。

vue的響應式原理

  • Object.defineProperty(obj, prop, descriptor)
  • obj 是要在其上定義屬性的對象;prop 是要定義或修改的屬性的名稱;descriptor 是將被定義或修改的屬性描述符。

比較核心的是 descriptor,它有不少可選鍵值,具體的能夠去參閱它的文檔。這裏咱們最關心的是 get 和 set,get 是一個給屬性提供的 getter 方法,當咱們訪問了該屬性的時候會觸發 getter 方法;set 是一個給屬性提供的 setter 方法,當咱們對該屬性作修改的時候會觸發 setter 方法。一旦對象擁有了 getter 和 setter,咱們能夠簡單地把這個對象稱爲響應式對象 - 對象遞歸調用 - 數組變異方法的解決方法:代理原型/實例方法

  • observe
  • observe 方法的做用就是給非 VNode 的對象類型數據添加一個 Observer,若是已經添加過則直接返回,不然在知足必定條件下去實例化一個 Observer 對象實例。
  • observe 的功能就是用來監測數據的變化.
  • Observer 是一個類,它的做用是給對象的屬性添加 getter 和 setter,用於依賴收集和派發更新:
  • 依賴收集和派發更新
  • 收集依賴的目的是爲了當這些響應式數據發生變化,觸發它們的 setter 的時候,能知道應該通知哪些訂閱者去作相應的邏輯處理,咱們把這個過程叫派發更新,其實 Watcher 和 Dep 就是一個很是經典的觀察者設計模式的實現
  • 派發更新就是數據發生變化的時候,觸發 setter 邏輯,把在依賴過程當中訂閱的的全部觀察者,也就是 watcher,都觸發它們的 update 過程,這個過程又利用了隊列作了進一步優化,在 nextTick 後執行全部 watcher 的 run,最後執行它們的回調函數
  • vue編譯Compile的過程主要分如下幾步

parse(生成AST)=> optimize(優化靜態節點) => generate(生成render function)

// 解析模板字符串生成 AST
const ast = parse(template.trim(), options)
//優化語法樹
optimize(ast, options)
//生成代碼
const code = generate(ast, options)
複製代碼

vue compute和watch的區別

  • computed 是計算屬性,依賴其餘屬性計算值,而且 computed 的值有緩存,只有當計算值變化纔會返回內容。
  • watch 監聽到值的變化就會執行回調,在回調中能夠進行一些邏輯操做。
  • 因此通常來講須要依賴別的屬性來動態得到值的時候可使用computed,對於監聽到值的變化須要作一些複雜業務邏輯的狀況可使用 watch。

對vuex的理解,單向數據流

vuex

  • state: 狀態中心
  • mutations: 更改狀態
  • actions: 異步更改狀態
  • getters: 獲取狀態
  • modules: 將state分紅多個modules,便於管理
    • mutations和action的區別

前端路由的兩種實現原理

  1. Hash模式
  • window對象提供了onhashchange事件來監聽hash值的改變,一旦url中的hash值發生改變,便會觸發該事件。
  1. History 模式
  • popstate監聽歷史棧信息變化,變化時從新渲染
  • 使用pushState方法實現添加功能
  • 使用replaceState實現替換功能

前端安全

XSS和CSRF

  • XSS:跨站腳本攻擊,是一種網站應用程序的安全漏洞攻擊,是代碼注入的一種。常見方式是將惡意代碼注入合法代碼裏隱藏起來,再誘發惡意代碼,從而進行各類各樣的非法活動。

預防:

  • 使用XSS Filter
    1. 輸入過濾,對用戶提交的數據進行有效性驗證,僅接受指定長度範圍內並符合咱們指望格式的的內容提交,阻止或者忽略除此外的其餘任何數據。
    2. 輸出轉義,當須要將一個字符串輸出到Web網頁時,同時又不肯定這個字符串中是否包括XSS特殊字符,爲了確保輸出內容的完整性和正確性,輸出HTML屬性時可使用HTML轉義編碼(HTMLEncode)進行處理,輸出到<script>中,能夠進行JS編碼。
  • 使用 HttpOnly Cookie

將重要的cookie標記爲httponly,這樣的話當瀏覽器向Web服務器發起請求的時就會帶上cookie字段,可是在js腳本中卻不能訪問這個cookie,這樣就避免了XSS攻擊利用JavaScript的document.cookie獲取cookie。

  • CSRF:跨站請求僞造,也稱 XSRF,是一種挾制用戶在當前已登陸的Web應用程序上執行非本意的操做的攻擊方法。與 XSS 相比,XSS利用的是用戶對指定網站的信任,CSRF利用的是網站對用戶網頁瀏覽器的信任。
  1. 預防:用戶操做限制——驗證碼機制
  • 方法:添加驗證碼來識別是否是用戶主動去發起這個請求,因爲必定強度的驗證碼機器沒法識別,所以危險網站不能僞造一個完整的請求。
  • 優勢:簡單粗暴,低成本,可靠,能防範99.99%的攻擊者。
  • 缺點:對用戶不友好。
  1. 請求來源限制——驗證 HTTP Referer 字段
  • 方法:在HTTP請求頭中有一個字段叫Referer,它記錄了請求的來源地址。 服務器須要作的是驗證這個來源地址是否合法,若是是來自一些不受信任的網站,則拒絕響應。
  • 優勢:零成本,簡單易實現。
  • 缺點:因爲這個方法嚴重依賴瀏覽器自身,所以安全性全看瀏覽器。
  • 額外驗證機制——token的使用
  1. 方法:使用token來代替驗證碼驗證。因爲黑客並不能拿到和看到cookie裏的內容,因此沒法僞造一個完整的請求。基本思路以下:
  2. 服務器隨機產生token(好比把cookie hash化生成),存在session中,放在cookie中或者以ajax的形式交給前端。
    • 前端發請求的時候,解析cookie中的token,放到請求url裏或者請求頭中。

    • 服務器驗證token,因爲黑客沒法獲得或者僞造token,因此能防範csrf

相關文章
相關標籤/搜索