Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java

Issue 2010403002: Upstream: Add WebAPK security check in WebappLauncherActivity. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: dfalcantara@'s comments. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.webapps; 5 package org.chromium.chrome.browser.webapps;
6 6
7 import android.app.Activity; 7 import android.app.Activity;
8 import android.content.Intent; 8 import android.content.Intent;
9 import android.net.Uri; 9 import android.net.Uri;
10 import android.os.Build; 10 import android.os.Build;
11 import android.os.Bundle; 11 import android.os.Bundle;
12 import android.util.Base64; 12 import android.util.Base64;
13 13
14 import org.chromium.base.ApiCompatibilityUtils; 14 import org.chromium.base.ApiCompatibilityUtils;
15 import org.chromium.base.ApplicationStatus; 15 import org.chromium.base.ApplicationStatus;
16 import org.chromium.base.CommandLine; 16 import org.chromium.base.CommandLine;
17 import org.chromium.base.ContextUtils; 17 import org.chromium.base.ContextUtils;
18 import org.chromium.base.Log; 18 import org.chromium.base.Log;
19 import org.chromium.chrome.browser.ChromeSwitches; 19 import org.chromium.chrome.browser.ChromeSwitches;
20 import org.chromium.chrome.browser.IntentHandler; 20 import org.chromium.chrome.browser.IntentHandler;
21 import org.chromium.chrome.browser.ShortcutHelper; 21 import org.chromium.chrome.browser.ShortcutHelper;
22 import org.chromium.chrome.browser.document.ChromeLauncherActivity; 22 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
23 import org.chromium.chrome.browser.metrics.LaunchMetrics; 23 import org.chromium.chrome.browser.metrics.LaunchMetrics;
24 import org.chromium.chrome.browser.tab.Tab; 24 import org.chromium.chrome.browser.tab.Tab;
25 import org.chromium.chrome.browser.util.IntentUtils; 25 import org.chromium.chrome.browser.util.IntentUtils;
26 import org.chromium.webapk.lib.common.WebApkConstants; 26 import org.chromium.webapk.lib.client.WebApkValidator;
27 27
28 import java.lang.ref.WeakReference; 28 import java.lang.ref.WeakReference;
29 29
30 /** 30 /**
31 * Launches web apps. This was separated from the ChromeLauncherActivity becaus e the 31 * Launches web apps. This was separated from the ChromeLauncherActivity becaus e the
32 * ChromeLauncherActivity is not allowed to be excluded from Android's Recents: crbug.com/517426. 32 * ChromeLauncherActivity is not allowed to be excluded from Android's Recents: crbug.com/517426.
33 */ 33 */
34 public class WebappLauncherActivity extends Activity { 34 public class WebappLauncherActivity extends Activity {
35 /** 35 /**
36 * Action fired when an Intent is trying to launch a WebappActivity. 36 * Action fired when an Intent is trying to launch a WebappActivity.
(...skipping 14 matching lines...) Expand all
51 } 51 }
52 52
53 super.onCreate(savedInstanceState); 53 super.onCreate(savedInstanceState);
54 Intent intent = getIntent(); 54 Intent intent = getIntent();
55 String webappId = webappInfo.id(); 55 String webappId = webappInfo.id();
56 String webappUrl = webappInfo.uri().toString(); 56 String webappUrl = webappInfo.uri().toString();
57 String webApkPackageName = webappInfo.webApkPackageName(); 57 String webApkPackageName = webappInfo.webApkPackageName();
58 int webappSource = webappInfo.source(); 58 int webappSource = webappInfo.source();
59 59
60 if (webappId != null && webappUrl != null) { 60 if (webappId != null && webappUrl != null) {
61 String webappMacString = IntentUtils.safeGetStringExtra(
62 intent, ShortcutHelper.EXTRA_MAC);
63 byte[] webappMac =
64 webappMacString == null ? null : Base64.decode(webappMacStri ng, Base64.DEFAULT);
65
66 Intent launchIntent = null; 61 Intent launchIntent = null;
67 62
68 // Permit the launch to a standalone web app frame if the intent was sent by Chrome, or 63 // Permit the launch to a standalone web app frame if any of the fol lowing are true:
69 // if the MAC is present and valid for the URL to be opened. 64 // - the request was for a WebAPK that is valid;
70 boolean isTrusted = IntentHandler.wasIntentSenderChrome(intent, 65 // - the MAC is present and valid for the homescreen shortcut to be opened;
71 ContextUtils.getApplicationContext()); 66 // - the intent was sent by Chrome.
72 boolean isUrlValid = (webappMac != null 67 boolean isValidWebApk = isValidWebApk(webApkPackageName, webappUrl);
73 && WebappAuthenticator.isUrlValid(this, webappUrl, webappMac ));
74 boolean isValidWebApk = isValidWebApk(webApkPackageName);
75 if (webApkPackageName != null && !isValidWebApk) {
76 isUrlValid = false;
77 }
78 68
79 if (isTrusted || isUrlValid) { 69 if (isValidWebApk
70 || isValidMacForUrl(webappUrl, IntentUtils.safeGetStringExtr a(
71 intent, ShortcutHelper.EXTRA_MAC))
72 || wasIntentFromChrome(intent)) {
80 LaunchMetrics.recordHomeScreenLaunchIntoStandaloneActivity(webap pUrl, webappSource); 73 LaunchMetrics.recordHomeScreenLaunchIntoStandaloneActivity(webap pUrl, webappSource);
81 launchIntent = createWebappLaunchIntent(webappInfo, isValidWebAp k); 74 launchIntent = createWebappLaunchIntent(webappInfo, isValidWebAp k);
82 } else { 75 } else {
83 Log.e(TAG, "Shortcut (%s) opened in Chrome.", webappUrl); 76 Log.e(TAG, "Shortcut (%s) opened in Chrome.", webappUrl);
84 77
85 // The shortcut data doesn't match the current encoding. Change the intent action 78 // The shortcut data doesn't match the current encoding. Change the intent action
86 // launch the URL with a VIEW Intent in the regular browser. 79 // launch the URL with a VIEW Intent in the regular browser.
87 launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webappUr l)); 80 launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webappUr l));
88 launchIntent.setClassName(getPackageName(), ChromeLauncherActivi ty.class.getName()); 81 launchIntent.setClassName(getPackageName(), ChromeLauncherActivi ty.class.getName());
89 launchIntent.putExtra(ShortcutHelper.REUSE_URL_MATCHING_TAB_ELSE _NEW_TAB, true); 82 launchIntent.putExtra(ShortcutHelper.REUSE_URL_MATCHING_TAB_ELSE _NEW_TAB, true);
90 launchIntent.putExtra(ShortcutHelper.EXTRA_SOURCE, webappSource) ; 83 launchIntent.putExtra(ShortcutHelper.EXTRA_SOURCE, webappSource) ;
91 launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 84 launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
92 | ApiCompatibilityUtils.getActivityNewDocumentFlag()); 85 | ApiCompatibilityUtils.getActivityNewDocumentFlag());
93 } 86 }
94 87
95 startActivity(launchIntent); 88 startActivity(launchIntent);
96 } 89 }
97 90
98 ApiCompatibilityUtils.finishAndRemoveTask(this); 91 ApiCompatibilityUtils.finishAndRemoveTask(this);
99 } 92 }
100 93
101 /** 94 /**
95 * Checks whether or not the MAC is present and valid for the web app shortc ut.
96 *
97 * The MAC is used to prevent malicious apps from launching Chrome into a fu ll screen
98 * Activity for phishing attacks (among other reasons).
99 *
100 * @param url The URL for the web app.
101 * @param mac MAC to compare the URL against. See {@link WebappAuthenticato r}.
102 * @return Whether the MAC is valid for the URL.
103 */
104 private boolean isValidMacForUrl(String url, String mac) {
105 return mac != null
106 && WebappAuthenticator.isUrlValid(this, url, Base64.decode(mac, Base64.DEFAULT));
107 }
108
109 private boolean wasIntentFromChrome(Intent intent) {
110 return IntentHandler.wasIntentSenderChrome(intent, ContextUtils.getAppli cationContext());
111 }
112
113 /**
102 * Creates an Intent to launch the web app. 114 * Creates an Intent to launch the web app.
103 * @param info Information about the web app. 115 * @param info Information about the web app.
104 * @param isWebApk If true, launch the app as a WebApkActivity. If false, l aunch the app as 116 * @param isWebApk If true, launch the app as a WebApkActivity. If false, l aunch the app as
105 * a WebappActivity. 117 * a WebappActivity.
106 */ 118 */
107 private Intent createWebappLaunchIntent(WebappInfo info, boolean isWebApk) { 119 private Intent createWebappLaunchIntent(WebappInfo info, boolean isWebApk) {
108 String activityName = isWebApk ? WebApkActivity.class.getName() 120 String activityName = isWebApk ? WebApkActivity.class.getName()
109 : WebappActivity.class.getName(); 121 : WebappActivity.class.getName();
110 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { 122 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
111 // Specifically assign the app to a particular WebappActivity instan ce. 123 // Specifically assign the app to a particular WebappActivity instan ce.
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 Tab tab = webappActivity.getActivityTab(); 162 Tab tab = webappActivity.getActivityTab();
151 tab.getTabWebContentsDelegateAndroid().activateContents(); 163 tab.getTabWebContentsDelegateAndroid().activateContents();
152 return true; 164 return true;
153 } 165 }
154 } 166 }
155 167
156 return false; 168 return false;
157 } 169 }
158 170
159 /** 171 /**
160 * Checks whether the package being targeted is a valid WebAPK. 172 * Checks whether the package being targeted is a valid WebAPK and whether t he url supplied
161 * @param webapkPackageName The package name of the requested WebAPK. 173 * can be fulfilled by that WebAPK.
174 *
175 * @param webApkPackage The package name of the requested WebAPK.
176 * @param url The url to navigate to.
162 * @return true iff all validation criteria are met. 177 * @return true iff all validation criteria are met.
163 */ 178 */
164 private boolean isValidWebApk(String webapkPackageName) { 179 private boolean isValidWebApk(String webApkPackage, String url) {
165 // TODO(hanxi): Adds more validation checks. For example, whether the We bAPK is signed 180 if (!CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_WEBAPK)
166 // by the WebAPK Minting Server. 181 || webApkPackage == null) {
167 return CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_WEBAPK) 182 return false;
168 && webapkPackageName != null 183 }
169 && webapkPackageName.startsWith(WebApkConstants.WEBAPK_PACKAGE_P REFIX); 184 if (!WebApkValidator.isValidWebApk(this, webApkPackage)) {
185 Log.d(TAG, "%s is not valid WebAPK", webApkPackage);
186 return false;
187 }
188 if (!webApkPackage.equals(WebApkValidator.queryWebApkPackage(this, url)) ) {
189 Log.d(TAG, "%s is not within scope of %s WebAPK", url, webApkPackage );
190 return false;
191 }
192 return true;
170 } 193 }
171 } 194 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698