Android进阶之路Android开发Android开发

Android浅谈网页打开APP(二)

2018-09-05  本文已影响29人  浪够_

上一节粗略讲述了URL Scheme如何打开app,这一节对这一机制进行详细说明

Android安全开发之浅谈网页打开App(一)

一. 网页打开APP简介

Android有一个特性,可以通过点击网页内的某个链接打开APP,或者在其他APP中通过点击某个链接打开另外一个APP,一些用户量比较大的APP,已经通过发布其AppLink SDK,开发者需要申请相应的资格,配置相关内容才能使用。这些都是通过用户自定义的URI scheme实现的,不过背后还是Android的Intent机制。Google的官方文档《Android Intents with Chrome》一文,介绍了在Android Chrome浏览器中网页打开APP的两种方法,一种是用户自定义的URI scheme(Custom URI scheme),另一种是“intent:”语法(Intent-based URI)。

第一种用户自定义的URI scheme形式如下:

scheme://host/path?parameters

第二种的Intent-based URI的语法形式如下:

intent://host/uri_path#Intent;参数;end

因为第二种形式大体是第一种形式的特例,所以很多文章又将第二种形式叫Intent Scheme URL,但是在Google的官方文档并没有这样的说法。

注意:使用Custom URI scheme给APP传递数据,只能使用相关参数来传递数据,不能想当然的使用scheme://host/uri_path#intent;参数;end的形式来构造传给APP的intent数据。具体原因看本文3.1章节

此外,还必须在APP的Androidmanifest文件中配置相关的选项才能产生网页打开APP的效果,具体在下面讲。

二. Custom Scheme URI打开APP

2.1 基本用法
需求:使用网页打开一个APP,并通过URL的参数给APP传递一些数据。
如自定义的Scheme为:

wdgz://wdfull/card?card_id=828

网页端的写法如下:

<?xml version="1.0 encoding="utf-8?>
<html>
     <head>
          <title>URL打开App</title>
     </head>
     <body>
          <a href="wdgz://wdfull/card?card_id=828">打开豌豆公主App</a>
     </body>
</html>

APP端接收来自网页信息的Activity,要在Androidmanifest.xml文件中Activity的intent-filter中声明相应action、category和data的scheme等。

<activity android:name="MyActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:scheme="wdgz"
                    android:host="wdfull" />

            </intent-filter>
</activity>

在MyActivity中接收intent并且获取相应参数的代码:

 @Override
 protected void onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val intent = getIntent()
        Log.d("shixiangyu",intent.toURI())
        val uri = intent.getData()

此时,我们可以看一下打印的intent.toURI()信息:


image.png

由上图可知Android系统自动为Custom URI scheme添加了默认的 #intent字段,以及category,launchFlags,component等信息。

另外还有以下几个API来获取相关信息:

getIntent().getScheme(); //获得Scheme名称

getIntent().getDataString(); //获得Uri全部路径

getIntent().getHost(); //获得host

三. Intent-based URI打开APP

3.1基本用法
Intent-based URI语法:

intent://
host/uri_path
#Intent;
action=[action];
category=[category];
component=[component]
scheme=[scheme];
end

注意:第二个Intent的第一个字母一定要大写,不然不会成功调用APP。

如何正确快速的构造网页端的intent?

可以先建个Android demo app,按正常的方法构造自己想打开某个组件的Intent对象,然后使用Intent的toUri()方法,会得到Intent对象的Uri字符串表示,并且已经用UTF-8和Uri编码好,直接复制放到网页端即可。

               Intent i = new Intent();
               i.setAction("android.intent.action.VIEW");
               i.addCategory("android.intent.category.BROWSABLE");
               i.addCategory("android.intent.category.DEFAULT");
               i.setData(Uri.parse("wdgz://wdfull/card?card_id=828"));

               Log.d("shixiangyu",i.toUri(Intent.URI_INTENT_SCHEME));

结果:


image.png

如果在demo中的Intent对象不能传递给目标APP的Activity或其他组件,则其Uri形式放在网页端也不可能打开APP的,这样写个demo容易排查错误。

另外,对于传递的参数的设置,可以直接跟在uri_path里面,然后直接通过intent.setData()的形式进行传递,上面的就是此种形式,也可以通过intent.putExtra()的方式进行传递,如

               Intent i = new Intent();
               i.setAction("android.intent.action.VIEW");
               i.addCategory("android.intent.category.BROWSABLE");
               i.addCategory("android.intent.category.DEFAULT");
               i.setData(Uri.parse("wdgz://wdfull/card"));
               i.putExtra("card_id","828");
               Log.d("shixiangyu",i.toUri(Intent.URI_INTENT_SCHEME));

我们来看一下此时构造的intent长相如何:


image.png

S.card_id跟的就是intent对象的putExtra()方法中的数据。采取这种方式的话,从intent中获取相关信息就有通过intent,getStringExtra()方法了。

APP端中的Androidmanifest.xml的声明写法同2.1节中的APP端写法完全一样。

然后服务端的代码便可换成:

<a href="intent://wdfull/card?cart_id=828#Intent;scheme=wdgz;category=android.intent.category.DEFAULT;category=android.intent.category.BROWSABLE;end">
打开豌豆公主App
</a>

接着,我们在被打开的MyActivity中打印intent.toUri()信息:

image.png

不要惊呼,没有看错,android系统自动把intent://替换成了wdgz://,另外在后面添加了 component 的相关信息。

问题来了,为何不能用scheme://host#intent;参数;end的形式来构造传给APP的intent数据,然后直接给网页端呢?

如对于:

<a href="wdgz://wdfull/card?cart_id=828#Intent;scheme=wdgz;category=android.intent.category.DEFAULT;category=android.intent.category.BROWSABLE;end">打开豌豆公主App</a>

是的,就是因为Android系统会自动为Custom URI scheme而非Intent-based URI添加默认的#intent等信息。

四. 风险评估

常见的用法是在APP获取到来自网页的数据后,重新生成一个intent,然后发送给别的组件使用这些数据。比如使用Webview相关的Activity来加载一个来自网页的url,如果此url来自url scheme中的参数,如:wdgz://wdfull/html?load_url=http://m.wamdougongzhu.cn

如果在APP中,没有检查获取到的load_url的值,攻击者可以构造钓鱼网站,诱导用户点击加载,就可以盗取用户信息。

在Webview加载load_url时,结合APP的自身业务采用白名单机制过滤网页端传过来的数据,黑名单容易被绕过。

上一篇下一篇

猜你喜欢

热点阅读