Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
JavaScript已經成為現代Web瀏覽器開發中最普遍的技術之一。之前在《PTES-信息收集》中講到源代碼審計也可能獲取到一些敏感信息,但有的測試人員只審計html源代碼,而忽略審計js文件里的源代碼,今天我們就來講一講審計js文件都能獲取到哪些信息。
通過審計js文件源代碼能獲取到的信息,我個人將其分為以下四類:敏感信息、業務邏輯、加密算法、Ajax請求。
敏感信息
審計js文件最直觀的就是很有可能獲取到賬號密碼、配置等敏感信息。
HTML定義頁面結構,CSS定義裝修樣式,而JavaScript定義前端工作內容,主要是監聽事件執行動作,比如邏輯判斷,亦或是向服務器發送請求等等。而要正確執行這些動作,通常都會進行一些簡單的配置。
最常見的配置就是設置網站根路徑,不過也經常遇到直接在js文件里配置賬號密碼的情況;更有甚者,有的開發人員直接在js文件里定義SQL語句,然后由前端發送到服務器執行。這不僅泄露了數據庫信息,也提高了SQL注入漏洞攻擊的風險。
以上是獲取敏感信息的一種情況,還有一種情況就是注釋。
為了更好的維護代碼、調試代碼,我們經常在源碼中見到各種注釋。比如為了方便調試,直接把賬號密碼寫在Javascript代碼中,調試完后,只是把這條語句注釋掉而非刪掉;有時候系統更迭,推出一些新的接口,開發人員把老接口注釋掉使用新的接口,但服務器端并沒有把老接口關掉等等。
以上情況不僅讓我們搜集到了更多目標信息,也增加了系統攻擊面,只能說:這些開發人員真他娘的是個人才。
業務邏輯
除了能獲取到敏感信息,審計js文件還可以獲取到Web系統的一些業務邏輯。
說到業務邏輯,就要牽扯到前端校驗。有些系統只做了前端校驗,只要響應包滿足條件,就會執行下一步操作,服務器端不會再進一步檢驗接下來的請求是否有問題,我們只要修改響應包就可以繞過檢測。
比如輸入錯誤的賬號密碼,響應false,要求重新輸入賬號密碼;我們把響應包攔截,把false改成true,前端檢測到true,認為賬號密碼正確,發送跳轉到系統內部的請求,而服務器沒有再校驗請求是否有問題,將系統內部頁面響應給前端。
要繞過前端校驗,像0/1、true/false這種很容易就能猜到該怎么修改,但有些系統可能有十多個響應碼,或者響應碼有多位,如果我們耐著性子一個一個去試,時間成本會很大。
比如0是用戶名錯誤,1是密碼錯誤,2是驗證碼錯誤,9999是登陸成功,如果我們從0開始,一個一個去試,說真的還不一定能試出來。除非先輸入正確的賬號密碼得到正確的響應碼,然后輸入錯誤的賬號密碼,再用之前得到的正確響應碼替換錯誤的響應碼,嘗試看是否存在前端校驗的問題。
問題是:如果是安全服務,客戶還有可能提供賬號密碼,但攻防演練、挖洞一般都是靠自己白手起家,哪里有什么賬號密碼給你。而前端業務邏輯通常都由js實現,基本都可以通過代碼審計來確定如何構造響應包來嘗試繞過前端校驗。我只想說:信息收集真的很重要。
加密算法
審計代碼能獲取到的第三類信息就是加密算法。在當今的大環境下,企業越來越重視安全,運用了各種防護手段來提高系統的安全系數,提高攻擊者的攻擊成本,其中就有加密機制。
可能很多測試人員在測試的時候,抓包發現參數值都是加密的,就這么放過了。但這種前端加密都是可以在js中找到加密算法的,要么在html文件的js中,要么包含在js文件中。
當然我們也可以不需要知道加密算法到底是怎么樣的,直接輸入測試的明文Payload,系統自然會利用加密算法輸出對應的加密數據。這個Payload不行,我們再輸入下一個明文Payload去測試。
以上的方式時間成本會增加很多,而且有時候系統會先檢測輸入的數據是否含有非法字符,沒有非法字符才會加密發送到服務器端。而只要我們找到了對應的加密算法,就可以手工構造或者編寫腳本批量生成我們想要的加密數據,進而去測試系統是否存在漏洞。
據目前工作經歷來看,涉及到加密的參數,存在漏洞的幾率要高很多。因為前端加密后,后端必須解密才能使用。但很多時候,系統的安全檢測只在請求傳過來的時候,加密時沒有檢測到非法字符就繞過了檢測,后端解密之后就可以肆意橫行。
Ajax請求
審計js文件能獲取到的信息還有Ajax請求,也是漏洞重災區。而Ajax請求的調用通常很隱蔽,且Ajax請求的觸發條件無規律,很容易被遺漏或忽略。
Ajax請求通常是被各個事件觸發調用,而這些事件的觸發往往需要滿足一定條件。但很多時候,即便事件觸發條件未滿足,我們去構造Ajax請求的數據包發送給服務器端,依然可以得到服務器的響應。
服務器訪問控制不當,并沒有去檢測用戶是否是通過正常業務邏輯發送Ajax請求,也沒有去檢測用戶是否有操作權限。服務器認為客戶端發過來的請求都是正確的,這又要提一下安全的本質:一切輸入都是不安全的。而且每一個Ajax請求都對應一個接口,這又增加了攻擊面,每個請求都可能形成獨立的攻擊過程。
舉個真實案例:修改密碼,先要通過短信驗證碼校驗才能修改新密碼。只有管理員才能修改密碼,修改密碼的Ajax請求由修改密碼功能調用,普通用戶沒有這個功能。(某些原因,沒有截圖,意淫一下吧)
開發人員認為所有的用戶都會按照系統業務邏輯一步一步觸發請求,先點擊發送驗證碼,然后填寫驗證碼進行校驗,通過校驗后跳轉到修改密碼的頁面,輸入新密碼,最后修改成功。而且只有管理員有這個功能頁面。
但通過代碼審計,直接在js文件中找到了修改密碼的Ajax請求,請求參數只有新密碼。現在我們已經找到了修改密碼的請求,那么我們可以跳過前面一系列的校驗和請求,只需要構造出修改密碼請求,就可以修改密碼。
而且這個Ajax請求是寫在js文件里的,系統并不會因為用戶權限的不同而調用不同的js文件,所以普通用戶也能夠查到到對應的js代碼,不存在管理員一說。
本文簡單講述了審計js文件源代碼能獲取到的四類信息:敏感信息、業務邏輯、加密算法、Ajax請求。
當然,這也僅僅是我個人的歸類,審計代碼能獲取到的信息遠不止這些,需要大家去深入挖掘,我純碎起一個拋磚引玉的作用。
忙里偷閑,差不多半年才寫了一篇文章。這波行動差不多要結束了,接下來就是國慶重保。國慶重保后不出意外的話應該,可能,也許會稍微輕松一點,爭取一個月能寫篇文章吧。感謝大家的關注!
在之前的一篇文章《前端開發過程中的HTML規范,來學習一下吧》中,我們有講過前端開發過程中需要注意到的HTML規范問題,今天這篇文章我們繼續來看下關于Javascript的規范問題。
Javascript
我們總是會在Javascript文件中定義變量,但是一不留神就會將其定義成全局變量,如果引用的外部JS文件較多,很容易出現全局變量污染的情況。
我們不推薦總是在全局空間定義變量的行為,因為所有在全局空間定義的變量都是掛在window對象上,很容易出現變量污染,如下所示。
不推薦-全局變量
IIFE就可以防止出現全局變量污染的情況,IIFE是立即執行的函數表達式,在IIFE內部會創建一個封閉的作用域,內部定義的變量不會影響外部的執行環境,而且可以通過參數傳遞的形式引用外部變量,最重要的一點是在函數執行完后會立即釋放占用的內存。
我們推薦使用下面這種寫法。
推薦寫法-IIFE
為了避免全局變量的干擾,我們建議所有腳本文件都從IIFE開始。
我們都知道之所以叫立即執行的函數表達式,是因為在函數表達式后面會多一個執行的括號。這個執行的括號可以出現在兩個地方,不管是在內部還是外部,都是有效的。但是為了讓整個函數表達式看起來像一個整體,我們推薦將括號寫在里面。
因此我們不推薦以下寫法。
不推薦寫法
而推薦以下寫法。
推薦寫法
同樣,我們可以通過參數傳遞的形式引用外部變量。
引用外部變量
我們都知道在ES5中是沒有塊級作用域概念的,只有函數級作用域,而且由于變量提升的存在,在函數內部聲明的變量都會提升至函數頂部,這就會造成一些難以預料的問題。
首先我們來看看變量提升是什么樣的情況?看看下面一段代碼。
變量提升
上面這段代碼返回的結果是undefined,并不是'Hello Shenzhen',這是因為變量v會在函數內部被提升至函數頂部,實際執行的其實是下面這段代碼。
實際執行
為了降低變量提升所帶來的編碼風險,我們應該手動聲明定義的變量和方法,并把其放在函數頂部。
我們不推薦以下寫法。
不推薦寫法
我們推薦以下寫法。
推薦寫法
在編寫判斷相等類型的條件語句時,總是使用嚴格相等(===),這樣可以避免Javascript在執行類型轉換時帶來的問題。
我們看下面一個例子,定義一個函數,傳入一個數字,如果等于5,則將這個數加5返回。如果不使用嚴格等于,在傳入一個字符串'5'后,會返回'55'。
沒有使用嚴格相等
因此,我們推薦在使用相等判斷時都采用嚴格相等(===)。
強烈建議在所有結束語句后面加上分號,如果不加上分號會引起一些很難發現的問題。我們看看下面一段代碼。
代碼
在上面這段代碼執行后,我們發現即使resultOperation()函數返回-1,與-1相等,后面的method方法仍然被調用。
這是因為在上面定義的數組末尾沒有加上分號,這個數組會與下面一行的-1當做表達式執行,任何非空數組-1都會返回NaN,NaN與resultOperation的返回結果-1不相等,因此后面的method方法會被執行。
省略分號不寫,不只是會出現上述的問題,還有很多,這里不一一列舉。
因此,建議在每個結尾的語句后加上分號,養成一個好的習慣。
閉包作為前端面試題中必不可少的知識點是應該要掌握的,而且在前端開發中經常會涉及到,關于閉包的問題,在我寫的一篇文章《前端面試中不可逃避的閉包問題,你真的了解嗎?》中有詳細介紹,大家可以好好看下。
今天這篇文章詳細的介紹了在前端開發過程中涉及到的Javascript規范問題,可能還不夠全面,大家可以自行補充。
前端項目開發的時候,系統支持文件下載是前端開發中常用到的功能之一,當用戶訪問我們的網站時發現有自己需要的資源時可以將資源下載下來。文件下載主要有兩種形式,一種是通過文件地址下載,該文件可以存放在前端或者后端。另一種則是通過文件流下載,前端通過發送請求給后端并獲取后端文件流進行下載。
download屬性:是HTML5中的a標簽的新特性,用來規定被下載的超鏈接目標。在a標簽中如果沒有申明download屬性的時a標簽的默會鏈接跳轉進行預覽(如txt , jpg , pdf ),當前瀏覽器不支持預覽的文件時則出現下載。當申明了download屬性之后瀏覽器會對href屬性鏈接的文件進行下載。download屬性與不支持H5的低版本瀏覽器不兼容且僅限于同源文件,如果是非同源download屬性會失效。比如引用第三方的網站內容、引用前后端分離的服務器內容、甚至本地測試引用的本地文件,download都會不起作用。如果你想測試該功能可以在本地開一個服務,將文件放同一服務中測試就可以了。
直接使用a標簽時只要在a標簽中添加download屬性,如果是非a標簽的話可以在出發事件的時候通過JavaScript來創建一個隱藏a標簽下載,當我們點擊時觸發隱藏的a標簽下載事件。這里使用appendChild和removeChild的處理是為了兼容Firefox瀏覽器。
需要了解XMLHttpRequest可以參考文章:JavaScript實戰001:XMLHttpRequest使用入門,這里我利用XMLHttpRequest對象來發送請求,用blob類型來接受后臺發過來的二進制類型文件。然后模擬a標簽創建隱藏的下載鏈接,通過URL.createObjectURL()方法創建一個指向blob對象的URL地址。
iframe是HTML標簽元素,可以用來創建內聯框架。iframe提供了src屬性用來規定在 iframe 中顯示的文檔的 URL,我們可以直接將文件地址拋給iframe,也可以賦值文件流地址給iframe。功能實現跟a標簽有點相似,創建一個隱藏的iframe標簽來實現文件的下載功能。使用文件地址下載需要注意的是瀏覽器支持預覽的文件類型無法下載(比如圖片、PDF文檔、text文本等會直接打開文件預覽),文件流下載只需將請求接口賦給src屬性,iframe會自動去請求該文件實現下載。
window.open()方法用于打開一個新的瀏覽器窗口或查找一個已命名的窗口,也可以用它來實現文件下載功能。而且這個比iframe更簡單,直接將文件地址或者請求接口賦給window.open(url)方法即可實現文件下載功能。但是有個缺點就是每次下載都會打開一個新的窗口來實現下載(想不跳轉可以嘗試window.location.assign()方法,用于加載一個新的文檔),而且如果使用文件地址下載的是瀏覽器支持預覽的文件類型無法下載(比如圖片、PDF文檔、text文本等會直接打開文件預覽)。
form表單是個比較常用的html表簽,用戶提交用戶信息,比如常見的登錄、注冊界面大部分都是通過form表單進行數據提交的。form表單所有要提交的數據都必須放在form標簽中,method屬性定義提交的方法(有get和post兩種提交方法),action屬性定義請求的地址。form標簽中支持input、menus、textarea、fieldset、legend 和 label 等元素,通過submit向服務器提交數據。這里我創建了form表單和input框,input用于輸入請求的參數,form用于提交數據請求。
這里提供下Django的后臺文件請求接口,以上文件請求都是基于該接口實現的。接收請求方法為GET,請求參數為id(數據庫存儲的文件id),采用FileResponse方式返回的文件流信息(具體實現功能可以參考文章:Django實戰013:各種文件下載功能實現詳解)。
下載的方式方法有很多,以上只是JavaScript中常見的幾種下載方式。其實用ajax或者axios也可以實現下載,但是萬變不離其中,會JavaScript下載害怕不會別的么。以上下載方式個人覺得還是iframe比較簡單方便,請求最好還是通過文件流來實現,相對文件地址下載會更安全些。
更多前端技巧可以參考專欄:Vue實戰技巧
*請認真填寫需求信息,我們會在24小時內與您取得聯系。