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
求出現(xiàn)的原因是這樣的:
我們有一個(gè) h5 頁面既需要嵌套到 App 內(nèi)部進(jìn)行用戶的信息填寫及提交,同時(shí)這個(gè) h5 頁面也能夠單獨(dú)使用。 而這些用戶信息中就包括 `input`框選擇圖片。 <input type="file" name="avatar" id="avatar" />
出現(xiàn)了什么問題呢?
那么問題就出在 input 框這里,點(diǎn)擊這個(gè) input 框,調(diào)起 android 手機(jī)自帶的拍照和選擇文件的對(duì)話框。
小米手機(jī)系統(tǒng)調(diào)起
只要選擇「圖片」或者「拍照」都沒有問題
問題就出現(xiàn)在選擇「取消」的時(shí)候
出現(xiàn)了問題,需要先解決點(diǎn)擊「取消」程序卡死的問題
這個(gè)問題,這篇文章已經(jīng)介紹過了
H5 通過 input 標(biāo)簽,調(diào)起 Android 手機(jī)相冊,點(diǎn)擊取消時(shí)手機(jī)卡住
如果之前沒有配置過,可以參考配置一下。
下面說今天的正題,就是點(diǎn)擊取消之后,如果之前頭像內(nèi)有圖片,那么取消后會(huì)把之前的圖片干掉,展示出一個(gè)加載錯(cuò)誤的樣子
原因找到了:當(dāng)取消的時(shí)候,為了避免卡頓,返回了一個(gè)圖片的路徑,但是這個(gè)圖片路徑上對(duì)應(yīng)的圖片是不存在的,從而導(dǎo)致了 H5 img 位置 顯示加載失敗
加載失敗
那么現(xiàn)在問題就來了:
如果不返回,就會(huì)卡頓;
如果返回了,就把 img 之前的展示圖片給干掉了
怎么辦呢?
我這邊的思路是:
將原來的 img 標(biāo)簽內(nèi)的 src 的內(nèi)容存儲(chǔ)到本地,然后判斷:如果用戶點(diǎn)擊了取消,那么就將這個(gè)原來的 src 內(nèi)容返回回去
那么這樣操作的話,就需要知道,如何拿到 img 標(biāo)簽中的 src 的內(nèi)容。
那么實(shí)際需要做這么幾部
1、這個(gè)需要和 H5 或者后臺(tái)溝通一下,將 H5 中的 這個(gè)頭像的 id 唯一,以保證能唯一找到這個(gè)頭像。
2、根據(jù) id 找到這個(gè) img 標(biāo)簽后,再拿 src 中的內(nèi)容存儲(chǔ)到本地
3、判斷用戶點(diǎn)擊取消時(shí),將本地存儲(chǔ)的圖片 src 內(nèi)容,返回給 H5。
第三點(diǎn)已經(jīng)在
H5 通過 input 標(biāo)簽,調(diào)起 Android 手機(jī)相冊,點(diǎn)擊取消時(shí)手機(jī)卡住
這個(gè)文章中提到過了,找到合適的位置直接返回即可。
所以本篇文章中的重點(diǎn)就是第一步:根據(jù) id 找到 src 的內(nèi)容。
1、創(chuàng)建 addJavascriptInterface 需要的「操作對(duì)象」,這個(gè)操作對(duì)象就是一個(gè)類,名字隨便起,不過內(nèi)部的方法必須添加@JavascriptInterface注解
//內(nèi)部類 final class InJavaScriptLocalObj { private static final String TAG = "MainActivity"; /** * @JavascriptInterface 必須要有的哦 * @param html * * 一旦檢測到 html 匹配到了要找的元素或者屬性,這里就會(huì)調(diào)用,否則不會(huì)調(diào)用這個(gè)方法 */ @JavascriptInterface public void showAvatar(String html) { Log.e(TAG, "showAvatar: " + html); } }
2、配置 webview
private void initWebView() { /** * 三項(xiàng)均需配置 */ webView.getSettings().setJavaScriptEnabled(true); webView.addJavascriptInterface(new InJavaScriptLocalObj(), "local_obj"); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { webView.loadUrl(url); return true; } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); /** * ambassador_avatar 是和后臺(tái)(h5)商議的唯一的 id */ view.loadUrl("javascript:window.local_obj.showAvatar(document.getElementById('ambassador_avatar').getAttribute('src'));"); } }); }
那么找元素關(guān)鍵的一句,就是
view.loadUrl("javascript:window.local_obj.showAvatar(document.getElementById('ambassador_avatar').getAttribute('src'));");
備注
找元素的方法很相似,就是跟 html 中的找 dom 節(jié)點(diǎn)一樣
可以移步到 w3school 逛網(wǎng)看一看
dom 元素查找方法
這里小總結(jié)一下
通過 id 查找 HTML 元素 通過標(biāo)簽名查找 HTML 元素 通過類名查找 HTML 元素 通過 CSS 選擇器查找 HTML 元素 通過 HTML 對(duì)象集合查找 HTML 元素 var myElement = document.getElementById("intro");//返回單個(gè)元素 var x = document.getElementsByTagName("p");//返回元素列表 var x = document.getElementsByClassName("intro");//返回元素列表 var x = document.querySelectorAll("p.intro");//返回元素列表 var x = document.forms["frm1"];//返回元素列表
返回元素列表的方法在使用是 需要像數(shù)組那樣去取得對(duì)應(yīng)的元素,如x[0]
拿到元素之后,通過 DOM 的文檔,拿到想要的屬性、值等等信息。
這樣就能通過存儲(chǔ)原來的圖片信息,在點(diǎn)擊取消的時(shí)候把信息返回,解決了本次需求的問題。
謝謝大家的收藏、關(guān)注、轉(zhuǎn)發(fā),持續(xù)更新!
1、Android中利用webView調(diào)用網(wǎng)頁上的Js代碼。
Android 中可以通過webView來實(shí)現(xiàn)和Js的交互,在程序中調(diào)用Js代碼,只需要將webView控件的支持Js的屬性設(shè)置為true,然后通過loadUrl就可以直接進(jìn)行調(diào)用,如下所示:
mWebView.getSettings().setJavaScriptEnabled(true); mWebView.loadUrl("javascript:test()");
2、網(wǎng)頁上調(diào)用Android中Java代碼的方法
在網(wǎng)頁中調(diào)用Java代碼,需要在webView控件中添加javascriptInterface。如下所示:
mWebView.addJavascriptInterface(new Object() { public void clickOnAndroid() { mHandler.post(new Runnable() { public void run() { Toast.makeText(Test.this, "測試調(diào)用java", Toast.LENGTH_LONG).show(); } }); } }, "demo");
在網(wǎng)頁中,只需要像調(diào)用Js方法一樣,進(jìn)行調(diào)用就可以
<div id='b'><a onclick="window.demo.clickOnAndroid()">b.c</a></div>
3、Java代碼調(diào)用Js并傳參
首先需要帶參數(shù)的Js函數(shù),如function test(str),然后只需在調(diào)用Js時(shí)傳入?yún)?shù)即可,如下所示:
mWebView.loadUrl("javascript:test('aa')");
4、Js中調(diào)用Java函數(shù)并傳參
首先一樣需要帶參數(shù)的函數(shù)形式,但需注意此處的參數(shù)需要final類型,即得到以后不可修改,如果需要修改其中的值,可以先設(shè)置中間變量,然后進(jìn)行修改。如下所示:
mWebView.addJavascriptInterface(new Object() { public void clickOnAndroid(final int i) { mHandler.post(new Runnable() { public void run() { int j = i; j++; Toast.makeText(Test.this, "測試調(diào)用java" + String.valueOf(j), Toast.LENGTH_LONG).show(); } }); } }, "demo");
然后在html頁面中,利用如下代碼:
<div id='b'><a onclick="window.demo.clickOnAndroid(2)">b.c</a></div>,
即可實(shí)現(xiàn)調(diào)用
web安全對(duì)iOS開發(fā)者來說重要嗎?重要!APP中通常會(huì)使用很多web頁面,例如廣告、登錄流程、閃屏,或者需要使用跨平臺(tái)功能的時(shí)候。你可能在頁面中僅僅一部分使用web,也可以整個(gè)頁面都是webView,甚至做一個(gè)web app。因此web安全對(duì)于app來說非常重要。
來自web的安全攻擊有以下幾種:
本文將針對(duì)這三種攻擊類型,給出安全防御措施。
網(wǎng)絡(luò)傳輸相信大家都很熟悉了,安全的傳輸能夠保證接收到的數(shù)據(jù)來自可信任的站點(diǎn),并且在傳輸工程中不會(huì)被篡改。安全傳輸是其它安全措施的基礎(chǔ),采取的措施包括:
Allow Arbitrary Loads in Web Content 這個(gè)開關(guān)一定要置為 NO!
web的內(nèi)容可以來自任何站點(diǎn),例如,webView上的一張圖片可以來自任何服務(wù)器,也可以從任意服務(wù)器上加載一個(gè)腳本或iframe。需要注意的是要當(dāng)心來自其它服務(wù)器的資源。跨域的保護(hù)已經(jīng)有20多年的歷史,并且形成了基本原則--同源策略:只有和頁面來源相同的腳本才會(huì)被該頁面執(zhí)行。例如iframe來自不同的域名,同源策略不允許加載這個(gè)iframe。僅僅靠同源策略還是不夠的,還需要采取其它的防御措施。
服務(wù)器可能會(huì)發(fā)生異常導(dǎo)致下發(fā)錯(cuò)誤的資源使得web發(fā)生crash,但是開發(fā)者通常是知道所要請求哪個(gè)資源的,在腳本里面增加一個(gè)檢查簽名。如果簽名匹配則認(rèn)為是下發(fā)了正確的資源,如果不匹配仍然可以正常工作,此時(shí)嘗試從頁面的資源里查找或者從自己的服務(wù)器重新加載。這樣做雖然降低了性能,但是提升了安全性。
<script src="https://cdn.example/framework.js" integrity="sha256-8WqyJLuWKRB...oZkCnxQbWwJVw="> </script> window.framwork || // reload from own domain
HTTP response: :status:200 Content-Security-Policy: default 'self'; // No inline script-src cdn.example; frame-src social.example; frame-ancestors news.example;
HTTP response的Header里面,default設(shè)置成自己,默認(rèn)只能加載同源的資源;script-src和frame-src 分別指定可信任的腳本和iframe的來源;frame-ancestor設(shè)置成news.example,指定只有news.example可以iframe我們的web。
另外不使用inline屬性的腳本也是一種防御措施,不使用inline腳本,只從文件加載腳本,這么做分離了邏輯和文件,更加安全。
HTTPOnly cookies作為一種安全措施,已經(jīng)有至少15年的使用歷史。在這之前script通過document.cookie這個(gè)強(qiáng)大的api能拿到文檔的cookie,留下安全隱患。HTTPOnly cookies能夠阻止這種情況,只允許HTTP請求訪問cookie,禁止使用script訪問cookie。它的使用方式很簡單,只需要在HTTP response的Header里面加上HttpOnly這一項(xiàng),如下
HTTP response: :status:200 Set-Cookie: auth = abc...123; HttpOnly;
在HTTP response的Header里面將SameSite cookies這一項(xiàng)設(shè)置為Strict,那么將不允許把cookie從一個(gè)域名發(fā)送到另一個(gè)域名。例如其他人的web里面嵌入了我們的web,如果我們的服務(wù)器HTTP response的Header里面SameSite cookies = Strict,那么其他人將無法使用他的cookie來訪問我們的服務(wù)器。
HTTP response: :status:200 Set-Cookie: auth = abc...123; HttpOnly; SameSite=strict
Cross-Origin-Resource-Policy是推出的新功能。之前web可以加載任意web中的資源,例如圖片或者script。在HTTP response的Header里面將Cross-Origin-Resource-Policy這一項(xiàng)設(shè)置為Same,將不允許別人的web向我們的服務(wù)器請求圖片或者script,但是我們自己的web可以。
HTTP response: :status:200 Cross-Origin-Resource-Policy:Same
Cross-Origin-Window-Policy也是新推出的功能。之前通過window.open這個(gè)強(qiáng)大的api,其他人的web可以在新窗口中打開我們域名下的web,通過一些手段可以修改我們的web,導(dǎo)航到攻擊者指定的頁面。在HTTP response的Header里面將Cross-Origin-Resource-Policy這一項(xiàng)設(shè)置為Deny,將阻止其他人修改我們web中的內(nèi)容,當(dāng)然別人仍然還是可以打開我們的web。Cross-Origin-Resource-Policy適用于希望使用post message 進(jìn)行窗口間通信,但是不想讓別人控制我們自己web內(nèi)容的情況。
HTTP response: :status:200 Cross-Origin-Window-Policy:Deny
Cross-Origin Attacks
Cross-Site Scripting
例如我們的web里面有一個(gè)文本框,用戶可以輸入文字,如下圖。假如攻擊者注入了這么一段腳本,如果沒有采取防御措施,那么我們web的cookie就會(huì)被盜取。
在HTTP response的Header中添加HTTPOnly這一項(xiàng),就能阻止腳本訪問文檔的cookie,從而防御跨域腳本攻擊。
另外一種防御手段是Content-Security-Policy,如下
HTTP response: :status:200 Content-Security-Policy: default-src 'self'; // No inline
Content-Security-Policy能保證拒絕加載外部來源的腳本,并且不使用inline屬性的腳本,只從文件中加載腳本。
例如我們的web需要從某個(gè)外部資源裝載一個(gè)framework,攻擊者可能攔截這個(gè)請求,并把它重定向到自己的攻擊腳本上,如下圖
使用Content-Security-Policy中script-src這個(gè)屬性可以指定信任的腳本來源,并且在引用資源的時(shí)候指定來源和校驗(yàn)簽名,如下
在HTTP response中:
HTTP response: :status:200 Content-Security-Policy: default-src 'self'; script-src cdn.example;
在HTML中:
<script src="https://cdn.example/framework.js" integrity="sha256-8WqyJLuWKRB...oZkCnxQbWwJVw="> </script> window.framwork || // reload from own domain
攻擊者可能在自己的web中嵌入我們的web,然后向我們的服務(wù)器發(fā)起一個(gè)偽造的網(wǎng)絡(luò)請求(使用的是攻擊者網(wǎng)站的cookie),如下圖
如果采取了防御措施,將HTTP response的Header里面的SameSite設(shè)置為strict,那么就會(huì)禁止攻擊者網(wǎng)站的cookie發(fā)動(dòng)到我們的服務(wù)器上面,如下
HTTP response: :status:200 Set-Cookie: auth=abc...123; SameSite=strict
防御措施有:
Speculative execution 的定義:預(yù)測執(zhí)行類似于批量執(zhí)行條件判斷語句,例如計(jì)算機(jī)大量執(zhí)行"x是否會(huì)造成數(shù)組array越界"這條指令,就能推測出這個(gè)數(shù)組的長度,進(jìn)一步推測出這個(gè)數(shù)組在內(nèi)存緩沖區(qū)中的地址邊界。利用緩沖區(qū)溢出這種攻擊手段,可以向web中注入攻擊腳本。當(dāng)x超過數(shù)組邊界的時(shí)候,本來應(yīng)該執(zhí)行越界的error回調(diào),但是確取出了攻擊腳本并執(zhí)行,造成數(shù)據(jù)泄露。顯然只靠同源策略是無法防御這種攻擊的,因?yàn)楣裟_本和文檔處在同一個(gè)域名下,并且在同一個(gè)線程中。
防御預(yù)測執(zhí)行攻擊的方法是確保web內(nèi)容和其他iframe(例如攻擊腳本)處在不同的線程中。
以Safari app為例,WKWebView會(huì)單獨(dú)分離出一個(gè)NetWork線程用于處理添加cookie等邏輯,而且每個(gè)網(wǎng)頁處在不同的線程當(dāng)中,所以evil網(wǎng)頁是無法通過預(yù)測執(zhí)行攻擊手段攻擊我們的頁面。而且因?yàn)镹etWork線程也是獨(dú)立的,所以evil網(wǎng)頁也無法通過預(yù)測執(zhí)行攻擊手段拿到重要數(shù)據(jù),例如cookie。
如果使用UIWebView,所有的web包括NetWork線程都在app的同一個(gè)線程中,所以是無法防御預(yù)測執(zhí)行攻擊手段的。
Content security policy的封鎖功能是處于Network線程中,和web線程是分離的,因此可以防御預(yù)測執(zhí)行攻擊手段。
例如web要加載一個(gè)廣告iframe,但是這個(gè)廣告iframe被重定向到了一個(gè)攻擊腳本,如果使用了Content security policy,如下,因?yàn)楣裟_本不在信任的frame-src里面,所以會(huì)禁止加載。還有一種情況,攻擊者的web引入了我們的web,因?yàn)樵O(shè)置了frame-ancestors為none,所以會(huì)禁止攻擊者網(wǎng)站引入我們的web,從而防御攻擊。
HTTP response: :status:200 Content-Security-Policy: default-src 'self'; frame-src ad.example social.example frame-ancestors 'none'
HttpOnly cookies 和 SameSite cookies的封鎖功能也是處于Network線程中,和web線程是分離的,因此可以防御預(yù)測執(zhí)行攻擊手段。HttpOnly cookies能夠禁止攻擊者通過腳本拿到cookie。SameSite cookies設(shè)為strict能夠禁止cookie從一個(gè)域發(fā)送到另一個(gè)域。
Cross-Origin-Resource-Policy
Cross-Origin-Resource-Policy的封鎖功能也是處于Network線程中,和web線程是分離的,因此可以防御預(yù)測執(zhí)行攻擊手段。Cross-Origin-Resource-Policy設(shè)置成Same能禁止攻擊者的web加載我們網(wǎng)站的資源。
Window Control Attacks
Cross-Origin-Window-Policy
攻擊者的頁面可以通過window.open這個(gè)api在新的窗口打開我們的web,攻擊者趁我們不注意的時(shí)候,把我們的頁面導(dǎo)航到釣魚頁面,然后誘導(dǎo)用戶填寫用戶名和密碼,這樣就竊取到了用戶信息。把HTTP response Header里面的Cross-Origin-Window-Policy設(shè)置為Deny,能夠禁止攻擊者修改我們的web,這樣攻擊者就無法導(dǎo)航到釣魚頁面。
總結(jié)
每種安全措施防御的攻擊類型
*請認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。