Files
codeql/java/ql/test/experimental/query-tests/security/CWE-200/InsecureWebResourceResponse.java

243 lines
9.9 KiB
Java

package com.example.app;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.Locale;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.webkit.MimeTypeMap;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import androidx.webkit.WebViewAssetLoader;
import androidx.webkit.WebViewAssetLoader.AssetsPathHandler;
import android.webkit.WebViewClient;
import android.webkit.WebResourceResponse;
/** Insecure activity with its subclassed webviewclient implementation. */
public class InsecureWebResourceResponse extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(-1);
String inputUrl = getIntent().getStringExtra("inputUrl");
getBadResponse1(inputUrl);
getBadResponse2(inputUrl);
getBadResponse3(inputUrl);
getGoodResponse4(inputUrl);
getGoodResponse5(inputUrl);
getBadResponse6(inputUrl);
getBadResponse7(inputUrl);
getGoodResponse8(inputUrl);
}
public static String getMimeTypeFromPath(String path) {
String extension = path;
int lastDot = extension.lastIndexOf('.');
if (lastDot != -1) {
extension = extension.substring(lastDot + 1);
}
extension = extension.toLowerCase(Locale.getDefault());
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
// BAD: Return file of input path in annonyous WebViewClient without validation
private void getBadResponse1(String url) {
WebView wv = (WebView) findViewById(-1);
wv.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
try {
Uri uri = Uri.parse(url);
FileInputStream inputStream = new FileInputStream(uri.getPath());
String mimeType = getMimeTypeFromPath(uri.getPath());
return new WebResourceResponse(mimeType, "UTF-8", inputStream);
} catch (IOException ie) {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}
});
wv.loadUrl(url);
}
// BAD: Return file of input path in annonyous WebViewClient with insufficient validation
// A malicious input such as https://any.domain/local_cache/..%2Fshared_prefs/auth.xml can bypass the validation
private void getBadResponse2(String url) {
WebView wv = (WebView) findViewById(-1);
wv.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
try {
Uri uri = Uri.parse(url);
if (uri.getPath().startsWith("/local_cache/")) {
File cacheFile = new File(getCacheDir(), uri.getLastPathSegment());
FileInputStream inputStream = new FileInputStream(cacheFile);
String mimeType = getMimeTypeFromPath(uri.getPath());
return new WebResourceResponse(mimeType, "UTF-8", inputStream);
} else {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
} catch (IOException ie) {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}
});
wv.loadUrl(url);
}
// BAD: Return file of input path in annonyous WebViewClient with insufficient validation
// A malicious input such as https://any.domain/files/..%2Fshared_prefs/auth.xml can bypass the validation
private void getBadResponse3(String url) {
WebView wv = (WebView) findViewById(-1);
wv.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
try {
Uri uri = Uri.parse(url);
String path = uri.getPath().substring(1);
if (path.startsWith("files/")) {
FileInputStream inputStream = new FileInputStream(path.substring("files/".length()));
String mimeType = getMimeTypeFromPath(uri.getPath());
return new WebResourceResponse(mimeType, "UTF-8", inputStream);
} else {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
} catch (IOException ie) {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}
});
wv.loadUrl(url);
}
// GOOD: Return file of input path in annonyous WebViewClient with sufficient validation
private void getGoodResponse4(String url) {
WebView wv = (WebView) findViewById(-1);
wv.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
try {
Uri uri = Uri.parse(url);
if (uri.getPath().startsWith("/local_cache/") && !uri.getPath().contains("..")) {
File cacheFile = new File(getCacheDir(), uri.getLastPathSegment());
FileInputStream inputStream = new FileInputStream(cacheFile);
String mimeType = getMimeTypeFromPath(uri.getPath());
return new WebResourceResponse(mimeType, "UTF-8", inputStream);
} else {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
} catch (IOException ie) {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}
});
wv.loadUrl(url);
}
// GOOD: Return file of input path in annonyous WebViewClient with sufficient validation
private void getGoodResponse5(String url) {
WebView wv = (WebView) findViewById(-1);
wv.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
try {
Uri uri = Uri.parse(url);
String path = uri.getPath().substring(1);
if (path.startsWith("files/") && !path.contains("..")) {
FileInputStream inputStream = new FileInputStream(path.substring("files/".length()));
String mimeType = getMimeTypeFromPath(uri.getPath());
return new WebResourceResponse(mimeType, "UTF-8", inputStream);
} else {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
} catch (IOException ie) {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}
});
wv.loadUrl(url);
}
// BAD: Return file of input path in standalone WebViewClient without validation
private void getBadResponse6(String url) {
WebView wv = (WebView) findViewById(-1);
wv.setWebViewClient(new VulnerableWebViewClient());
wv.loadUrl(url);
}
// BAD: Return file of input path in annonyous WebViewClient with insufficient validation using WebResourceRequest object
private void getBadResponse7(String url) {
WebView wv = (WebView) findViewById(-1);
wv.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
try {
Uri uri = request.getUrl();
if (uri.getPath().startsWith("/local_cache/")) {
File cacheFile = new File(getCacheDir(), uri.getLastPathSegment());
FileInputStream inputStream = new FileInputStream(cacheFile);
String mimeType = getMimeTypeFromPath(uri.getPath());
return new WebResourceResponse(mimeType, "UTF-8", inputStream);
} else {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
} catch (IOException ie) {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}
});
wv.loadUrl(url);
}
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
.addPathHandler("/assets/", new AssetsPathHandler(this))
.build();
// GOOD: Return file of input path in annonyous WebViewClient with WebViewAssetLoader
private void getGoodResponse8(String url) {
WebView wv = (WebView) findViewById(-1);
wv.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return assetLoader.shouldInterceptRequest(request.getUrl());
}
});
wv.loadUrl(url);
}
}
class VulnerableWebViewClient extends WebViewClient {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
try {
Uri uri = Uri.parse(url);
FileInputStream inputStream = new FileInputStream(uri.getPath());
String mimeType = InsecureWebResourceResponse.getMimeTypeFromPath(uri.getPath());
return new WebResourceResponse(mimeType, "UTF-8", inputStream);
} catch (IOException ie) {
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}
}