談談JS中的函數劫持

寫於 2016.09.21javascript

說到劫持,第一反應多是什麼很差的東西。函數劫持並不邪惡,關鍵是看使用的人。雖然這個概念在前端領域使用較少,可是在安全領域、自定義業務等場景下仍是有必定的使用價值的。因此,這一篇文章將會和你們一塊兒去了解一下JS中的函數劫持是什麼,有什麼用。html

基本概念

函數劫持,顧名思義,即在一個函數運行以前把它劫持下來,添加咱們想要的功能。當這個函數實際運行的時候,它已經不是本來的函數了,而是帶上了被咱們添加上去的功能。這也是咱們常見的鉤子函數的原理之一。前端

乍一看上去,這很像是函數的改寫。函數的改寫也能夠理解爲是函數劫持的一種,可是這種方式太噁心了。做爲一個劫持者,在綁票得到好處之後也應該遵照職業道德,把人原封不動地還回去,因此咱們得在合適的地方把函數本來的功能給從新調用回來。java

推而廣之,其實「劫持」這一律念咱們常常會遇到,比方說某網站被運營商劫持了,在瀏覽該網站的時候會彈出運營商的廣告。安全

舉例分析

如今咱們來舉個簡單的例子,劫持一下alert()函數,爲它增添一點小小的功能:bash

let warn = alert
window.alert = (t) => {
    if (confirm('How are you?')) warn(t)
}

alert('Help me...!!!')
複製代碼

能夠打開開發者工具嘗試一下這個例子,你會發現只有你在confirm裏面點擊了OK,纔會彈出Help me...!!!函數

接下來咱們把這部分的內容封裝一下,成爲一個通用的函數:工具

const hijack = (obj, method, fun) => {
  let orig = obj[method]
  obj[method] = fun(orig)
}
複製代碼

首先咱們定義了一個hijack函數,它會先把原函數給保存下來,而後執行自定義函數,而原函數將會在自定義函數內部進行調用。學習

而後咱們來劫持confirm()函數:測試

hijack(window, 'confirm', (orig) => {
  return (text) => {
    alert('HELP ME PLZ!!!')
    if (orig.call(this, text)) {
      alert('YOU SEEMS FINE AND I AM LEAVING, GOOD BYE!')
    } else {
      alert('HOLD ON! I AM COMING!!')
    }
  }
})
複製代碼

這段函數的功能很簡單就不詳細說明了,直接調用confirm()你就知道了: codepen例子

反劫持

新建一個頁面,打開你的開發者工具控制檯,輸入alert,你會看到這樣的輸出:

function alert() { [native code] }
複製代碼

而後使用本文開頭的那段代碼,把alert()劫持一下,再從新在控制檯輸入alert,你會看到這樣的輸出:

function (t) => {
    if (confirm('How are you?')) warn(t)
}
複製代碼

經過上述的例子能夠知道,要看一個函數是否被劫持了,只須要直接把它打印出來便可。針對系統原生的函數,[native code]即表明它是純淨無污染的。

函數劫持的做用

除了爲函數增長功能之外,還可以利用函數劫持去追蹤惡意用戶的信息。通常的XSS攻擊會先利用alert()等可以輸出信息的方法進行測試,這時候咱們能夠先對原生alert()進行劫持,向其輸入追蹤信息的代碼,最後才把原函數釋放出去。當惡意用戶在測試alert()的時候就會當即被咱們追蹤,而他本人卻無從察覺。

後記

關於JS的函數劫持,也不是什麼新鮮的東西,只是在最近的工做中遇到了這個知識點感受比較陌生,因此花了一些時間進行了研究,並把結果記錄下來。若是發現有什麼錯漏的地方歡迎指正!

感謝你的閱讀,歡迎關注個人專欄,我將不按期分享本身的學習體驗,開發心得,搬運牆外的乾貨。下次見啦!


參考資料:

相關文章
相關標籤/搜索