展会信息港展会大全

Android PhoneGap源码分析——白名单
来源:互联网   发布日期:2015-09-24 19:13:47   浏览:5441次  

导读:对于单独的Web app应用来说,加载进来的url一般不能保证它的安全性。那么如何来处理url安全性的问题呢。 让我们来看看PhoneGap是如何做的。 PhoneGap采用了白名单的形式,认为在白名单中的url认为是安全的......

对于单独的Web app应用来说,加载进来的url一般不能保证它的安全性。那么如何来处理url安全性的问题呢。

让我们来看看PhoneGap是如何做的。

PhoneGap采用了白名单的形式,认为在白名单中的url认为是安全的,不在白名单中的url是不安全的。对于安全的url,PhoneGap的Web app会直接打开,对于不安全的url,会通过浏览器打开。

那么怎么增加白名单呢?PhoneGap是需要在配置文件res/xml/config.xml中设置,如下:

<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*" />就是加的白名单,我们只需要将网址后面加上*,上格式加进配置文件即可。

那么PhoneGap又是如何实现白名单的呢?让我们看一下源代码:CordovaWebView.java。CordovaWebView是显示的WebView的基类。它在初始化时,会加载配置文件的配置项,源代码如下:

/**

* 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);

}

}

在解析xml文件时,会将origin标签中的内容加入白名单,调用的是addWhiteListEntry方法。下面我们来看看addWhiteListEntry方法的源代码:

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);

}

}

我们可以看到,它用正则表达式解析后将白名单中的url加入到whiteList这个属性中,而whiteList是个ArrayList类型的属性。

那么PhoneGap的Web app在显示网页时又是如何利用白名单的呢?让我们继续来看下面的源代码,这是加载网页时会调用的方法:

/**

* 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);

}

}

}

我们可以看到,里面会用isUrlWhiteListed等方法判断该url是否在白名单中,或者是否安全,然后对安全的url直接通过loadUrl来 加载进该Web app,对于PhoneGap认为不安全的url会通过发Intent的形式打开浏览器加载该网页。

下面再贴一段isUrlWhiteListed方法的源代码:

/**

* 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;

}

赞助本站

人工智能实验室

相关热词: PhoneGap

AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港