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

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/installedapp/InstalledAppProviderImpl.java

Issue 2802603002: getInstalledRelatedApps: Introduce random delay to stop timing attacks. (Closed)
Patch Set: Rebase. Created 3 years, 8 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
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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.content.browser.installedapp; 5 package org.chromium.content.browser.installedapp;
6 6
7 import android.content.Context; 7 import android.content.Context;
8 import android.content.pm.ApplicationInfo; 8 import android.content.pm.ApplicationInfo;
9 import android.content.pm.PackageManager; 9 import android.content.pm.PackageManager;
10 import android.content.pm.PackageManager.NameNotFoundException; 10 import android.content.pm.PackageManager.NameNotFoundException;
11 import android.content.res.Resources; 11 import android.content.res.Resources;
12 import android.os.AsyncTask; 12 import android.os.AsyncTask;
13 import android.util.Pair;
13 14
14 import org.json.JSONArray; 15 import org.json.JSONArray;
15 import org.json.JSONException; 16 import org.json.JSONException;
16 import org.json.JSONObject; 17 import org.json.JSONObject;
17 18
18 import org.chromium.base.Log; 19 import org.chromium.base.Log;
20 import org.chromium.base.ThreadUtils;
19 import org.chromium.base.VisibleForTesting; 21 import org.chromium.base.VisibleForTesting;
20 import org.chromium.installedapp.mojom.InstalledAppProvider; 22 import org.chromium.installedapp.mojom.InstalledAppProvider;
21 import org.chromium.installedapp.mojom.RelatedApplication; 23 import org.chromium.installedapp.mojom.RelatedApplication;
22 import org.chromium.mojo.system.MojoException; 24 import org.chromium.mojo.system.MojoException;
23 25
24 import java.net.URI; 26 import java.net.URI;
25 import java.net.URISyntaxException; 27 import java.net.URISyntaxException;
26 import java.util.ArrayList; 28 import java.util.ArrayList;
27 29
28 /** 30 /**
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 final RelatedApplication[] relatedApps, final FilterInstalledAppsRes ponse callback) { 74 final RelatedApplication[] relatedApps, final FilterInstalledAppsRes ponse callback) {
73 if (mFrameUrlDelegate.isIncognito()) { 75 if (mFrameUrlDelegate.isIncognito()) {
74 callback.call(new RelatedApplication[0]); 76 callback.call(new RelatedApplication[0]);
75 return; 77 return;
76 } 78 }
77 79
78 final URI frameUrl = mFrameUrlDelegate.getUrl(); 80 final URI frameUrl = mFrameUrlDelegate.getUrl();
79 81
80 // Use an AsyncTask to execute the installed/related checks on a backgro und thread (so as 82 // Use an AsyncTask to execute the installed/related checks on a backgro und thread (so as
81 // not to block the UI thread). 83 // not to block the UI thread).
82 new AsyncTask<Void, Void, RelatedApplication[]>() { 84 new AsyncTask<Void, Void, Pair<RelatedApplication[], Integer>>() {
83 @Override 85 @Override
84 protected RelatedApplication[] doInBackground(Void... unused) { 86 protected Pair<RelatedApplication[], Integer> doInBackground(Void... unused) {
85 return filterInstalledAppsOnBackgroundThread(relatedApps, frameU rl); 87 return filterInstalledAppsOnBackgroundThread(relatedApps, frameU rl);
86 } 88 }
87 89
88 @Override 90 @Override
89 protected void onPostExecute(RelatedApplication[] installedApps) { 91 protected void onPostExecute(Pair<RelatedApplication[], Integer> res ult) {
90 callback.call(installedApps); 92 final RelatedApplication[] installedApps = result.first;
93 int delayMillis = result.second;
94 // Before calling the callback, delay for the amount of time tha t has been
95 // calculated in |delayMillis|.
96 delayThenRun(new Runnable() {
97 @Override
98 public void run() {
99 callback.call(installedApps);
100 }
101 }, delayMillis);
91 } 102 }
92 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 103 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
93 } 104 }
94 105
95 @Override 106 @Override
96 public void close() {} 107 public void close() {}
97 108
98 @Override 109 @Override
99 public void onConnectionError(MojoException e) {} 110 public void onConnectionError(MojoException e) {}
100 111
101 /** 112 /**
102 * Filters a list of apps, returning those that are both installed and match the origin. 113 * Filters a list of apps, returning those that are both installed and match the origin.
103 * 114 *
104 * This method is expected to be called on a background thread (not the main UI thread). 115 * This method is expected to be called on a background thread (not the main UI thread).
105 * 116 *
106 * @param relatedApps A list of applications to be filtered. 117 * @param relatedApps A list of applications to be filtered.
107 * @param frameUrl The URL of the frame this operation was called from. 118 * @param frameUrl The URL of the frame this operation was called from.
108 * @return A subsequence of applications that meet the criteria. 119 * @return Pair of: A subsequence of applications that meet the criteria, an d, the total amount
120 * of time in ms that should be delayed before returning to the user , to mask the
121 * installed state of the requested apps.
109 */ 122 */
110 private RelatedApplication[] filterInstalledAppsOnBackgroundThread( 123 private Pair<RelatedApplication[], Integer> filterInstalledAppsOnBackgroundT hread(
111 RelatedApplication[] relatedApps, URI frameUrl) { 124 RelatedApplication[] relatedApps, URI frameUrl) {
112 ArrayList<RelatedApplication> installedApps = new ArrayList<RelatedAppli cation>(); 125 ArrayList<RelatedApplication> installedApps = new ArrayList<RelatedAppli cation>();
126 int delayMillis = 0;
113 PackageManager pm = mContext.getPackageManager(); 127 PackageManager pm = mContext.getPackageManager();
114 for (RelatedApplication app : relatedApps) { 128 for (RelatedApplication app : relatedApps) {
115 // If the package is of type "play", it is installed, and the origin is associated with 129 // If the package is of type "play", it is installed, and the origin is associated with
116 // package, add the package to the list of valid packages. 130 // package, add the package to the list of valid packages.
117 // NOTE: For security, it must not be possible to distinguish (from the response) 131 // NOTE: For security, it must not be possible to distinguish (from the response)
118 // between the app not being installed and the origin not being asso ciated with the app 132 // between the app not being installed and the origin not being asso ciated with the app
119 // (otherwise, arbitrary websites would be able to test whether un-a ssociated apps are 133 // (otherwise, arbitrary websites would be able to test whether un-a ssociated apps are
120 // installed on the user's device). 134 // installed on the user's device).
121 if (app.platform.equals(RELATED_APP_PLATFORM_ANDROID) && app.id != n ull 135 if (app.platform.equals(RELATED_APP_PLATFORM_ANDROID) && app.id != n ull) {
122 && isAppInstalledAndAssociatedWithOrigin(app.id, frameUrl, p m)) { 136 delayMillis += calculateDelayForPackageMs(app.id);
123 installedApps.add(app); 137 if (isAppInstalledAndAssociatedWithOrigin(app.id, frameUrl, pm)) {
138 installedApps.add(app);
139 }
124 } 140 }
125 } 141 }
126 142
127 RelatedApplication[] installedAppsArray = new RelatedApplication[install edApps.size()]; 143 RelatedApplication[] installedAppsArray = new RelatedApplication[install edApps.size()];
128 installedApps.toArray(installedAppsArray); 144 installedApps.toArray(installedAppsArray);
129 return installedAppsArray; 145 return Pair.create(installedAppsArray, delayMillis);
130 } 146 }
131 147
132 /** 148 /**
149 * Determines how long to artifically delay for, for a particular package na me.
150 */
151 private int calculateDelayForPackageMs(String packageName) {
152 // Important timing-attack prevention measure: delay by a pseudo-random amount of time, to
153 // add significant noise to the time taken to check whether this app is installed and
154 // related. Otherwise, it would be possible to tell whether a non-relate d app is installed,
155 // based on the time this operation takes.
156 //
157 // Generate a 16-bit hash based on a unique device ID + the package name .
158 short hash = PackageHash.hashForPackage(packageName);
159
160 // The time delay is the low 10 bits of the hash in 100ths of a ms (betw een 0 and 10ms).
161 int delayHundredthsOfMs = hash & 0x3ff;
162 return delayHundredthsOfMs / 100;
163 }
164
165 /**
133 * Determines whether a particular app is installed and matches the origin. 166 * Determines whether a particular app is installed and matches the origin.
134 * 167 *
135 * @param packageName Name of the Android package to check if installed. Ret urns false if the 168 * @param packageName Name of the Android package to check if installed. Ret urns false if the
136 * app is not installed. 169 * app is not installed.
137 * @param frameUrl Returns false if the Android package does not declare ass ociation with the 170 * @param frameUrl Returns false if the Android package does not declare ass ociation with the
138 * origin of this URL. Can be null. 171 * origin of this URL. Can be null.
139 */ 172 */
140 private static boolean isAppInstalledAndAssociatedWithOrigin( 173 private boolean isAppInstalledAndAssociatedWithOrigin(
141 String packageName, URI frameUrl, PackageManager pm) { 174 String packageName, URI frameUrl, PackageManager pm) {
142 if (frameUrl == null) return false; 175 if (frameUrl == null) return false;
143 176
144 // Early-exit if the Android app is not installed. 177 // Early-exit if the Android app is not installed.
145 JSONArray statements; 178 JSONArray statements;
146 try { 179 try {
147 statements = getAssetStatements(packageName, pm); 180 statements = getAssetStatements(packageName, pm);
148 } catch (NameNotFoundException e) { 181 } catch (NameNotFoundException e) {
149 return false; 182 return false;
150 } 183 }
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 } 301 }
269 302
270 private static boolean statementTargetMatches(URI frameUrl, URI assetUrl) { 303 private static boolean statementTargetMatches(URI frameUrl, URI assetUrl) {
271 if (assetUrl.getScheme() == null || assetUrl.getAuthority() == null) { 304 if (assetUrl.getScheme() == null || assetUrl.getAuthority() == null) {
272 return false; 305 return false;
273 } 306 }
274 307
275 return assetUrl.getScheme().equals(frameUrl.getScheme()) 308 return assetUrl.getScheme().equals(frameUrl.getScheme())
276 && assetUrl.getAuthority().equals(frameUrl.getAuthority()); 309 && assetUrl.getAuthority().equals(frameUrl.getAuthority());
277 } 310 }
311
312 /**
313 * Runs a Runnable task after a given delay.
314 *
315 * Protected and non-static for testing.
316 *
317 * @param r The Runnable that will be executed.
318 * @param delayMillis The delay (in ms) until the Runnable will be executed.
319 * @return True if the Runnable was successfully placed into the message que ue.
320 */
321 protected void delayThenRun(Runnable r, long delayMillis) {
322 ThreadUtils.postOnUiThreadDelayed(r, delayMillis);
323 }
278 } 324 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698