整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          教你怎么用JavaScript檢測當(dāng)前瀏覽器是無頭瀏

          教你怎么用JavaScript檢測當(dāng)前瀏覽器是無頭瀏覽器

          么是無頭瀏覽器(headless browser)?

          無頭瀏覽器是指可以在圖形界面情況下運行的瀏覽器。我可以通過編程來控制無頭瀏覽器自動執(zhí)行各種任務(wù),比如做測試,給網(wǎng)頁截屏等。

          為什么叫“無頭”瀏覽器?

          “無頭”這個詞來源于最初的“無頭計算機(jī)(Headless computer)”。維基百科關(guān)于的“無頭計算機(jī)”詞條:

          無頭系統(tǒng)(headless system)是指已配置為無須顯示器(即“頭”)、鍵盤和鼠標(biāo)操作的計算機(jī)系統(tǒng)或設(shè)備。無頭系統(tǒng)通常通過網(wǎng)絡(luò)連接控制,但也有部分無頭系統(tǒng)的設(shè)備需要通過RS-232串行連接進(jìn)行設(shè)備的管理。服務(wù)器通常采用無頭模式以降低運作成本。

          為什么要檢測無頭瀏覽器?

          除了之前提到的兩種無害的使用案例,無頭瀏覽器可以被用來自動執(zhí)行惡意任務(wù)。最常見的形式是做網(wǎng)絡(luò)爬蟲,或偽裝訪問量,或探測網(wǎng)站漏洞。

          一個非常流行的無頭瀏覽器是PhantomJS,因為它是基于 Qt 框架,所以跟我們常見的瀏覽器相比有很多不同的特征,因此有很多方法判斷出它。

          但是,從chrome 59開始,谷歌發(fā)布了一款無頭谷歌瀏覽器。它跟PhantomJS不同,它是基于正統(tǒng)的谷歌瀏覽器開發(fā)出來的,不是基于其它的框架,這讓程序很難區(qū)分出它是正常瀏覽器還是無頭瀏覽器。

          下面,我們將介紹幾種判斷程序是運行在普通瀏覽器還是無頭瀏覽器里的方法。

          檢測無頭瀏覽器

          注意:這些方法只是在四種設(shè)備 (2 Linux, 2 Mac) 里測試過,也就是說, 肯定還有其他很多方法檢測無頭瀏覽器。

          User agent

          先介紹使用做最常見的一種判斷瀏覽器種類的方法,檢查User agent。在linux計算機(jī)里Chrome version 59無頭瀏覽器的User agent值是:

          “Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/59.0.3071.115 Safari/537.36”

          于是,我們可以這樣檢測是否是無頭Chrome瀏覽器:

           if (/HeadlessChrome/.test(window.navigator.userAgent)) {
            console.log("Chrome headless detected");
           }

          User agent 也可以從 HTTP headers 里獲取。然而,這兩種情況都很容易偽造。

          插件 Plugins

          navigator.plugins 會返回一個數(shù)組,里面是當(dāng)前瀏覽器里的插件信息。通常,普通Chrome瀏覽器有一些缺省插件,比如 Chrome PDF viewer 或 Google Native Client。相反,在無頭模式里,沒有任何插件,返回的是個空數(shù)組。

           if(navigator.plugins.length==0) {
            console.log("It may be Chrome headless");
           }

          語言

          在谷歌瀏覽器里,有兩個JavaScript屬性可以獲取當(dāng)前瀏覽器的語言設(shè)置: navigator.language 和 navigator.languages。頭一個是指瀏覽器界面的語言,后一個返回的是個數(shù)組,里面存儲的是瀏覽器用戶的所有次選語言。然而,在無頭模式里,navigator.languages 返回的是個空字符串。

           if(navigator.languages=="") {
            console.log("Chrome headless detected");
           }

          WebGL

          WebGL 提供了一組能在HTML canvas 里執(zhí)行3D渲染的API。通過這些API,我們可以查詢出圖形驅(qū)動的 vendor 和 renderer 。

          在linux上的普通谷歌瀏覽器里,我們獲得的 renderer 和 vendor 值為: “Google SwiftShader” 和 “Google Inc.”。

          而在無頭模式里,我們獲得的一個是 “Mesa OffScreen”——它是沒有使用任何 window 系統(tǒng)的渲染技術(shù)的名稱,和 “Brian Paul” ——開源 Mesa 圖形庫的最初的程序。

           var canvas=document.createElement('canvas');
           var gl=canvas.getContext('webgl');
            
           var debugInfo=gl.getExtension('WEBGL_debug_renderer_info');
           var vendor=gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
           var renderer=gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
            
           if(vendor=="Brian Paul" && renderer=="Mesa OffScreen") {
            console.log("Chrome headless detected");
           }


          并不是所有版本的無頭瀏覽器都有同樣的這兩個值。然而目前在無頭瀏覽器里是“Mesa Offscreen” 和 “Brian Paul” 這兩個值。

          瀏覽器特征

          Modernizr 可以探測出當(dāng)前瀏覽器對HTML和CSS各種特性的支持程度。我發(fā)現(xiàn),普通Chrome和無頭Chrome里唯一的區(qū)別是,無頭模式下沒有 hairline 特征,它是用來檢測是否支持 hidpi/retina hairlines的

           if(!Modernizr["hairline"]) {
            console.log("It may be Chrome headless");
           }

          加載失敗的圖片

          最后,我發(fā)現(xiàn)的最后一個方法,也是看起來最有效的方法,切入點是檢查瀏覽器里不能正常加載的圖片的高和寬。

          在正常的Chrome里,未成功加載的圖片的大小跟瀏覽器的zoom有關(guān),但肯定不是零。而在無頭Chrome瀏覽器里,這種圖片的寬和高都是0。

           ?
           var body=document.getElementsByTagName("body")[0];
           var image=document.createElement("img");
           image.src="http://iloveponeydotcom32188.jg";
           image.setAttribute("id", "fakeimage");
           body.appendChild(image);
           image.onerror=function(){
            if(image.width==0 && image.height==0) {
            console.log("Chrome headless detected");
            }
           } 

          這就是檢測無頭瀏覽器的詳細(xì)步驟

          這里小編是一個有著10年工作經(jīng)驗的前端高級工程師,關(guān)于web前端有許多的技術(shù)干貨,包括但不限于各大廠的最新面試題系列、前端項目、最新前端路線等。需要的伙伴可以私信我

          發(fā)送【前端資料】

          就可以獲取領(lǐng)取地址,免費送給大家。對于學(xué)習(xí)web前端有任何問題(學(xué)習(xí)方法,學(xué)習(xí)效率,如何就業(yè))都可以問我。希望你也能憑自己的努力,成為下一個優(yōu)秀的程序員

          者 | 浪里行舟

          責(zé)編 | 胡巍巍

          在互聯(lián)網(wǎng)時代,數(shù)據(jù)安全與個人隱私受到了前所未有的挑戰(zhàn),各種新奇的攻擊技術(shù)層出不窮。如何才能更好地保護(hù)我們的數(shù)據(jù)?本文主要側(cè)重于分析幾種常見的攻擊的類型以及防御的方法。

          XSS


          XSS (Cross-Site Scripting),跨站腳本攻擊,因為縮寫和 CSS重疊,所以只能叫 XSS。跨站腳本攻擊是指通過存在安全漏洞的Web網(wǎng)站注冊用戶的瀏覽器內(nèi)運行非法的HTML標(biāo)簽或JavaScript進(jìn)行的一種攻擊。

          跨站腳本攻擊有可能造成以下影響:

          • 利用虛假輸入表單騙取用戶個人信息。
          • 利用腳本竊取用戶的Cookie值,被害者在不知情的情況下,幫助攻擊者發(fā)送惡意請求。
          • 顯示偽造的文章或圖片。

          XSS 的原理是惡意攻擊者往 Web 頁面里插入惡意可執(zhí)行網(wǎng)頁腳本代碼,當(dāng)用戶瀏覽該頁之時,嵌入其中 Web 里面的腳本代碼會被執(zhí)行,從而可以達(dá)到攻擊者盜取用戶信息或其他侵犯用戶安全隱私的目的。

          XSS 的攻擊方式千變?nèi)f化,但還是可以大致細(xì)分為幾種類型。

          1.非持久型 XSS(反射型 XSS )

          非持久型 XSS 漏洞,一般是通過給別人發(fā)送帶有惡意腳本代碼參數(shù)的 URL,當(dāng) URL 地址被打開時,特有的惡意代碼參數(shù)被 HTML 解析、執(zhí)行。


          舉一個例子,比如頁面中包含有以下代碼:

           1<select>
           2 <script>
           3 document.write(''
           4 + '<option value=1>'
           5 + location.href.substring(location.href.indexOf('default=') + 8)
           6 + '</option>'
           7 );
           8 document.write('<option value=2>English</option>');
           9 </script>
          10</select>
          

          攻擊者可直接通過URL (類似:https://xxx.com/xxx?default=<script>alert(document.cookie)</script>) 注入可執(zhí)行的腳本代碼。不過一些瀏覽器如Chrome其內(nèi)置了一些XSS過濾器,可以防止大部分反射型XSS攻擊。

          非持久型 XSS 漏洞攻擊有以下幾點特征:

          • 即時性,不經(jīng)過服務(wù)器存儲,直接通過 HTTP 的 GET 和 POST 請求就能完成一次攻擊,拿到用戶隱私數(shù)據(jù)。
          • 攻擊者需要誘騙點擊,必須要通過用戶點擊鏈接才能發(fā)起
          • 反饋率低,所以較難發(fā)現(xiàn)和響應(yīng)修復(fù)
          • 盜取用戶敏感保密信息

          為了防止出現(xiàn)非持久型 XSS 漏洞,需要確保這么幾件事情:

          • Web 頁面渲染的所有內(nèi)容或者渲染的數(shù)據(jù)都必須來自于服務(wù)端。
          • 盡量不要從 URL,document.referrer,document.forms 等這種 DOM API 中獲取數(shù)據(jù)直接渲染。
          • 盡量不要使用eval, new Function(),document.write(),document.writeln(),window.setInterval(),window.setTimeout(),innerHTML,document.createElement() 等可執(zhí)行字符串的方法。
          • 如果做不到以上幾點,也必須對涉及 DOM 渲染的方法傳入的字符串參數(shù)做 escape 轉(zhuǎn)義。
          • 前端渲染的時候?qū)θ魏蔚淖侄味夹枰?escape 轉(zhuǎn)義編碼。

          2.持久型 XSS(存儲型 XSS)

          持久型 XSS 漏洞,一般存在于 Form 表單提交等交互功能,如文章留言,提交文本信息等,黑客利用的 XSS 漏洞,將內(nèi)容經(jīng)正常功能提交進(jìn)入數(shù)據(jù)庫持久保存,當(dāng)前端頁面獲得后端從數(shù)據(jù)庫中讀出的注入代碼時,恰好將其渲染執(zhí)行。

          舉個例子,對于評論功能來說,就得防范持久型 XSS 攻擊,因為我可以在評論中輸入以下內(nèi)容

          主要注入頁面方式和非持久型 XSS 漏洞類似,只不過持久型的不是來源于 URL,referer,forms 等,而是來源于后端從數(shù)據(jù)庫中讀出來的數(shù)據(jù) 。持久型 XSS 攻擊不需要誘騙點擊,黑客只需要在提交表單的地方完成注入即可,但是這種 XSS 攻擊的成本相對還是很高。

          攻擊成功需要同時滿足以下幾個條件:

          • POST 請求提交表單后端沒做轉(zhuǎn)義直接入庫。
          • 后端從數(shù)據(jù)庫中取出數(shù)據(jù)沒做轉(zhuǎn)義直接輸出給前端。
          • 前端拿到后端數(shù)據(jù)沒做轉(zhuǎn)義直接渲染成 DOM。

          持久型 XSS 有以下幾個特點:

          • 持久性,植入在數(shù)據(jù)庫中
          • 盜取用戶敏感私密信息
          • 危害面廣

          3.如何防御

          對于 XSS 攻擊來說,通常有兩種方式可以用來防御。

          1) CSP

          CSP 本質(zhì)上就是建立白名單,開發(fā)者明確告訴瀏覽器哪些外部資源可以加載和執(zhí)行。我們只需要配置規(guī)則,如何攔截是由瀏覽器自己實現(xiàn)的。我們可以通過這種方式來盡量減少 XSS 攻擊。

          通常可以通過兩種方式來開啟 CSP:

          • 設(shè)置 HTTP Header 中的 Content-Security-Policy
          • 設(shè)置 meta 標(biāo)簽的方式

          這里以設(shè)置 HTTP Header 來舉例:

          • 只允許加載本站資源
          1Content-Security-Policy: default-src 'self'
          
          • 只允許加載 HTTPS 協(xié)議圖片
          1Content-Security-Policy: img-src https://*
          
          • 允許加載任何來源框架


          1Content-Security-Policy: child-src 'none'
          


          如需了解更多屬性,請查看Content-Security-Policy文檔

          對于這種方式來說,只要開發(fā)者配置了正確的規(guī)則,那么即使網(wǎng)站存在漏洞,攻擊者也不能執(zhí)行它的攻擊代碼,并且 CSP 的兼容性也不錯。

          2) 轉(zhuǎn)義字符

          用戶的輸入永遠(yuǎn)不可信任的,最普遍的做法就是轉(zhuǎn)義輸入輸出的內(nèi)容,對于引號、尖括號、斜杠進(jìn)行轉(zhuǎn)義

           1function escape(str) {
           2 str=str.replace(/&/g, '&')
           3 str=str.replace(/</g, '<')
           4 str=str.replace(/>/g, '>')
           5 str=str.replace(/"/g, '&quto;')
           6 str=str.replace(/'/g, ''')
           7 str=str.replace(/`/g, '`')
           8 str=str.replace(/\//g, '/')
           9 return str
          10}
          

          但是對于顯示富文本來說,顯然不能通過上面的辦法來轉(zhuǎn)義所有字符,因為這樣會把需要的格式也過濾掉。對于這種情況,通常采用白名單過濾的辦法,當(dāng)然也可以通過黑名單過濾,但是考慮到需要過濾的標(biāo)簽和標(biāo)簽屬性實在太多,更加推薦使用白名單的方式。

          1const xss=require('xss')
          2let html=xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>')
          3// -> <h1>XSS Demo</h1><script>alert("xss");</script>
          4console.log(html)
          

          以上示例使用了 js-xss 來實現(xiàn),可以看到在輸出中保留了 h1 標(biāo)簽且過濾了 script 標(biāo)簽。

          3) HttpOnly Cookie。

          這是預(yù)防XSS攻擊竊取用戶cookie最有效的防御手段。Web應(yīng)用程序在設(shè)置cookie時,將其屬性設(shè)為HttpOnly,就可以避免該網(wǎng)頁的cookie被客戶端惡意JavaScript竊取,保護(hù)用戶cookie信息。

          CSRF


          CSRF(Cross Site Request Forgery),即跨站請求偽造,是一種常見的Web攻擊,它利用用戶已登錄的身份,在用戶毫不知情的情況下,以用戶的名義完成非法操作。

          1.CSRF攻擊的原理

          下面先介紹一下CSRF攻擊的原理:

          完成 CSRF 攻擊必須要有三個條件:

          • 用戶已經(jīng)登錄了站點 A,并在本地記錄了 cookie
          • 在用戶沒有登出站點 A 的情況下(也就是 cookie 生效的情況下),訪問了惡意攻擊者提供的引誘危險站點 B (B 站點要求訪問站點A)。
          • 站點 A 沒有做任何 CSRF 防御

          我們來看一個例子: 當(dāng)我們登入轉(zhuǎn)賬頁面后,突然眼前一亮驚現(xiàn)"XXX隱私照片,不看后悔一輩子"的鏈接,耐不住內(nèi)心躁動,立馬點擊了該危險的網(wǎng)站(頁面代碼如下圖所示),但當(dāng)這頁面一加載,便會執(zhí)行submitForm這個方法來提交轉(zhuǎn)賬請求,從而將10塊轉(zhuǎn)給黑客。

          2.如何防御

          防范 CSRF 攻擊可以遵循以下幾種規(guī)則:

          • Get 請求不對數(shù)據(jù)進(jìn)行修改
          • 不讓第三方網(wǎng)站訪問到用戶 Cookie
          • 阻止第三方網(wǎng)站請求接口
          • 請求時附帶驗證信息,比如驗證碼或者 Token

          1) SameSite

          可以對 Cookie 設(shè)置 SameSite 屬性。該屬性表示 Cookie 不隨著跨域請求發(fā)送,可以很大程度減少 CSRF 的攻擊,但是該屬性目前并不是所有瀏覽器都兼容。

          2) Referer Check

          HTTP Referer是header的一部分,當(dāng)瀏覽器向web服務(wù)器發(fā)送請求時,一般會帶上Referer信息告訴服務(wù)器是從哪個頁面鏈接過來的,服務(wù)器籍此可以獲得一些信息用于處理。可以通過檢查請求的來源來防御CSRF攻擊。正常請求的referer具有一定規(guī)律,如在提交表單的referer必定是在該頁面發(fā)起的請求。所以通過檢查http包頭referer的值是不是這個頁面,來判斷是不是CSRF攻擊。

          但在某些情況下如從https跳轉(zhuǎn)到http,瀏覽器處于安全考慮,不會發(fā)送referer,服務(wù)器就無法進(jìn)行check了。若與該網(wǎng)站同域的其他網(wǎng)站有XSS漏洞,那么攻擊者可以在其他網(wǎng)站注入惡意腳本,受害者進(jìn)入了此類同域的網(wǎng)址,也會遭受攻擊。出于以上原因,無法完全依賴Referer Check作為防御CSRF的主要手段。但是可以通過Referer Check來監(jiān)控CSRF攻擊的發(fā)生。

          3) Anti CSRF Token

          目前比較完善的解決方案是加入Anti-CSRF-Token。即發(fā)送請求時在HTTP 請求中以參數(shù)的形式加入一個隨機(jī)產(chǎn)生的token,并在服務(wù)器建立一個攔截器來驗證這個token。服務(wù)器讀取瀏覽器當(dāng)前域cookie中這個token值,會進(jìn)行校驗該請求當(dāng)中的token和cookie當(dāng)中的token值是否都存在且相等,才認(rèn)為這是合法的請求。否則認(rèn)為這次請求是違法的,拒絕該次服務(wù)。

          這種方法相比Referer檢查要安全很多,token可以在用戶登陸后產(chǎn)生并放于session或cookie中,然后在每次請求時服務(wù)器把token從session或cookie中拿出,與本次請求中的token 進(jìn)行比對。由于token的存在,攻擊者無法再構(gòu)造出一個完整的URL實施CSRF攻擊。但在處理多個頁面共存問題時,當(dāng)某個頁面消耗掉token后,其他頁面的表單保存的還是被消耗掉的那個token,其他頁面的表單提交時會出現(xiàn)token錯誤。

          4) 驗證碼

          應(yīng)用程序和用戶進(jìn)行交互過程中,特別是賬戶交易這種核心步驟,強(qiáng)制用戶輸入驗證碼,才能完成最終請求。在通常情況下,驗證碼夠很好地遏制CSRF攻擊。但增加驗證碼降低了用戶的體驗,網(wǎng)站不能給所有的操作都加上驗證碼。所以只能將驗證碼作為一種輔助手段,在關(guān)鍵業(yè)務(wù)點設(shè)置驗證碼。

          點擊劫持


          點擊劫持是一種視覺欺騙的攻擊手段。攻擊者將需要攻擊的網(wǎng)站通過 iframe 嵌套的方式嵌入自己的網(wǎng)頁中,并將 iframe 設(shè)置為透明,在頁面中透出一個按鈕誘導(dǎo)用戶點擊。

          1. 特點

          • 隱蔽性較高,騙取用戶操作
          • "UI-覆蓋攻擊"
          • 利用iframe或者其它標(biāo)簽的屬性

          2. 點擊劫持的原理

          用戶在登陸 A 網(wǎng)站的系統(tǒng)后,被攻擊者誘惑打開第三方網(wǎng)站,而第三方網(wǎng)站通過 iframe 引入了 A 網(wǎng)站的頁面內(nèi)容,用戶在第三方網(wǎng)站中點擊某個按鈕(被裝飾的按鈕),實際上是點擊了 A 網(wǎng)站的按鈕。

          接下來我們舉個例子:我在優(yōu)酷發(fā)布了很多視頻,想讓更多的人關(guān)注它,就可以通過點擊劫持來實現(xiàn)

           1iframe {
           2width: 1440px;
           3height: 900px;
           4position: absolute;
           5top: -0px;
           6left: -0px;
           7z-index: 2;
           8-moz-opacity: 0;
           9opacity: 0;
          10filter: alpha(opacity=0);
          11}
          12button {
          13position: absolute;
          14top: 270px;
          15left: 1150px;
          16z-index: 1;
          17width: 90px;
          18height:40px;
          19}
          20</style>
          21......
          22<button>點擊脫衣</button>
          23<img src="http://pic1.win4000.com/wallpaper/2018-03-19/5aaf2bf0122d2.jpg">
          24<iframe src="http://i.youku.com/u/UMjA0NTg4Njcy" scrolling="no"></iframe>
          


          從上圖可知,攻擊者通過圖片作為頁面背景,隱藏了用戶操作的真實界面,當(dāng)你按耐不住好奇點擊按鈕以后,真正的點擊的其實是隱藏的那個頁面的訂閱按鈕,然后就會在你不知情的情況下訂閱了。

          3. 如何防御

          1)X-FRAME-OPTIONS

          X-FRAME-OPTIONS是一個 HTTP 響應(yīng)頭,在現(xiàn)代瀏覽器有一個很好的支持。這個 HTTP 響應(yīng)頭 就是為了防御用 iframe 嵌套的點擊劫持攻擊。

          該響應(yīng)頭有三個值可選,分別是

          • DENY,表示頁面不允許通過 iframe 的方式展示
          • SAMEORIGIN,表示頁面可以在相同域名下通過 iframe 的方式展示
          • ALLOW-FROM,表示頁面可以在指定來源的 iframe 中展示

          2)JavaScript 防御

          對于某些遠(yuǎn)古瀏覽器來說,并不能支持上面的這種方式,那我們只有通過 JS 的方式來防御點擊劫持了。

           1<head>
           2 <style id="click-jack">
           3 html {
           4 display: none !important;
           5 }
           6 </style>
           7</head>
           8<body>
           9 <script>
          10 if (self==top) {
          11 var style=document.getElementById('click-jack')
          12 document.body.removeChild(style)
          13 } else {
          14 top.location=self.location
          15 }
          16 </script>
          17</body>
          以上代碼的作用就是當(dāng)通過 iframe 的方式加載頁面時,攻擊者的網(wǎng)頁直接不顯示所有內(nèi)容了。
          


          URL跳轉(zhuǎn)漏洞


          定義:借助未驗證的URL跳轉(zhuǎn),將應(yīng)用程序引導(dǎo)到不安全的第三方區(qū)域,從而導(dǎo)致的安全問題。

          1.URL跳轉(zhuǎn)漏洞原理

          黑客利用URL跳轉(zhuǎn)漏洞來誘導(dǎo)安全意識低的用戶點擊,導(dǎo)致用戶信息泄露或者資金的流失。其原理是黑客構(gòu)建惡意鏈接(鏈接需要進(jìn)行偽裝,盡可能迷惑),發(fā)在QQ群或者是瀏覽量多的貼吧/論壇中。

          安全意識低的用戶點擊后,經(jīng)過服務(wù)器或者瀏覽器解析后,跳到惡意的網(wǎng)站中。

          惡意鏈接需要進(jìn)行偽裝,經(jīng)常的做法是熟悉的鏈接后面加上一個惡意的網(wǎng)址,這樣才迷惑用戶。

          諸如偽裝成像如下的網(wǎng)址,你是否能夠識別出來是惡意網(wǎng)址呢?

          1http://gate.baidu.com/index?act=go&url=http://t.cn/RVTatrd
          2http://qt.qq.com/safecheck.html?flag=1&url=http://t.cn/RVTatrd
          3http://tieba.baidu.com/f/user/passport?jumpUrl=http://t.cn/RVTatrd
          

          2.實現(xiàn)方式:

          • Header頭跳轉(zhuǎn)
          • Javascript跳轉(zhuǎn)
          • META標(biāo)簽跳轉(zhuǎn)

          這里我們舉個Header頭跳轉(zhuǎn)實現(xiàn)方式:

          1<?php
          2$url=$_GET['jumpto'];
          3header("Location: $url");
          4?>
          1http://www.wooyun.org/login.php?jumpto=http://www.evil.com
          

          這里用戶會認(rèn)為www.wooyun.org都是可信的,但是點擊上述鏈接將導(dǎo)致用戶最終訪問www.evil.com這個惡意網(wǎng)址。

          3.如何防御

          1)referer的限制

          如果確定傳遞URL參數(shù)進(jìn)入的來源,我們可以通過該方式實現(xiàn)安全限制,保證該URL的有效性,避免惡意用戶自己生成跳轉(zhuǎn)鏈接

          2)加入有效性驗證Token

          我們保證所有生成的鏈接都是來自于我們可信域的,通過在生成的鏈接里加入用戶不可控的Token對生成的鏈接進(jìn)行校驗,可以避免用戶生成自己的惡意鏈接從而被利用,但是如果功能本身要求比較開放,可能導(dǎo)致有一定的限制。

          SQL注入


          SQL注入是一種常見的Web安全漏洞,攻擊者利用這個漏洞,可以訪問或修改數(shù)據(jù),或者利用潛在的數(shù)據(jù)庫漏洞進(jìn)行攻擊。

          1.SQL注入的原理

          我們先舉一個萬能鑰匙的例子來說明其原理:

          1<form action="/login" method="POST">
          2 <p>Username: <input type="text" name="username" /></p>
          3 <p>Password: <input type="password" name="password" /></p>
          4 <p><input type="submit" value="登陸" /></p>
          5</form>
          

          后端的 SQL 語句可能是如下這樣的:

          1let querySQL=`
          2 SELECT *
          3 FROM user
          4 WHERE username='${username}'
          5 AND psw='${password}'
          6`;
          7// 接下來就是執(zhí)行 sql 語句...
          8
          

          這是我們經(jīng)常見到的登錄頁面,但如果有一個惡意攻擊者輸入的用戶名是 admin' --,密碼隨意輸入,就可以直接登入系統(tǒng)了。why! ----這就是SQL注入。

          我們之前預(yù)想的SQL 語句是:

          1SELECT * FROM user WHERE username='admin' AND psw='password'
          


          但是惡意攻擊者用奇怪用戶名將你的 SQL 語句變成了如下形式:

          1SELECT * FROM user WHERE username='admin' --' AND psw='xxxx'
          


          在 SQL 中,' --是閉合和注釋的意思,-- 是注釋后面的內(nèi)容的意思,所以查詢語句就變成了:

          1SELECT * FROM user WHERE username='admin'
          

          所謂的萬能密碼,本質(zhì)上就是SQL注入的一種利用方式。

          一次SQL注入的過程包括以下幾個過程:

          • 獲取用戶請求參數(shù)
          • 拼接到代碼當(dāng)中
          • SQL語句按照我們構(gòu)造參數(shù)的語義執(zhí)行成功

          SQL注入的必備條件: 1.可以控制輸入的數(shù)據(jù) 2.服務(wù)器要執(zhí)行的代碼拼接了控制的數(shù)據(jù)。

          我們會發(fā)現(xiàn)SQL注入流程中與正常請求服務(wù)器類似,只是黑客控制了數(shù)據(jù),構(gòu)造了SQL查詢,而正常的請求不會SQL查詢這一步,SQL注入的本質(zhì):數(shù)據(jù)和代碼未分離,即數(shù)據(jù)當(dāng)做了代碼來執(zhí)行。

          2.危害

          • 獲取數(shù)據(jù)庫信息
          • 管理員后臺用戶名和密碼
          • 獲取其他數(shù)據(jù)庫敏感信息:用戶名、密碼、手機(jī)號碼、身份證、銀行卡信息……
          • 整個數(shù)據(jù)庫:脫褲
          • 獲取服務(wù)器權(quán)限
          • 植入Webshell,獲取服務(wù)器后門
          • 讀取服務(wù)器敏感文件

          3.如何防御

          • 嚴(yán)格限制Web應(yīng)用的數(shù)據(jù)庫的操作權(quán)限,給此用戶提供僅僅能夠滿足其工作的最低權(quán)限,從而最大限度的減少注入攻擊對數(shù)據(jù)庫的危害
          • 后端代碼檢查輸入的數(shù)據(jù)是否符合預(yù)期,嚴(yán)格限制變量的類型,例如使用正則表達(dá)式進(jìn)行一些匹配處理。
          • 對進(jìn)入數(shù)據(jù)庫的特殊字符(',",\,<,>,&,*,; 等)進(jìn)行轉(zhuǎn)義處理,或編碼轉(zhuǎn)換。基本上所有的后端語言都有對字符串進(jìn)行轉(zhuǎn)義處理的方法,比如 lodash 的 lodash._escapehtmlchar 庫。
          • 所有的查詢語句建議使用數(shù)據(jù)庫提供的參數(shù)化查詢接口,參數(shù)化的語句使用參數(shù)而不是將用戶輸入變量嵌入到 SQL 語句中,即不要直接拼接 SQL 語句。例如 Node.js 中的 mysqljs 庫的 query 方法中的 ? 占位參數(shù)。


          OS命令注入攻擊


          OS命令注入和SQL注入差不多,只不過SQL注入是針對數(shù)據(jù)庫的,而OS命令注入是針對操作系統(tǒng)的。OS命令注入攻擊指通過Web應(yīng)用,執(zhí)行非法的操作系統(tǒng)命令達(dá)到攻擊的目的。只要在能調(diào)用Shell函數(shù)的地方就有存在被攻擊的風(fēng)險。倘若調(diào)用Shell時存在疏漏,就可以執(zhí)行插入的非法命令。

          命令注入攻擊可以向Shell發(fā)送命令,讓W(xué)indows或Linux操作系統(tǒng)的命令行啟動程序。也就是說,通過命令注入攻擊可執(zhí)行操作系統(tǒng)上安裝著的各種程序。

          1.原理

          黑客構(gòu)造命令提交給web應(yīng)用程序,web應(yīng)用程序提取黑客構(gòu)造的命令,拼接到被執(zhí)行的命令中,因黑客注入的命令打破了原有命令結(jié)構(gòu),導(dǎo)致web應(yīng)用執(zhí)行了額外的命令,最后web應(yīng)用程序?qū)?zhí)行的結(jié)果輸出到響應(yīng)頁面中。

          我們通過一個例子來說明其原理,假如需要實現(xiàn)一個需求:用戶提交一些內(nèi)容到服務(wù)器,然后在服務(wù)器執(zhí)行一些系統(tǒng)命令去返回一個結(jié)果給用戶

          1// 以 Node.js 為例,假如在接口中需要從 github 下載用戶指定的 repo
          2const exec=require('mz/child_process').exec;
          3let params={/* 用戶輸入的參數(shù) */};
          4exec(`git clone ${params.repo} /some/path`);
          params.repo傳入的是 https://github.com/admin/admin.github.io.git 確實能從指定的 git repo 上下載到想要的代碼。
          

          但是如果 params.repo 傳入的是 https://github.com/xx/xx.git && rm -rf /* && 恰好你的服務(wù)是用 root 權(quán)限起的就糟糕了。

          2.如何防御

          • 后端對前端提交內(nèi)容進(jìn)行規(guī)則限制(比如正則表達(dá)式)。
          • 在調(diào)用系統(tǒng)命令前對所有傳入?yún)?shù)進(jìn)行命令行參數(shù)轉(zhuǎn)義過濾。
          • 不要直接拼接命令語句,借助一些工具做拼接、轉(zhuǎn)義預(yù)處理,例如 Node.js 的 shell-escape npm包

          參考資料

          • 常見Web 安全攻防總結(jié)
          • 前端面試之道
          • 圖解Http
          • Web安全知多少
          • web安全之點擊劫持(clickjacking)
          • URL重定向/跳轉(zhuǎn)漏洞
          • 網(wǎng)易web白帽子

          編者按】本文來自A List Apart,重點講述了開發(fā)者如何應(yīng)對琳瑯滿目的新技術(shù)。作者建議,開發(fā)者在接受新概念的同時,更要重視對原始瀏覽器的支持,并增強(qiáng)用戶體驗的開發(fā)。

          將Web視為應(yīng)用平臺的概念,正前所未有的流行著。但用來創(chuàng)建這些所謂“Web應(yīng)用”的工具仍存在許多經(jīng)常被我們忽視或誤解的陷阱。單頁面Web應(yīng)用框架已得到極大關(guān)注,我們可以借助這些框架創(chuàng)建一些復(fù)雜的高性能應(yīng)用,與傳統(tǒng)網(wǎng)站相比,這些應(yīng)用更可靠且交互更加豐富。但所有的這些益處,以及隨之而來的思維模式和開發(fā)方式的轉(zhuǎn)變,是以犧牲瀏覽器的基本功能為代價的,Web開發(fā)者們有時卻將其視為理所當(dāng)然。

          JavaScript可能非常脆弱

          隨著各家廠商不斷地炒作這股熱浪,我們可能誤以為當(dāng)用戶的瀏覽器不能執(zhí)行JavaScript時,并不需要為他們提供回退方案。用戶的瀏覽器不能執(zhí)行JavaScript一定事出有因,他們手動選擇禁用JavaScript只是眾多原因之一。維護(hù)英國政府網(wǎng)站的團(tuán)隊——政府?dāng)?shù)字服務(wù)(GDS)發(fā)現(xiàn):每500位訪問GOV.UK的用戶中,有5人沒有請求JavaScript,其中只有1人主動禁用了JavaScript,其他4人沒有請求可能因為以下幾個原因:企業(yè)代理服務(wù)器限制過高;高延遲導(dǎo)致JavaScript請求超時;甚或是一個沒有被注意到的語法錯誤。

          此外,CSS和HTML都可以優(yōu)雅降級,而JavaScript卻做不到。這意味著,如果開發(fā)者使用一個單一的ES6語法特性,甚或是調(diào)用一個沒有經(jīng)過驗證的標(biāo)準(zhǔn)庫函數(shù),他們的JavaScript就很有可能在執(zhí)行過程中終斷或者根本就不執(zhí)行。如果你使用JavaScript來增強(qiáng)網(wǎng)站,上面提到的這些問題尚且可以忍受,畢竟訪問者仍然可以訪問鏈接,可以提交表單,可以使用Web能提供的最原始功能;但如果JavaScript是網(wǎng)站必不可少的一部分時,無論是誰使用稍微過時的瀏覽器都可能獲得一個空白頁面,自然也沒有人來解釋頁面為什么會變成空白。

          語義結(jié)構(gòu)仍然非常重要

          自1993年Tim Berners-Lee設(shè)計HTML以來,HTML為相互關(guān)聯(lián)的文檔網(wǎng)定義了一個通用結(jié)構(gòu),也就是我們熟知的Web。滲透在這個通用結(jié)構(gòu)中的語義含義為Web頁面中包含的信息提供了計算機(jī)可以處理的上下文。從實際的意義來說,這些額外的信息增強(qiáng)了用戶使用Web瀏覽器時的體驗。舉個例子,Web瀏覽器可以實現(xiàn)一個向用戶的日歷中添加使用time元素定義的事件的方法;屏幕閱讀器可以用不同的方式通讀一個列表或一段文字,對于人類來說,文檔中的列表與段落看起來明顯不一樣,HTML提供的通用框架讓計算機(jī)也能夠清晰分辨列表與段落。

          HTML暗含的語義含義使Web與諸如Cocoa、WPF以及Qt這樣的原生應(yīng)用環(huán)境有著不同的發(fā)展方向。結(jié)構(gòu)化的信息對Web來說非常重要,因為我們需要通過多種方式訪問Web信息。而當(dāng)我創(chuàng)建一個iPhone應(yīng)用時,我可以穩(wěn)妥地假設(shè)每一個人都會用相同的方式去使用它。我的App總會以相同的方式呈現(xiàn)信息,并且我能夠完全掌控信息在應(yīng)用里的最終呈現(xiàn)。即使有些人通過VoiceOver(Apple為視障人群提供的輔助技術(shù))與我的App進(jìn)行交互,他們?nèi)匀豢梢耘c視力正常的用戶一樣:通過點擊屏幕進(jìn)行操作。唯一的不同是他們需要聽文字而不是去閱讀。

          而這種方法在Web上卻行不通。人們除了通過Web瀏覽器訪問網(wǎng)站,還會通過類似Pocket、Instapaper這樣的應(yīng)用來消費網(wǎng)站內(nèi)容,這些應(yīng)用嘗試使用Web頁面的結(jié)構(gòu)化信息來提取網(wǎng)站的相關(guān)內(nèi)容。智能手表上的瀏覽器可能直接忽略你的布局,然后通過更適合一英寸屏幕的方式展現(xiàn)你的信息。未來的設(shè)備也許能夠直接將網(wǎng)站提供的信息轉(zhuǎn)化為人類大腦中的思維,這誰又會知道呢?回過頭看,VoiceOver的工作原理是按順序朗讀用戶指尖下排列的文字,然而Web屏幕閱讀器則通讀全部文檔,忽略布局,并且通過HTML標(biāo)簽的標(biāo)準(zhǔn)化語義來推斷文檔含義。舉個例子,最近推出的main元素(譯者注:參考https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/main)用來定義文檔的主體部分,Web屏幕閱讀器可以讀取并識別這樣的標(biāo)簽。對于一個視覺正常的用戶來說,通過Google Chrome訪問你的網(wǎng)站時,無論你使用<main>或者是<div id=”main”>基本沒有區(qū)別。但對于使用其它Web客戶端的人來說,例如使用屏幕閱讀器或Instapaper,main元素隱含的含義可以讓軟件更好地幫助他們?yōu)g覽文檔。

          所以,開發(fā)一款Web應(yīng)用不像為原生平臺開發(fā)那么簡單。在五個主流瀏覽器中確保應(yīng)用能按照我們的需求正常工作并及時發(fā)布,對于Web平臺來說還遠(yuǎn)遠(yuǎn)不夠,我們需要在屏幕閱讀器中測試我們的工作成果,需要重審我們的標(biāo)記來確保應(yīng)用能提供盡可能多的語義元數(shù)據(jù)——不僅需要協(xié)調(diào)已有的Web客戶端,也要為將來可能出現(xiàn)的一切設(shè)備做準(zhǔn)備。

          單頁面Web應(yīng)用框架

          當(dāng)使用類似Angular和Ember這樣的“單頁面Web應(yīng)用”框架時,流行的做法是把網(wǎng)站當(dāng)成原生應(yīng)用一樣對待,如此一來,開發(fā)者們就很少會考慮到Web平臺與眾不同的一面。他們?yōu)橛脩糇鞒龅募僭O(shè)很容易徹底毀掉不滿足假設(shè)的用戶的真實體驗。這種思維模式會導(dǎo)致什么后果?我們來看一個示例,并認(rèn)真思考我最近在Patreon網(wǎng)站上發(fā)現(xiàn)的一個登錄按鈕(后來有改動):

          <span class="patreon-button sub-section navigation-active" data-ng-click="triggerChangeWindow(navigation.login_url)">Log In</span>

          Patreon那個相當(dāng)標(biāo)準(zhǔn)的登錄按鈕表現(xiàn)得像一個鏈接,這里不需要特殊的JavaScript。

          這個鏈接在我的Safari中可以正常運行,但是在除主流瀏覽器外的其它環(huán)境中,這個按鈕完全不能使用。假設(shè)我們有一個稱為WatchBrowse的智能手表瀏覽器,很可能它需要為用戶顯示一系列的列表鏈接來實現(xiàn)站內(nèi)導(dǎo)航,因為這個特殊的智能手表沒有光標(biāo)用來與頁面進(jìn)行交互。HTML定義了一個在Web頁面上創(chuàng)建鏈接的標(biāo)準(zhǔn)方式(a元素),WatchBrowse理論上可以在頁面上列出每一個a標(biāo)簽和它的href屬性以及內(nèi)容,除非出現(xiàn)一個類似Patreon的網(wǎng)站,并且該網(wǎng)站決定回避Web標(biāo)準(zhǔn)并且重新實現(xiàn)瀏覽器的基本功能。

          如果Patreon使用一個a標(biāo)簽而不是span標(biāo)簽,WatchBrowse大概可以找到鏈接并將它顯示在列表中,你可以為鏈接模擬一個點擊事件,當(dāng)用戶選中鏈接時進(jìn)行跳轉(zhuǎn)。但是如果讓瀏覽器提前知曉鏈接將導(dǎo)向何處是否會更好?一個瀏覽器擴(kuò)展可能通過頁面上標(biāo)簽的href屬性來查找鏈接,如果你想快速找到某人Twitter賬戶的鏈接,那么提供一個可以溯源的href屬性就很實用。當(dāng)鏈接的href屬性不再是靜態(tài)值,而是取決于任意的JavaScript點擊句柄,這些有用的功能就無法實現(xiàn)了。

          Patreon的網(wǎng)站是基于Angular建立的,Angular本身沒有錯,將HTML當(dāng)做視圖層并用這些框架去實現(xiàn)大概是導(dǎo)致Patreon糟糕決定的主要原因。

          如果我們按照框架開發(fā)者在他們文檔中推薦的方法創(chuàng)建相同的鏈接會怎樣?一個更標(biāo)準(zhǔn)創(chuàng)建鏈接的方式看起來可能是這樣的:

          <a ng-href="/login">Log In</a>

          當(dāng)通過客戶端JavaScript渲染到DOM中時,上面的代碼被轉(zhuǎn)換成這樣:

          <a ng-href="/login" class="ng-binding" href="/login">Log In</a>

          Ember以相同的方式處理這個問題。一個鏈接在Ember模板中被這樣定義:

          {{#link-to sessions.new}}Log In{{/link-to}}

          當(dāng)它被渲染到DOM中時,它變成這樣:

          <a id="ember-563" class="ember-view" href="/sessions/new">Log In</a>

          Ember和Angular之后會攔截鏈接的點擊事件,這樣就可以不通過重載頁面來渲染新的內(nèi)容。至關(guān)重要的是,如果點擊事件永遠(yuǎn)不被觸發(fā)并且瀏覽器已經(jīng)加載了href的值,那么對于用戶來說點擊鏈接只會帶來一次額外的頁面重載,看起來并不會有什么不同,因為Ember和Angular默認(rèn)情況下不會嘗試依照URL定義他們自己的路由來重新制造輪子。

          然而,在當(dāng)前的形式下,Ember和Angular仍然需要加載JavaScript來渲染他們的模板并且在第一時間創(chuàng)建那些連接。每500個訪問使用Angular或Ember構(gòu)建的網(wǎng)站中4人將會遭遇一次徹底白屏。

          是否有一個解決方案?

          如果在服務(wù)端渲染動態(tài)Web頁面的內(nèi)容,那么渲染功能的代碼只需支持在服務(wù)器端運行。但Web頁面放在客戶端進(jìn)行渲染時,相關(guān)代碼需要支持每一臺可能訪問網(wǎng)站的客戶端。開發(fā)者現(xiàn)在正逐步拋棄服務(wù)端渲染的做法,因為他們不能提供客戶端渲染所帶來的富應(yīng)用體驗。但是我認(rèn)為在客戶端應(yīng)用的新世界中,服務(wù)端渲染尚有一席之地。

          目前,開發(fā)者使用單頁面Web應(yīng)用框架需要針對加載JavaScript作出一個權(quán)衡。但在我看來,這些正是框架應(yīng)該去解決的問題。作為Web開發(fā)者,我們有幸使用有史以來最通用的編程語言之一為Web編寫應(yīng)用代碼。如果框架開發(fā)者能夠夜以繼日(不可否認(rèn)任務(wù)非常艱辛)地使應(yīng)用像在瀏覽器中一樣地運行在Node中,服務(wù)器就可以完成初始頁面渲染的任務(wù),隨后所有的任務(wù)由瀏覽器負(fù)責(zé)處理。當(dāng)然,如果服務(wù)器可以將鏈接渲染成a標(biāo)簽的形式,就像Ember目前在客戶端上實現(xiàn)的那樣,那么就可以允許沒有收到JavaScript的用戶(無論出于什么樣的原因)正常瀏覽網(wǎng)站。同樣也可以通過在服務(wù)器(而不是在客戶端)上運行所有的驗證和子任務(wù)邏輯,使表單正常工作。如果框架維護(hù)者一開始就朝著這個方向努力,那么每一個使用該框架的開發(fā)者都可以立即將一個只能工作在最新Web瀏覽器中的應(yīng)用轉(zhuǎn)換為一種漸進(jìn)增強(qiáng)的體驗,這樣做幾乎可以兼容任何Web客戶端——過去的、現(xiàn)在的、以及未來的。

          漸進(jìn)增強(qiáng)對于Web開發(fā)者來說早已是重要的一環(huán),它使我們意識到對于Web體驗來說內(nèi)容是至關(guān)重要的一部分,任何針對用戶體驗的額外改進(jìn)不應(yīng)當(dāng)破壞任何一個客戶端訪問Web頁面所包含的內(nèi)容。目前創(chuàng)建單頁面應(yīng)用的方法傾向于放棄這條準(zhǔn)則,然而漸進(jìn)增強(qiáng)和單頁面應(yīng)用從本質(zhì)上來講其實可以相互兼容。

          事實上,這個領(lǐng)域已經(jīng)有了不小的進(jìn)步,例如,一個Ember內(nèi)部的團(tuán)隊正在通過實現(xiàn)服務(wù)端渲染來改進(jìn)Ember與搜索引擎的兼容性。但是由單頁面Web應(yīng)用引發(fā)的問題的解決方案并不能只依賴純技術(shù)角度:人們看待Web的方式已成為一個日益嚴(yán)重的問題。將Web視為另一個應(yīng)用平臺的做法已司空見慣,但是Web所能做的比這多得多。無論訪問者通過2000美元的iMac還是50美元的安卓平板,甚至在我們無法想象的未來,花費5美元就可以購買的Web客戶端來訪問,Web始終是一個通用信息平臺。事實上,不犧牲小部分用戶的體驗對我們來說非常重要,如此一來我們可以在這個過程中稍微改進(jìn)一下其余正在破壞Web普適性的體驗。

          作者:Ross Penman是一位來自蘇格蘭的web開發(fā)者和狂熱的技術(shù)專家。2014年度新型人才網(wǎng)絡(luò)獎決賽入圍選手。Ross經(jīng)常慶祝他的工作來促進(jìn)科技領(lǐng)域的年輕人。他的Twitter內(nèi)容與web開發(fā)和口袋怪獸訓(xùn)練有關(guān)。(譯者:劉振濤,審校:陳秋歌)


          主站蜘蛛池模板: 亚洲a∨无码一区二区| 国精产品一区一区三区有限公司| 国产免费一区二区视频| 国产日韩AV免费无码一区二区| 91一区二区视频| 国产一区二区三区影院| 国产精品视频免费一区二区三区| 亚洲国产精品第一区二区| 亚洲熟女综合色一区二区三区 | 人妻无码第一区二区三区| 日韩精品无码久久一区二区三| 色一情一乱一伦一区二区三区日本 | 国产丝袜无码一区二区三区视频| 国产成人一区二区三中文| 在线日产精品一区| 韩国一区二区视频| 亚洲乱码日产一区三区| 亚洲国产精品一区| 国产一区三区三区| 少妇人妻精品一区二区| 亚洲一区爱区精品无码| 精品视频午夜一区二区| 亚洲一区二区三区国产精华液| 久久精品国产一区二区三区日韩| 无码人妻精品一区二| 波多野结衣一区二区三区高清av | 伊人色综合一区二区三区影院视频 | 精品一区二区三区无码免费直播| 无码精品一区二区三区在线| 任你躁国产自任一区二区三区| 久久一区二区三区99| 国产精品伦子一区二区三区| 成人区人妻精品一区二区不卡视频| 波多野结衣精品一区二区三区| 福利一区二区三区视频午夜观看| 国产激情一区二区三区在线观看| 精品国产一区二区二三区在线观看| 日本国产一区二区三区在线观看 | 在线精品国产一区二区三区| 国产精品久久无码一区二区三区网 | 久久久久人妻精品一区|