热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SecuringWebViewswithChromeCustomTabs

PlaidempowersinnovatorsinthefintechspacebyprovidingthemwithaccesstofinancialdataviaauniformAPI. Inordertohelpendusersconnecttheirbankingdatatofintechapps,PlaiddevelopedLink,adrop-inmodulethathandlescr

Plaid empowers innovators in the fintech space by providing them with access to financial data via a uniform API.  In order to help end users connect their banking data to fintech apps, Plaid developedLink, a drop-in module that handles credential validation, multi-factor authentication, and error handling for every supported bank.

Android developers previously had to open Link URLs in WebViews .  Every app that wanted to use Link required a lot of developer effort and, without standardization, there were bound to be bugs in some of the implementations. In order to improve the developer experience, we recently released an SDK making the WebView easy to integrate into any app with a few lines of code.

Additionally, WebViews are not completely secure for end users who input sensitive information into the Link flow. In order to make our SDK as secure as possible, we've implemented it using Chrome custom tabs instead of Android WebViews. In this article we explain why we've made that decision and how we've overcome the technical issues we encountered along the way.

Evaluating Our Options

As an SDK, our code runs within other developers’ applications, and, in turn, their application processes.  In order to run the Link web app in a WebView, Javascript has to be enabled. This opens the door for other apps to run malicious code, such as registering callbacks that try to intercept usernames and passwords. Additionally, a malicious app could open another web page that mimics the Link flow in a phishing attempt.

When looking for a solution that is easy to integrate with for developers, intuitive for end users, and secure, we evaluated several options:

  1. building a native link flow : Because native Link flows would also run in another app's process, savvy developers could use reflection to find our input EditTexts and register callbacks in a manner similar to Javascript in a WebView.
  2. building a separate authenticator app : This would provide a native sandboxed experience and would be an ideal experience for end-users; however, many users would not want to download an extra app from the Play Store.  This means we would need a fallback solution for users who refuse to download the app.
  3. opening Link in a separate browser window : This would be a sandboxed, secure solution. Almost all users have a browser installed, but the context switching from an app to a browser would introduce a noticeable delay, especially on low-end devices.
  4. using Chrome Custom Tabs : This is the solution we chose, as it had none of the drawbacks mentioned above.

Our Choice: Chrome Custom Tabs

Chrome custom tabs (CCT) is a part of the Chrome browser that integrates with the Android framework to allow apps to open websites in a lightweight process.  CCT opens faster than a browser and, if preloaded via its warm-up call, is potentially even faster than a WebView. While it still runs Javascript, it is in its own process, which prevents apps from running malicious code. Furthermore, the CCT UI provides an action bar which shows the URL of the page being loaded, along with an SSL verification lock icon for secure pages. This reassures users that the correct page is being shown.

Securing WebViews with Chrome Custom Tabs

While not all users have Chrome installed, the vast majority do. For those who do not, we are using the browser fallback method described above (option 3); other than adding one line of code, we get the fallback for free from CCT.  As noted before, the browser fallback is not the ideal user experience due to its latency, but it does maintain the high level of security that Plaid requires.

As we developed the CCT solution, we ran into and addressed several complications:

  • Getting event data
  • Retrieving the final result
  • Controlling the CCT activity & process

Getting Event Data

When a user navigates between screens in Link, a redirect occurs and data is provided to developers in the URL parameters.

Securing WebViews with Chrome Custom Tabs

This redirect information is valuable for developers, as it helps them understand user behavior.  With CCT running in its own process and not providing a redirect callback, this information would normally be inaccessible, which would make our secure SDK less functional for developers than their custom WebView implementations.

To provide this information from CCT, we instead recorded the redirect events on the server in a Redis datastore.  When the SDK opens Link, it makes a bootstrap call to our servers, which provide a per-user channel ID chosen by us and a secret key.  The SDK then creates an app-scoped worker object, which polls the server using an RX interval stream .  On each polling call we provide the server with the channel ID, secret key, and the last event's UUID (or null) to get the latest events.

Observable.interval(interval, TimeUnit.SECONDS)
  .subscribeOn(Schedulers.computation())
  .observeOn(AndroidSchedulers.mainThread())
  .flatMapSingle(makeNetworkCall())
  .subscribe(
      {
          // Handle messages
      },
      {
          // Handle errors
      })

The Android framework may kill any process, including the app using Plaid's SDK. Since the worker object is tied to the application, this would result in the worker being stopped. If the user continued the flow, (either successfully or unsuccessfully) the SDK would make a final call to the channel and get the remaining events.  Events would only be lost if the user aborted the flow and force killed the app.

Retrieving the Final Result

Similar to passing event data to clients, Link uses the URL to signal that the user has completed the flow. The relevant URL includes necessary data, such as the public key or an error code.

Since we can't access the URL with CCT, we stored the final result in Redis with the same channel ID.  While this means that our polling worker would know when Link has finished, there would be no guarantee that the worker would still be alive.  Even if it were alive, the user may have to wait until the next polling call for the result to be delivered, which could be a long couple of seconds.

To ensure a result is delivered in a timely manner, we use a deep link to reopen the SDK.  The deep link is constructed using the application's app ID, which must be associated with the client secret and whitelisted on the developer dashboard. This, plus the fact that only one app on a device can have the same app ID, ensures no other apps intercept the redirect.  The Link web app then builds an intent URI, which is fired at the end of the Link flow.

intent://redirect/#Intent;scheme=plaid;package=$packageName;end;

Our SDK includes an intent filter to handle the URI, so that the application re-opens and makes a call directly to the channel immediately.


  
 
  
  
 
  

Controlling CCT

CCT lacks interfaces for the app to:

  • listen for when the user closes the activity
  • detect when the user has clicked the “Open in Browser” option
  • force it to close

We have successfully worked around all these shortcomings.

First, to listen for when the user closes the activity, we open CCT using startActivityForResult and pass it a request code.  If the user closes CCT using the X in the upper left corner of the system back button, the onActivityResult callback is triggered with the request code we provided and a result code of Activity.RESULT_CANCELED .  The data intent does not include any information, but we can make a final call to the channel to get the remaining events. We then pass them to the client app and return aLinkCancellation object, signaling that Link was closed intentionally by the user.

Next, the potential concern with detecting when the user has clicked “Open in Browser” is that the user could then go through the entire flow in a separate application, namely the browser.  This is not a problem for us, because the polling and intent systems continue to work in the same manner and we can still get the data needed.

Finally, when the user completes the flow successfully and the result intent is fired, the CCT process would remain open and in the user's task list.  This phantom process would not only be wasteful, but could also be confusing to a user when they press the "recent tasks" system button.  Therefore, we need a way to force CCT to close when the flow is complete.

In order to do this, we used the pattern shown in the OpenId AppAuth for Android library. Instead of handling the result in the activity that opens Link, we place the intent filter on a separate activity.  This second activity handles all the redirects from the web app, which include: successful completions, errors that close the flow, oAuth or App-to-App redirects, and general system errors.  The activity then passes the data back to the opening activity using an intent with the Intent.FLAG_ACTIVITY_SINGLE_TOP and Intent.FLAG_ACTIVITY_CLEAR_TOP flags.  Used together, they clear everything on the stack above the opening activity, including CCT.

val intent = Intent(activity, LinkActivity::class.java)
when (state) {
  is RedirectState.ChromeCustomTabsComplete -> {
    intent.putExtra(LINK_CHROME_CUSTOM_TABS_COMPLETE_REDIRECT, true)
    intent.putExtra(LINK_RESULT_CODE, state.resultCode)
    intent.putExtra(LINK_RESULT, state.result)
  }
  is RedirectState.UserInitiatedChromeCustomTabsViewClose -> {
    intent.putExtra(LINK_CHROME_CUSTOM_TABS_USER_CLOSE_REDIRECT, true)
  }
  is RedirectState.OAuth -> {
    intent.putExtra(LINK_OAUTH_REDIRECT, true)
    intent.putExtra(LINK_OAUTH_STATE_ID, state.oauthStateId)
  }
  is RedirectState.RedirectError ->
    intent.putExtra(LINK_REDIRECT_ERROR, true)
}
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
return intent
Securing WebViews with Chrome Custom Tabs

Final thoughts on CCT

In order to provide a secure, sandboxed experience not available in WebViews or native flows, CCT is a viable solution. It is easy to integrate with for developers and provides a better user experience than opening browser windows thanks to its lightweight nature and speed.

CCT’s sandboxed nature and limited API mean it is not without its downsides.  Listening to URL redirects, getting final results and controlling the CCT process all required us to come up with creative solutions.  These solutions relied on an understanding of Android's built-in features, especially the intent framework.

The benefits for developers and consumers were well worth the required effort and we recommend using CCT in other apps and SDKs for a fast and secure integration. Moreover, you can use the tips provided here to improve the user (and developer) experience.

If you are interested in solving unique problems that will be used by thousands of developers and millions of consumers, visit ourcareers page.


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 我们


推荐阅读
  • 资源:吊炸天!74款APP完整源码!android界面中点击输入框时弹出输入法如果输入框在底部会出现输入法遮挡输入内容的问题解决办法设置activity的windowsoftinpu ... [详细]
  • 本文介绍了在满足特定条件时如何在输入字段中使用默认值的方法和相应的代码。当输入字段填充100或更多的金额时,使用50作为默认值;当输入字段填充有-20或更多(负数)时,使用-10作为默认值。文章还提供了相关的JavaScript和Jquery代码,用于动态地根据条件使用默认值。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 获取时间的函数js代码,js获取时区代码
    本文目录一览:1、js获取服务器时间(动态)2 ... [详细]
  • 作用域链迷惑性代码vara100;functiontest(){console.log(a);}functiontestFun(){vara200;test();}不假思索的想到出 ... [详细]
  • 安卓端开源移动浏览器开源项目
    进入android开发以来,webview用的比较多,后来又看了一些基于webview的浏览器代码,慢慢的将积累的东西做成了一个安卓移动浏 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • 本文介绍了一道网络流题目hdu4888 Redraw Beautiful Drawings的解题思路。题目要求以行和列作为结点建图,并通过最大流算法判断是否有解以及是否唯一。文章详细介绍了建图和算法的过程,并强调在dfs过程中要进行回溯。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 判断编码是否可立即解码的程序及电话号码一致性判断程序
    本文介绍了两个编程题目,一个是判断编码是否可立即解码的程序,另一个是判断电话号码一致性的程序。对于第一个题目,给出一组二进制编码,判断是否存在一个编码是另一个编码的前缀,如果不存在则称为可立即解码的编码。对于第二个题目,给出一些电话号码,判断是否存在一个号码是另一个号码的前缀,如果不存在则说明这些号码是一致的。两个题目的解法类似,都使用了树的数据结构来实现。 ... [详细]
author-avatar
小丁啊小丁
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有