在WebView中對第三方H5頁面的文本密碼框添加自定義隨機鍵盤

前言:

首先介紹一下這個需求的背景,由於公司是涉及到金融行業的需要與銀行對接資金存管。出於保密性這裏不直接列出公司名字和銀行名字。從2018年國家對金融行業大整改以來,爲了能夠順利通過備案,我們也跟着政府的腳步一步一步走向合規。

好了,大致就是因爲要通過備案,必須把這個需求實現,否則將不會通過。

需求內容就是,當客戶端有關資金交易的時候,會通過加密數據以及祕鑰的方式把第三方銀行的頁面(充值、提現、投資...)等通過解析前面的加密數據獲取到裏面的鏈接用WebView把第三方銀行的頁面加載出來,並且此時必須對第三方頁面的文本框密碼框做攔截監聽,而且要實現公司自己的隨機鍵盤,屏蔽系統鍵盤。爲什麼要屏蔽系統鍵盤?因爲怕手機被root,鍵盤被植入的木馬監聽!那爲啥自定義鍵盤不會被監聽,因爲自定義鍵盤屬於應用。要監聽你的應用那就要破解反編譯再簽名打包等,如果做到這一點了,那說明你的應用本身就不安全了,要不要自定義鍵盤也沒啥用。

起初,覺着挺簡單,畢竟以前做過自定義的鍵盤。然後就直接開擼。

等到隨機鍵盤做出來以後,我才發現,頁面並不是我們公司自己的,而是第三方的,如果需要第三方頁面調用我們的接口,雙方公司不是必須要協商好接口協議嗎,此時才能調用我們自定義的鍵盤。

關鍵的地方就是在於,銀行不可能因爲你一家的需求改自己的公共頁面。

分析完之後,我考慮到幾個問題:

1.首先我們要能夠獲取並且設置這個框的焦點事件。

2.我們的自定義鍵盤如何綁定到這個文本框,看過android源碼的都知道EditText是如何與系統輸入法綁定的。

這個兩個問題解決了,應該基本就可以實現了。再仔細分析一下,這兩個問題其實就是一個問題,那就是如何獲取到當先密碼框的Object,對這個Object設置監聽,設置值等一系列操作只要獲取的這個Object了,那就是幾行代碼就能解決的問題了。

思路:

獲取到網頁源碼分析密碼框的特性做出篩選(Input標籤type=password就是密碼框了)。

解析出來type=password的Input標籤通過遍歷的方式得到ID(input.getElementById(id)就可以得到這個密碼框的Object了)。

回到上面1中,設置這個框的焦點事件,我們能夠通過解析出這個Object了,那麼該怎麼把監聽注入到這個Object中?爲什麼說要注入進去,因爲頁面是別人的,你總不能在別人頁面中添加js代碼吧,只能是注入js代碼。

思路分析清楚了,那流程就好辦了。

解決方案:

1.遍歷網頁input標籤並且type=password的標籤並且添加onFocus事件

webView.loadUrl("javascript:(function(){" +
				"var objs = document.getElementsByTagName(\"input\");" +
				"for(var i=0;i<objs.length;i++)" +
				"{"
				+"var type = objs[i].getAttribute(\"type\");"
				+"if(type==\"password\"){"
				+"objs[i].οnfοcus=function()" +
				"{"
				+ "window.androidWebView.openSoftInput(this.id,this.type);" +
				"}" +
				"}" +
				"}" +
				"})()");

這段代碼邏輯應該都能看懂,就是WebView中加載js的方法loadUrl加載你自己寫的js事件,這就把js代碼注入到網頁中並且執行。主要解釋一下window.androidWebView.openSoftInput(this.id,this.type)這一句。androidWebView是

webView.addJavascriptInterface(new JavascriptInterface(),
				"androidWebView");

在這一句中給你的JavascriptInterface類相當於起的一個給網頁調用的別名。後面openSoftInput(this.id,this.type)是你在JavascriptInterface這個類中定義的函數名括號裏面是參數都是String類型。這樣在黨文本框獲取到焦點的時候,會調用你在JavascriptInterface類中定義的openSoftInput函數,並且把當前密碼框的id,type傳過去(其實type後來我發現沒用着,但是留着日後萬一可以拓展)這時候就是java代碼了,你在openSoftInput函數中寫你如何調用自定義鍵盤的邏輯就可以了。

2.自定義鍵盤假裝你已經寫好了(網上很多代碼這裏也不提供了)

這個鍵盤可以通過dialog、popWindow等方式彈出,然後就是如何把輸入的值設置到當前密碼框。首先自定義的鍵盤要想跟系統鍵盤一樣,可以對此input密碼框增刪查改的話,必須拿到一個類似EditTextView中一個Editable的對象,對這個對象進行操作。但是這個是網頁,如果要實現那很繁瑣,這裏給大家提供一個簡單的思路,就是在自定義的鍵盤上面提供一個android原生的EditTextView,把你的密碼首先輸入到這個文本框,等到自定義鍵盤dismiss或者點擊上面的ok按鈕時,通過上面WebView.loadUrl(....)的方式設置給這個密碼框,這樣簡單很多。請看:

//如果輸入的是\符號會被轉義,需要輸入\\兩次才能設置進去
	private void setPassword(final String id ,final String pwd){
		webView.post(new Runnable() {
			@Override
			public void run() {
				webView.loadUrl("javascript:(function(){" +
						"var objs = document.getElementById(\""+id+"\");" +
						"objs.value=\""+pwd +"\";"+
                        "objs.blur();" +
                        "})()");
			}
		});
    }

這裏由於直接用WebView.loadUrl會拋出一個異常,大致意思就是線程不能執行這個操作,所以就用了異步的方式。在設置值objs.value=pwd後執行objs.blur讓此時的密碼框失去焦點,爲啥要這樣做,因爲我們注入的是onFocus事件,如果不讓它失去焦點的話,你再點擊到當前密碼框,onFocus事件不會調用,所以你的鍵盤就彈不出來。特別注意:經過測試這種設置的方式目前發現兩個特殊符號要做轉義處理,否則這個值不但設置不進去而且你的js代碼不會執行(是js報錯了,但是不會引起程序崩潰)。兩個符號是雙引號(")、反斜槓(\)。

細節處理:怎麼處理呢,就是把你的pwd拆分出來,如果有(")或者(\)就在他們前面添加一個(\)來轉義一下例如:我輸入的密碼是(" " " " " ")六個雙引號,那麼你處理過後給js設置的時候應該是(\"\"\"\"\"\")。再例如我輸入的密碼是(\\\\\\)六個反斜槓那麼你處理後給js設置的時候應該是(\\\\\\\\\\\\)沒錯十二根斜槓,因爲每一根你都要給他轉義,哈哈哈!

基本思路和核心代碼都寫出來了,相信大家應該可以自己擼起來了。

事後我感覺這種入侵代碼的方式頗有爬蟲的感覺,哈哈,大概暴力破解密碼的方式就是基於這種思想來玩的吧!

以上代碼寫的很難看,用了很多+號什麼的,因爲項目本身代碼是要保密的,這是臨時擼的,思想大家理解了就可以有千萬個實現方式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章