◆敖 毅
(南京政治學院軍事信息管理系 上海 200433)
基于HTML5實現(xiàn)的微信公眾號支付漏洞分析與研究
◆敖 毅
(南京政治學院軍事信息管理系 上海 200433)
大量微信公眾號系統(tǒng)選用HTML5作為技術(shù)實現(xiàn)方案。基于HTML5的微信公眾號系統(tǒng)在實現(xiàn)微信支付功能時,如果支付流程設計或系統(tǒng)實現(xiàn)不合理,會造成篡改攻擊漏洞或短路攻擊漏洞,可以被惡意用戶用于發(fā)起中間人攻擊。本文模擬了利用兩種漏洞進行中間人攻擊的過程,分析了兩種漏洞的形成原理,并提出了防范漏洞的解決方案。
HTML5;微信支付;篡改攻擊漏洞;短路攻擊漏洞
騰訊公司的微信(WeChat)推出公眾號、服務號以及微信支付功能后,越來越多的商家通過推出微信公眾號,開辦微商城,提供微服務等形式依托微信開展商業(yè)活動。由于HTML5具有跨平臺、易實現(xiàn)、方便升級等優(yōu)勢,大量微信公眾號系統(tǒng)選用HTML5技術(shù)作為技術(shù)實現(xiàn)方案。但是,在基于HTML5的微信公眾號系統(tǒng)在實現(xiàn)微信支付功能時,如果流程設計或系統(tǒng)實現(xiàn)不合理,容易造成支付漏洞,引來惡意用戶攻擊。
日前,筆者就處理了一起針對微信公眾號支付漏洞的惡意用戶攻擊事件,經(jīng)估算,這次攻擊共造成了約15萬元人民幣的經(jīng)濟損失。值得指出的是,本文提到的支付漏洞目前在大量微信公眾號中仍然存在,需引起高度重視。
經(jīng)分析,這次攻擊是惡意用戶采用中間人攻擊的方法,通過網(wǎng)絡抓包的手段,利用某微信公眾號的微信支付流程中存在的篡改攻擊漏洞和短路攻擊漏洞,偽造網(wǎng)絡請求數(shù)據(jù),最終實現(xiàn)了惡意消費。
下面將對比該微信公眾號的正常支付流程,模擬惡意用戶利用漏洞發(fā)起中間人攻擊的過程。
1.1 微信公眾號正常支付流程

圖1 微信公眾號微信支付流程
該微信公眾號設計的正常支付流程共分七步,如圖1所示。第一步,通過微信客戶端關注微信公眾號;第二步,點擊微信公眾號底部菜單欄中的“購買會員”菜單項;第三步,跳轉(zhuǎn)到“永久VIP會員”購買頁面,輸入手機號;第四步,點擊【立即購買】按鈕后,跳轉(zhuǎn)到確認購買頁面;第五步,在確認購買頁面點擊【微信支付】按鈕,彈出微信支付對話框;第六步,在微信支付對話框中輸入支付密碼,進行支付操作;第七步,如果支付成功,會收到消息通知,告知用戶購買VIP會員已成功,可以開始使用VIP客戶的功能;如果支付失敗,將返回第二步。
1.2 惡意用戶進行中間人攻擊過程模擬
在上述微信公眾號的微信支付流程中,因為系統(tǒng)設計和實現(xiàn)不合理,留下了篡改攻擊漏洞和短路攻擊漏洞,可以被惡意用戶利用進行中間人攻擊。
(1)利用篡改攻擊漏洞實施中間人攻擊
篡改攻擊漏洞,是由于系統(tǒng)的接口設計或?qū)崿F(xiàn)存在缺陷造成的漏洞,導致惡意用戶可以通過篡改網(wǎng)絡交互數(shù)據(jù)等方法,達到攻擊系統(tǒng)的目的。上述微信公眾號支付流程的第四步的設計就存在篡改攻擊漏洞,可以被利用實施中間人攻擊。
當用戶點擊【立即購買】按鈕,跳轉(zhuǎn)到確認購買頁面時,如果使用網(wǎng)絡抓包工具Fiddle Web Debugger抓取此時微信公眾號提交到后端系統(tǒng)的URL請求(如圖 2所示),可以在抓取的URL請求中,發(fā)現(xiàn)有“totalprice”字段,該字段的值為“12”。從該字段的字面意思推測,其值可能是微信公眾號向后臺系統(tǒng)提交的訂單總價金額。經(jīng)比對,這個值確實與支付流程的第五步微信支付中顯示的價格一致。這意味著如果修改此字段的值,則微信支付系統(tǒng)生成的支付憑證中的金額值也會相應地修改。

圖2 篡改攻擊模漏洞示例
我們嘗試在Fiddle中將此值修改為0.01(也即1分錢),提交該微信公眾號后臺系統(tǒng)后,果然在隨后的第五步中,微信支付頁面顯示的值為0.01元。我們隨即通過微信支付了1分錢,該微信公眾號即反回支付成功消息,并取得了VIP用戶的所有特權(quán)。這意味著惡意用戶只需支付1分錢,即可享受本來需要12元錢的服務了。
經(jīng)驗證,篡改攻擊漏洞也存在于某些電商平臺和團購網(wǎng)站的微信公眾號中。
(2)利用短路攻擊漏洞實施中間人攻擊
短路攻擊漏洞,是由于系統(tǒng)的流程設計或?qū)崿F(xiàn)存在缺陷造成的漏洞,利用該漏洞,惡意用戶可以更改腳本代碼,造成代碼中的條件判斷語句“短路”,只執(zhí)行條件分支中的某部分語句,達到攻擊系統(tǒng)的目的。上述微信公眾號支付流程的第五步的設計存在短路攻擊漏洞,可以被利用實施中間人攻擊。
當用戶點擊【微信支付】按鈕,發(fā)起微信支付請求時,我們可以使用Fiddle截獲后臺服務器返回的頁面代碼,如代碼 1所示。分析此段代碼發(fā)現(xiàn),該微信公眾號是通過判斷微信支付接口返回的res對象的err_msg屬性值來判斷用戶是否支付成功。如果支付成功,將調(diào)用后臺Web API(payover),提交用戶支付成功的信息,并修改用戶狀態(tài)。
代碼1 存在短路攻擊漏洞的JavaScript源代碼

因此,如果能夠在這里讓程序始終執(zhí)行支付成功的邏輯,就能達到修改用戶狀態(tài)的目的。至少有三種方法可以實現(xiàn)這一目的。
第一種方法是將if表達式中的邏輯判斷符號“==”修改為賦值符號“=”,達到使if判斷語句“短路”的目的。如下面代碼所示。

根據(jù)Javascript語言規(guī)范,賦值語句返回的是所賦的值(這里即是“get_brand_wcpay_request:ok”);而if語句只有當被判斷的值為false、0、“”、undefined、null、NaN時才為假值,其余條件皆為真值。因此這樣修改后,這個判斷語句就變?yōu)榱艘粋€恒真式。也意味著,不論用戶是否實際支付成功,都將執(zhí)行if語句中真值分支的代碼。
第二種方法是直接刪除if語句和后面的else語句塊,使得無論用戶微信支付是否成功,或者是否實際支付,都會調(diào)用后臺Web API,提交用戶支付成功的信息,并修改用戶狀態(tài)。
第三種方法是在if判斷語句前增加一行代碼(如代碼 2中紅框所示),通過修改res的err_msg屬性值,達到使if判斷語句“短路”的目的。這是因為,Javascript對象的屬性值可以在任意時刻修改,甚至當對象不存在某個屬性時,也可以通過賦值的方式,動態(tài)地為其增加屬性。
代碼2 通過修改javas對象屬性實施短路攻擊

經(jīng)驗證,上面三種方法都可以對該微信公眾號實施短路漏洞攻擊。值得注意的是,有的微信公眾號系統(tǒng)考慮到了第一、二種攻擊方法,因此采取將微信支付接口返回的res對象直接提交到后臺系統(tǒng),在后臺系統(tǒng)中再根據(jù)res.err_msg的值來判斷用戶是否支付成功。但是由于存在第三種攻擊方法,仍然可能造成短路攻擊漏洞。
安全性作為微信支付的首要非功能特性,極大地影響著用戶的使用意愿和使用體驗,因此在設計和實現(xiàn)微信支付業(yè)務功能時,應該將安全性作為首要考慮的設計要點。騰訊公司在設計微信公眾號支付功能時,已經(jīng)考慮到了安全的問題,并給出了參考的業(yè)務流程,如圖3所示。

圖3 微信公眾號微信支付流程圖②
對照微信公眾號微信支付流程來分析篡改攻擊漏洞和短路攻擊漏洞,可以看出,造成這兩個漏洞的最主要原因是在實現(xiàn)微信支付功能時,沒有按照正確的流程進行設計和實現(xiàn)。
2.1 篡改攻擊漏洞分析
按照微信支付流程,當微信支付用戶通過點擊微信支付消息或掃描二維碼,準備在微信客戶端瀏覽器中打開用于支付的HTML5頁面時(圖 3第2步),將向微信公眾號后臺系統(tǒng)提交生成支付訂單的請求;微信公眾號后臺系統(tǒng)收到請求后,生成客戶訂單(圖 3第4步);再調(diào)用微信支付統(tǒng)一下單API,向微信支付系統(tǒng)提交生成預付單請求,微信支付系統(tǒng)在生成預付單后,返回預付單信息(prepay_id)給微信公眾號后臺系統(tǒng)(圖 3第5步);微信公眾號后臺系統(tǒng)根據(jù)返回的預付單信息(prepay_id)生成JSAPI頁面調(diào)用的參數(shù)并簽名(paySign)(圖 3第6步)后生成HTML5頁面返回用戶,等待用戶點擊進行支付。
導致產(chǎn)生篡改攻擊漏洞的主要原因是在上述流程中,“請求生成支付賬單”和“生成用戶訂單”兩步間的信息交互設計存在問題。
微信公眾號后臺系統(tǒng)在生成用于支付的消息或二維碼時,通常會使用一個標識號作為前后端交互的依據(jù),這個標識號可以是用戶的訂單號或產(chǎn)品的產(chǎn)品號。當用戶點擊消息或掃描二維碼請求生成支付訂單時,后臺系統(tǒng)應根據(jù)這個標識號生成對應的訂單,包括計算訂單的應付金額。
但是部分以提供會員、充值、點卡、外賣等產(chǎn)品的微信公眾號系統(tǒng),由于產(chǎn)品形態(tài)單一,而且通常一個產(chǎn)品就是一個訂單,因此沒有設計獨立的標識號,而是將應付金額等敏感數(shù)據(jù)包含在了前后端交互的信息中;后臺系統(tǒng)在收到前端系統(tǒng)的支付請求后,也沒有進行必要的驗證,就直接將請求數(shù)據(jù)生成了預付單,這樣就會留下篡改攻擊漏洞。
2.2 短路攻擊漏洞分析
從微信支付流程看,從用戶確認支付(圖 3第9步)到微信客戶端展示支付結(jié)果(圖 3第15步),共有六個步驟。這其中包含了兩個并行任務,用于返回用戶支付結(jié)果:一是通過異步的方式通知微信公眾號后臺系統(tǒng)支付結(jié)果(圖 3第10步),微信公眾號后臺系統(tǒng)在處理完支付結(jié)果后再將處理結(jié)果通知微信支付服務(圖 3中第11步);二是通過JS API直接返回支付結(jié)果給微信客戶端(圖 3第12步)。在公眾號支付開發(fā)者文檔中明確說明,這兩個并行處理的任務并“不保證遵循嚴格的時序,JS API返回值作為觸發(fā)商戶網(wǎng)頁跳轉(zhuǎn)的標志,但商戶后臺應該只在收到微信后臺的支付成功回調(diào)通知后,才做真正的支付成功的處理”③。因此,當微信支付的JS API返回支付結(jié)果后,要驗證用戶是否實際支付成功,還應向微信公眾號的后臺系統(tǒng)提交查詢用戶實際支付結(jié)果的請求(圖 3第13步),微信公眾號的后臺系統(tǒng)通過調(diào)用微信支付查詢API,查詢實際支付結(jié)果(圖 3第14步),再根據(jù)查詢結(jié)果執(zhí)行支付后個性化頁面展示。
短路攻擊漏洞造成損失的直接原因是惡意用戶繞過用戶支付結(jié)果驗證流程,將用戶狀態(tài)修改為已正常支付的狀態(tài)。系統(tǒng)實現(xiàn)中的兩個錯誤共同導致了短路攻擊漏洞:一是錯誤地使用微信客戶端收到的JS API返回結(jié)果作為驗證用戶是否支付的依據(jù);二是在前端的Javascript中調(diào)用修改用戶支付狀態(tài)的代碼。
分析基于HTML5的微信公眾號的微信支付頁面代碼,發(fā)現(xiàn)在調(diào)用微信支付接口時,都參照了公眾號支付開發(fā)者文檔中提供的示例,如代碼3所示。
從代碼 3中可以看出,基于HTML5的微信公眾號實現(xiàn)微信支付,是通過使用微信內(nèi)置瀏覽器提供的內(nèi)置對象WeixinJSBridge調(diào)用getBrandWCPayRequest方法來調(diào)用微信支付接口。在該方法的回調(diào)函數(shù)中,可以根據(jù)微信支付接口返回的結(jié)果res.err_msg(可能的返回值如表 1所示)進行下一步處理。但是在公眾號支付開發(fā)者文檔中,明確說明:“res.err_msg將在用戶支付成功后返回ok,但并不保證它絕對可靠”④。不能保證其絕對可靠的原因如前文所述,就是因為Javascript的動態(tài)語言特性。
代碼3 JSAPI微信支付模板代碼



表1 微信公眾號支付接口返回值㈤
因此,導致短路攻擊漏洞的一個原因是直接將微信客戶端收到的JS API返回結(jié)果作為驗證用戶是否支付成功的依據(jù),沒有嚴格按照微信支付業(yè)務流程要求,在后臺進行支付結(jié)果驗證,致使驗證流程可能被繞過。
導致短路攻擊漏洞的另一個原因是將修改用戶支付狀態(tài)的代碼放在了前端Javascript代碼中(如前文代碼 1所示)。由于可以繞過支付結(jié)果驗證環(huán)節(jié),這就導致既不能保證業(yè)務流程的完整性,也不能保證用戶狀態(tài)修改合法。實際上,按照微信支付流程,應該是在微信公眾號的后臺系統(tǒng)收到微信支付系統(tǒng)的異步通知后才能修改用戶支付狀態(tài)。為了保證能夠?qū)⒅Ц督Y(jié)果成功通知到微信公眾號后臺系統(tǒng),微信支付系統(tǒng)還采取了以下四種措施:
(1)微信支付系統(tǒng)通過一定的策略⑥定期重新發(fā)起通知,盡可能提高通知的成功率,但需要注意的是,微信支付系統(tǒng)并不保證通知最終能成功。
(2)當微信公眾號后臺系統(tǒng)收到異步通知進行處理時,應檢查對應業(yè)務數(shù)據(jù)的狀態(tài),判斷該通知是否已經(jīng)處理過。
(3)由于異步通知回調(diào)地址不能進行簽名,微信公眾號后臺系統(tǒng)必須對支付結(jié)果通知的內(nèi)容要做簽名驗證,防止數(shù)據(jù)泄漏導致出現(xiàn)“假通知”,造成資金損失。
(4)微信支付系統(tǒng)提供了“下載對賬單”API⑦,供微信公眾號后臺系統(tǒng)定期下載對賬單,比對支付記錄,防止資金損失。
要避免在基于HTML5的微信公眾號的微信支付模塊中留下篡改攻擊漏洞或短路攻擊漏洞,需要從系統(tǒng)的設計、實現(xiàn)、運維等多個方面著手。
3.1 前后端模塊之間的交互應是系統(tǒng)設計時關注的重點
要保證微信支付的安全,系統(tǒng)設計是關鍵。在系統(tǒng)設計時,應嚴格按照公眾號支付開發(fā)者文檔中提供的業(yè)務流程,對前后端模塊的職責、交互接口、傳輸協(xié)議等進行正確設計。
(1)前后端模塊職責分明。前端模塊只負責頁面的展示和部分的輸入校驗功能,而訂單處理、預付單生成、支付結(jié)果處理、賬單狀態(tài)查詢等關鍵功能應放在后端模塊。
(2)交互接口最小化。在接口設計時,可遵循RESTful風格,按照HTTP協(xié)議規(guī)則設計API接口;在傳輸內(nèi)容上,只傳遞訂單號或產(chǎn)品號等必要信息,特別是在前端模塊向后端模塊發(fā)起PUT、POST請求時,應避免將價格、數(shù)量、總價等可能影響到支付結(jié)果的敏感信息包含在內(nèi)。
(3)選擇HTTPS協(xié)議作為傳輸協(xié)議。與HTTP協(xié)議相比,HTTPS協(xié)議具有更好的保密特性,可以防止在傳輸過程中被獲取或篡改信息。
3.2 在系統(tǒng)開發(fā)過程中應層層設防,避免留下漏洞
由于程序員個體經(jīng)驗的不足,或者是團隊沒有采用恰當?shù)能浖_發(fā)方法,在系統(tǒng)實現(xiàn)階段往往容易造成微信支付功能出現(xiàn)漏洞。通過層層設防的方式,有助于減少系統(tǒng)開發(fā)過程中造成的漏洞。
(1)對前端代碼進行必要的分離、混淆和壓縮。在實現(xiàn)前端模塊時,要充分掌握Javascript語言規(guī)范和正確的使用方式,避免因誤用留下漏洞;將HTML5代碼和Javascript代碼分離,有利于對Javascript代碼進行獨立的管理;借助諸如YUI Compressor、Closure Compiler、uglifyjs等工具軟件對Javascript腳本文件進行混淆和壓縮,可以增加惡意用戶逆向分析和篡改程序的難度。
(2)后端模塊必須對請求參數(shù)進行校驗。對于前端模塊傳遞來的任何請求,后端模塊都必須對請求所攜帶的參數(shù)進行校驗,包括有效性校驗、合規(guī)性校驗、業(yè)務規(guī)則校驗等,保證請求的合法性。校驗通過后才能進行后續(xù)處理,以杜絕惡意用戶在參數(shù)傳遞過程中實施篡改攻擊。
(3)采用驗收測試、代碼審查等軟件工程方法,減少人為因素造成漏洞。驗收測試可以模擬軟件系統(tǒng)在實際使用場景中的不同運行流程,驗證軟件的功能質(zhì)量特性;代碼審查通過團隊成員間交叉審查源代碼,達到彌補個體經(jīng)驗不足,減少系統(tǒng)漏洞,提高代碼質(zhì)量的目的。
3.3 在運維中應通過定期核查保障資金安全
除了在系統(tǒng)的設計和實現(xiàn)時需要考慮周全,小心謹慎外,在運維過程中加強定期核查也是保障資金安全的重要手段。定期核查可以通過對賬檢查和日志審計等方式進行。
(1)在系統(tǒng)中應提供“對賬檢查”功能,通過微信支付系統(tǒng)提供的“下載對賬單”接口,定期或手動下載對賬單。運維人員通過自動或人工比對提交到微信支付系統(tǒng)的訂單及金額與微信公眾號系統(tǒng)中記錄的訂單和金額,發(fā)現(xiàn)是否存在異常訂單支付記錄。
(2)系統(tǒng)應提供完備的運行日志,可以對支付過程中的運行情況進行跟蹤記錄。當發(fā)現(xiàn)遭受惡意用戶攻擊或者資金異常情況時,運維人員可以通過分析系統(tǒng)運行日志,查找問題出現(xiàn)的時間和位置,分析惡意用戶的攻擊方式,及時修補漏洞。
[1]【微信支付】公眾號支付開發(fā)者文檔[EB/OL].https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1#.2016.
[2]【微信支付】公眾號支付開發(fā)者文檔[EB/OL].https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4#.2016.
[3]【微信支付】公眾號支付開發(fā)者文檔[EB/OL].https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index =6.2016.
[4]【微信支付】公眾號支付開發(fā)者文檔[EB/OL].https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6.2016.
[5]【微信支付】公眾號支付開發(fā)者文檔[EB/OL].https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7.2016.
注釋:
①中間人攻擊(Man-in-the-middle attack,縮寫:MITM)是指攻擊者與通訊的兩端分別創(chuàng)建獨立的聯(lián)系,并交換其所收到的數(shù)據(jù),使通訊的兩端認為他們正在通過一個私密的連接與對方直接對話,但事實上整個會話都被攻擊者完全控制。在中間人攻擊中,攻擊者可以攔截通訊雙方的通話并插入新的內(nèi)容。來源:維基百科,https://zh.wikipedia.org/wiki/中間人攻擊,查詢于:2016.06.03
②【微信支付】公眾號支付開發(fā)者文檔,來源:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4#,查詢于:2016.05.18
③【微信支付】公眾號支付開發(fā)者文檔,來源:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1,查詢于:2016.05.18
④【微信支付】公眾號支付開發(fā)者文檔,來源:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index =6,查詢于:2016.05.20
⑤【微信支付】公眾號支付開發(fā)者文檔,來源:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index =6,查詢于:2016.05.18
⑥【微信支付】公眾號支付開發(fā)者文檔,來源:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7,查詢于:2016.05.20
⑦【微信支付】公眾號支付開發(fā)者文檔,來源:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6,查詢于:2016.05.20