GoBack () solution not normal due to redirection
first of all, the initial page is a, click a link to jump to B (http://xxx.com.cn/), b page Redirect to C page (http://xxx.com.cn/website/index.html)
When Webview.goback () is invoked, the page is rolled back to B and then redirected back to the C page.
This can cause two problems:
1. Unable to fall back to WebView's initial page a
2. Unable to exit the activity normally or fragment (only if you have not finished loading C, fallback to exit the page)
As for how to solve this problem, I have summarized the following three methods, which can be used according to the specific situation:
First, the need to communicate with front-end developers, the importance of orientation is necessary, if the jump link is only the domain name, and then the default redirect to the domain name/index.html, and there is no special treatment, then this redirection does not make sense.
Just connect the pages, like
Replace directly with the
<a href= "http:///xxx.com.cn/index.html"/>
Can resolve the problem.
Two. The redirection in the page is necessary, then we need to maintain a WebView history stack, filter or reload the page according to our own needs:
To determine which link is currently redirected, then you need to ignore the link at the top level when you rollback, without using webview.goback (), and remove the redirected and redirected URLs.
Gets the Loadurl () action after the initial page link.
3. There is also a method, and method 2 similar to the need to maintain their own webview history stack, but the need for front-end coordination, to provide a JS function to get the page is redirected
When the URL is filtered in the webviewclient callback Shouldoverloading (), if it is a redirected address, it is not added to the stack and can be loaded according to the historical stack when it is rolled back.
This is mainly about method two:
First, define a history stack:
Private arraylist<string> Loadhistoryurls = new arraylist<string> ();
Add the initial page URL
Loadhistoryurls.add (Inital_web_url);
Then add the loaded URL:
public boolean shouldoverrideurlloading (webview view,string URL) {
//Add filtered URL to the history stack
loadhistoryurls.add (url );
return true;
}
Finally in Webview.goback () Processing:
@Override Public
boolean onKeyDown (int keycode, keyevent event) {
//To determine if the operation can be returned (
Webview.cangoback () && Event.getkeycode () = = Keyevent.keycode_back) {
//filtering for redirected links
if (loadhistoryurls.size () >0 &&loadurls.get (Loadhistoryurls.size ()-1). Contains ("index.html")
//Remove the last two links
in the load stack Loadhistoryurls.remove (Loadhistoryurls.get (Loadhistoryurls.size ()-1));
Loadhistoryurls.remove (Loadhistoryurls.get (Loadhistoryurls.size ()-1));
Load orientation before the page
webview.load (Loadurls.get (Loadhistoryurls.size ()-1));
return true;
}
}
With regard to the load stack, it was later found that the webview itself had the corresponding API:
Get History list
webbackforwardlist mwebbackforwardlist = Webview.copybackforwardlist ();
However, this API may be affected by the system version or modified by different phone systems.
So when we solve this problem, we can maintain the loading history stack or call the system API directly on demand.
Here to sum up, if the redirection is not necessary, take the plan one, the simplest, the modification is very small. Redirection is necessary, use scenario two or scenario three.
Because of the need to interact with the front-end staff, the project three needs of communication, development, maintenance costs are much higher than the scheme two, but for whether the decision to redirect is very accurate, if there are multiple redirects, once the development is completed without the need to change the code again. Program two need to write dead URL to filter, if there are multiple redirects, it will appear to be more bloated code, each need to add code. Specific use depends on the development of the project.
Finally, a generic approach is needed, but it requires strong background support: When WebView is loaded, the request is sent to the server, which is then parsed by the server, and the result is returned to the client for display. And the server can encode the content of the Web page or remove redundancy, and combined with CDN to improve the response speed, this is the current browser development of a common strategy. But a large number of data collection, analysis and processing, the server's reliance on more serious, if the development of a tight schedule or limited company resources, can be solved by reference to the above methods.
The most important thing to say, this article is mainly for loading the development of the H5 encountered problems in the solution, as to Third-party Web site loading, this is no way to solve. including the micro-letter also, for a variety of public platforms and Third-party links, there is no general solution, so they are in the interactive processing, a jump in the H5 will be in the top left corner of the title bar appears close button. After all, the user is not aware of fast consecutive clicks two times return to normal return to the home page.
JS Object Injection Vulnerability Solution
1, use the scene
we often use WebView to show a Web page, now many applications in order to achieve a server-controlled, many results pages are web pages, rather than local implementation, there are many benefits, such as the interface changes do not need to redistribute a new version, directly on the server side to modify the line. Use Web pages to show the interface, typically, there is more or less interaction with Java code, such as clicking on a button on the page, we need to know the button click event, or we want to call a method, let the page perform some action, in order to achieve these interactions, we usually use JS to achieve, And WebView has provided such a method, the specific use is as follows:
Mwebview.getsettings (). Setjavascriptenabled (true);
Mwebview.addjavascriptinterface (New Jsinterface (), "jsinterface");
We register a name "Jsinterface" object to WebView, then can access to jsinterface this object in JS, can call some methods of this object, finally can call to Java code, realize JS and Java code of interaction.
Let's take a look at the description of the Addjavascriptinterface method on the Android website:
This can is used to allow JavaScript to control the host application. This is a powerful feature, but also presents a security risk for applications targeted to API level Jelly_bean or below, Because JavaScript could use reflection to access a injected object ' s public fields. Use of this method in a WebView containing untrusted content could allow a attacker to manipulate the host application in unintended ways, executing Java code with the permissions of the host application. Use extreme care The When using this method in a webview which could contain content.
JavaScript interacts with Java object in a private, background thread of this webview. Care is therefore required to maintain thread safety.
The Java object ' s fields are not accessible.
Simply put, it is possible to use addjavascriptinterface to cause insecurity because JS may contain malicious code. The loophole we're going to talk about today is this, and when JS contains malicious code, it can do everything.
2, vulnerability description
through JavaScript, you can access the current device's SD card anything above, even contact information, SMS and so on. It's disgusting, quack. Well, let's look at how this was wrong. You can look at this bug description on the Cloud platform: hit this spot.
1,webview added a JavaScript object, and the current application has read and write SDcard permissions, namely: Android.permission.WRITE_EXTERNAL_STORAGE
The 2,js can traverse the Window object, find the object of the object with the "GetClass" method, and then get the runtime object through the reflection mechanism, and then call the static method to execute some commands, such as the command to access the file.
3, and then from the execution of the command returned after the input stream to get the string, you can get the file name information. Then you can do whatever you want, so it's dangerous. The core JS code is as follows:
function Execute (Cmdargs)
{for
(var obj. window) {
if ("GetClass" in Window[obj]) {
alert (obj);
Return Window[obj].getclass (). forname ("Java.lang.Runtime")
. GetMethod ("GetRuntime", null). Invoke (Null,null). EXEC (Cmdargs);
}
}
3, proof of vulnerability
For example: To prove this loophole, write a demo to illustrate. I'm just loading a local web page containing malicious JS code, and the HTML code is as follows:
This HTML works as follows:
Figure I: expected to run the result chart
Above, click on the button, JS passed a paragraph of text to the Java code, show a toast, click on the picture, the picture url,width,height to the Java layer, also with toast display.
To implement such a feature, you need to note the Java object.
Simply explain
1, see the Execute () method, which iterates through all the window objects, finds the object containing the GetClass method, uses the object's class, finds the Java.lang.Runtime object, and then invokes the GetRuntime The static method method gets an instance of runtime, and then calls the Exec () method to execute a command.
The 2,getcontents () method reads the content from the stream and displays it on the interface.
3, the key code is the following two sentences
Return Window[obj].getclass (). forname ("Java.lang.Runtime")
. GetMethod ("GetRuntime", null). Invoke (Null,null). EXEC (Cmdargs);
The Java code is implemented as follows:
Mwebview = (webview) Findviewbyid (R.id.webview);
Mwebview.getsettings (). Setjavascriptenabled (true);
Mwebview.addjavascriptinterface (New Jsinterface (), "Jsinterface");
Mwebview.loadurl ("file:///android_asset/html/test.html");
Permissions to add:
<uses-permission android:name= "Android.permission.INTERNET"/>
<uses-permission android:name= " Android.permission.ACCESS_NETWORK_STATE "/>
<uses-permission android:name=" android.permission.WRITE_ External_storage "/>
When you click on the Load menu, run the screenshot below: (in theory, there should be a graphical interface)
Figure II: Actual running results, listing the files in the SDcard
Example two: 360 browsers also have this problem, I tested the system is the Android 4.0.2,360 browser version is: 4.8.7
In the browser input box, enter: http://bitkiller.duapp.com/jsobj.html, and then go to, it will appear the following interface
Figure three: 360 Browser Run results
Description: Where Searchboxjavabridge_ is not a 360-injected object, it is injected inside the webview, which is added on the Android system after 3.0.
After closing this dialog box, it lists all the files listed on the current SDcard, as shown in the following figure
Figure IV: Error results
4, Solution
(1), Android more than 4.2 of the system
over 4.2 of Android, Google made a correction by declaring a @javascriptinterface in the Java remote method, such as the following code:
(2), under the Android 4.2 system
This problem is more difficult to solve, but it is not impossible to solve.
First of all, we definitely can't call the Addjavascriptinterface method any more. On this issue, the core is to know the JS event this action, JS and Java interaction We know that there are several, than prompt, alert and so on, such actions will correspond to the Webchromeclient class in the corresponding method, for prompt, Its corresponding method is the Onjsprompt method, which is declared as follows:
public boolean onjsprompt (WebView view, string URL, String message,
string defaultvalue, jspromptresult result)
Through this method, JS can transfer information (text) to Java, and Java can also transfer information (text) to JS, notify the idea we can find solutions?
After a number of attempts and analysis, to find a more feasible solution, please look at the following small points:
"1" Let JS call a JavaScript method, this method is to call the prompt method, through the prompt the information in JS passed over, this information should be our combination of a meaningful text, may include: specific identification, method name, parameters and so on. In the Onjsprompt method, we parse the passed text, get the method name, parameters, and so on, and then invoke the specified method through the reflection mechanism to invoke the method to the Java object.
"2" about the return value, you can return it via prompt, so you can return the processing results of Java methods to JS.
"3" We need to dynamically generate a section of the JavaScript method of the JS script, by Loadurl to load it, and thus register into the HTML page, the specific code is as follows:
JavaScript: (function Jsaddjavascriptinterface_ () {
if (typeof (Window.jsinterface)!= ' undefined ') {
Console.log (' Window.jsinterface_js_interface_name is exist!! ');}
else {
Window.jsinterface = {
onbuttonclick:function (arg0) {return
prompt (' MyApp: ' +json.stringify ({obj : ' Jsinterface ', func: ' OnButtonClick ', args:[arg0]});
},
onimageclick:function (arg0,arg1,arg2) {
Prompt (' MyApp: ' +json.stringify ({obj: ' jsinterface ', func: ' Onimageclick ', Args:[arg0,arg1,arg2]});}
;
}
}
) ()
Description
"1", the above code jsinterface is the object name to register, it registered two methods, OnButtonClick (arg0) and Onimageclick (arg0, Arg1, arg2), if there is a return value, add back.
"2", in prompt, is our agreed string, which contains a specific identifier MyApp:, followed by a string of JSON strings containing the method name, parameters, object name, and so on.
"3", when JS calls OnButtonClick or Onimageclick, it will call back to the Java layer of the Onjsprompt method, we then resolve the method name, parameter, object name, and then reflection call method.
"4", window.jsinterface this means declaring a JS object on the window, declaring the method in the form of a method name: function (parameter 1, parameter 2)
5, some thinking
The following are some of the issues and considerations that are encountered during the implementation of this solution:
(1) After the generation of JS method, load This JS time is what?
At the beginning when the WebView normal load URL to load JS, but found that there will be problems, if the webview jump to the next page, before the loaded JS may be invalid, so need to load again. This problem has been tried, need to load JS in the following several methods, they are webchromeclient and Webviewclient method:
- Onloadresource
- Doupdatevisitedhistory
- onpagestarted
- Onpagefinished
- Onreceivedtitle
- Onprogresschanged
- There's nothing wrong with testing these places at the moment, and I'm not entirely sure there's no problem here.
(2) Need to filter out the object class method
Because the method of the specified object is obtained by reflection, he will also get the method of the base class, the topmost base class is object, so we need to filter out the public method of object in order not to inject the GetClass method into JS. Strictly speaking, there should be a list of methods to filter. At present, in my implementation, the methods that need to be filtered are:
- "GetClass",
- "Hashcode",
- "Notify",
- "Notifyall",
- "Equals",
- "ToString",
- "Wait",
(3) by manual loadurl to load a section of JS, this way the object in JS is not in window? In other words, by traversing the Window object, can not find us through the Loadurl injected JS object?
On this issue, our method is through JS declaration, through the form of Loadurl to inject into the page, in fact, the essence of this dynamically generated this section of JS directly written in the HTML page, so, these JS window, although the inclusion of our declared object, But they are not Java objects, they are declared through the JS syntax, so there is no getclass such methods. In essence they are JS objects.
(4) under the Android 3.0, the system has added a JS interface called Searchboxjavabridge_, to solve this security problem, we also need to remove this interface, call the Removejavascriptinterface method. This searchboxjavabridge_ seems to be related to Google's search box.
(5) In the implementation process, we need to determine if the system version is below 4.2, because Android fixes this security issue over 4.2. We just need to fix the system under 4.2.