Android PhoneGap source code analysis-whitelist

Source: Internet
Author: User

For a single Web app, the loaded url generally does not guarantee its security. So how to deal with url security issues.

Let's take a look at how PhoneGap works.

PhoneGap uses a whitelist. The url in the whitelist is considered safe, and the url not in the whitelist is insecure. For secure URLs, the Web app of PhoneGap will open directly. For insecure URLs, It will be opened through a browser.

So how to add a white list? PhoneGap needs to be set in the configuration file res/xml/config. xml, as follows:

 

 <cordova>- <!--     access elements control the Android whitelist.    Domains are assumed blocked unless set otherwise       -->   <access origin="http://127.0.0.1*" /> - <!--  allow local pages   --> - <!--  <access origin="https://example.com" /> allow any secure requests to example.com   --> - <!--  <access origin="https://example.com" subdomains="true" /> such as above, but including subdomains, such as www   -->   <access origin=".*" />   <log level="DEBUG" />   <preference name="useBrowserHistory" value="false" />   <preference name="exit-on-suspend" value="false" /> - <plugins>  <plugin name="App" value="org.apache.cordova.App" />   <plugin name="Geolocation" value="org.apache.cordova.GeoBroker" />   <plugin name="Device" value="org.apache.cordova.Device" />   <plugin name="Accelerometer" value="org.apache.cordova.AccelListener" />   <plugin name="Compass" value="org.apache.cordova.CompassListener" />   <plugin name="Media" value="org.apache.cordova.AudioHandler" />   <plugin name="Camera" value="org.apache.cordova.CameraLauncher" />   <plugin name="Contacts" value="org.apache.cordova.ContactManager" />   <plugin name="File" value="org.apache.cordova.FileUtils" />   <plugin name="NetworkStatus" value="org.apache.cordova.NetworkManager" />   <plugin name="Notification" value="org.apache.cordova.Notification" />   <plugin name="Storage" value="org.apache.cordova.Storage" />   <plugin name="Temperature" value="org.apache.cordova.TempListener" />   <plugin name="FileTransfer" value="org.apache.cordova.FileTransfer" />   <plugin name="Capture" value="org.apache.cordova.Capture" />   <plugin name="Battery" value="org.apache.cordova.BatteryListener" />   <plugin name="SplashScreen" value="org.apache.cordova.SplashScreen" />   <plugin name="Echo" value="org.apache.cordova.Echo" />   <plugin name="Globalization" value="org.apache.cordova.Globalization" />   </plugins>  </cordova>

 

 

<Access origin = "http: // 127.0.0.1 *"/> is the added whitelist. You only need to add * to the URL and add the preceding format to the configuration file.

So how does PhoneGap implement a whitelist? Let's take a look at the source code: CordovaWebView. java. CordovaWebView is the base class of the displayed WebView. It loads configuration items in the configuration file during initialization. The source code is as follows:

 

    /**     * Load Cordova configuration from res/xml/cordova.xml.     * Approved list of URLs that can be loaded into DroidGap     *      <access origin="http://server regexp" subdomains="true" />     * Log level: ERROR, WARN, INFO, DEBUG, VERBOSE (default=ERROR)     *      <log level="DEBUG" />     */    private void loadConfiguration() {        int id = getResources().getIdentifier("config", "xml", this.cordova.getActivity().getPackageName());        if(id == 0)        {            id = getResources().getIdentifier("cordova", "xml", this.cordova.getActivity().getPackageName());               Log.i("CordovaLog", "config.xml missing, reverting to cordova.xml");        }        if (id == 0) {            LOG.i("CordovaLog", "cordova.xml missing. Ignoring...");            return;        }        XmlResourceParser xml = getResources().getXml(id);        int eventType = -1;        while (eventType != XmlResourceParser.END_DOCUMENT) {            if (eventType == XmlResourceParser.START_TAG) {                String strNode = xml.getName();                if (strNode.equals("access")) {                    String origin = xml.getAttributeValue(null, "origin");                    String subdomains = xml.getAttributeValue(null, "subdomains");                    if (origin != null) {                        this.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0));                    }                }                else if (strNode.equals("log")) {                    String level = xml.getAttributeValue(null, "level");                    LOG.i("CordovaLog", "Found log level %s", level);                    if (level != null) {                        LOG.setLogLevel(level);                    }                }                else if (strNode.equals("preference")) {                    String name = xml.getAttributeValue(null, "name");                    String value = xml.getAttributeValue(null, "value");                    LOG.i("CordovaLog", "Found preference for %s=%s", name, value);                    Log.d("CordovaLog", "Found preference for " + name + "=" + value);                    // Save preferences in Intent                    this.cordova.getActivity().getIntent().putExtra(name, value);                }            }            try {                eventType = xml.next();            } catch (XmlPullParserException e) {                e.printStackTrace();            } catch (IOException e) {                e.printStackTrace();            }        }        // Init preferences        if ("true".equals(this.getProperty("useBrowserHistory", "false"))) {            this.useBrowserHistory = true;        }        else {            this.useBrowserHistory = false;        }        if ("true".equals(this.getProperty("fullscreen", "false"))) {            this.cordova.getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);            this.cordova.getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);        }    }

 

 

When parsing an xml file, the content in the origin tag is added to the whitelist and the addWhiteListEntry method is called. Let's take a look at the source code of the addWhiteListEntry method:

 

    public void addWhiteListEntry(String origin, boolean subdomains) {        try {            // Unlimited access to network resources            if (origin.compareTo("*") == 0) {                LOG.d(TAG, "Unlimited access to network resources");                this.whiteList.add(Pattern.compile(".*"));            } else { // specific access                // check if subdomains should be included                // TODO: we should not add more domains if * has already been added                if (subdomains) {                    // XXX making it stupid friendly for people who forget to include protocol/SSL                    if (origin.startsWith("http")) {                        this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://(.*\\.)?")));                    } else {                        this.whiteList.add(Pattern.compile("^https?://(.*\\.)?" + origin));                    }                    LOG.d(TAG, "Origin to allow with subdomains: %s", origin);                } else {                    // XXX making it stupid friendly for people who forget to include protocol/SSL                    if (origin.startsWith("http")) {                        this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://")));                    } else {                        this.whiteList.add(Pattern.compile("^https?://" + origin));                    }                    LOG.d(TAG, "Origin to allow: %s", origin);                }            }        } catch (Exception e) {            LOG.d(TAG, "Failed to add origin %s", origin);        }    }

 

We can see that the url in the whiteList is added to the whiteList attribute after regular expression parsing, while whiteList is an ArrayList attribute.

 

So how does the PhoneGap Web app use the whitelist when displaying webpages? Let's continue to look at the following source code. This is the method that will be called when a webpage is loaded:

 

    /**     * Load the specified URL in the Cordova webview or a new browser instance.     *     * NOTE: If openExternal is false, only URLs listed in whitelist can be loaded.     *     * @param url           The url to load.     * @param openExternal  Load url in browser instead of Cordova webview.     * @param clearHistory  Clear the history stack, so new page becomes top of history     * @param params        DroidGap parameters for new app     */    public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap<String, Object> params) {        LOG.d(TAG, "showWebPage(%s, %b, %b, HashMap", url, openExternal, clearHistory);        // If clearing history        if (clearHistory) {            this.clearHistory();        }        // If loading into our webview        if (!openExternal) {            // Make sure url is in whitelist            if (url.startsWith("file://") || url.indexOf(this.baseUrl) == 0 || isUrlWhiteListed(url)) {                // TODO: What about params?                // Clear out current url from history, since it will be replacing it                if (clearHistory) {                    this.urls.clear();                }                // Load new URL                this.loadUrl(url);            }            // Load in default viewer if not            else {                LOG.w(TAG, "showWebPage: Cannot load URL into webview since it is not in white list.  Loading into browser instead. (URL=" + url + ")");                try {                    Intent intent = new Intent(Intent.ACTION_VIEW);                    intent.setData(Uri.parse(url));                    cordova.getActivity().startActivity(intent);                } catch (android.content.ActivityNotFoundException e) {                    LOG.e(TAG, "Error loading url " + url, e);                }            }        }        // Load in default view intent        else {            try {                Intent intent = new Intent(Intent.ACTION_VIEW);                intent.setData(Uri.parse(url));                cordova.getActivity().startActivity(intent);            } catch (android.content.ActivityNotFoundException e) {                LOG.e(TAG, "Error loading url " + url, e);            }        }    }

 

We can see that isUrlWhiteListed and other methods are used to determine whether the url is in the White List or secure, and then the secure url is directly loaded into the Web app through loadUrl, for a url that PhoneGap deems unsafe, it will open the browser to load the webpage in the Intent form.

 

Next I will post the source code of the isUrlWhiteListed method:

 

    /**     * Determine if URL is in approved list of URLs to load.     *     * @param url     * @return      */    public boolean isUrlWhiteListed(String url) {        // Check to see if we have matched url previously        if (this.whiteListCache.get(url) != null) {            return true;        }        // Look for match in white list        Iterator<Pattern> pit = this.whiteList.iterator();        while (pit.hasNext()) {            Pattern p = pit.next();            Matcher m = p.matcher(url);            // If match found, then cache it to speed up subsequent comparisons            if (m.find()) {                this.whiteListCache.put(url, true);                return true;            }        }        return false;    }

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.