CodeQL 文档

Android WebView 中不安全的资源获取

ID: java/android/unsafe-android-webview-fetch
Kind: path-problem
Security severity: 6.1
Severity: warning
Precision: medium
Tags:
   - security
   - external/cwe/cwe-749
   - external/cwe/cwe-079
Query suites:
   - java-security-extended.qls
   - java-security-and-quality.qls

点击查看 CodeQL 代码库中的查询

允许加载外部控制的 URL 并且启用了 JavaScript 接口的 Android WebViews 可能容易受到跨站脚本和敏感资源泄露攻击。

如果 WebViewWebSettings 对象已调用 setAllowFileAccessFromFileURLs(true)setAllowUniversalAccessFromFileURLs(true),则不得加载任何不受信任的网页内容。

启用这些设置将允许在 file:// 上下文中加载的恶意脚本启动跨站脚本攻击,访问任意本地文件,包括 WebView Cookie、会话令牌、私人应用程序数据,甚至用于任意网站的凭据。

此查询检测以下两种情况

  1. 启用 JavaScript 并允许远程输入时,WebView 引入的漏洞。

  2. 当也启用“允许跨源资源访问”时的更严重漏洞。此设置在 API 级别 30(Android 11)中已弃用,但大多数设备仍然受到影响,特别是因为某些 Android 手机更新缓慢或根本不再更新。

建议

仅在启用 JavaScript 时,才允许显示 WebView 中的受信任网页内容。在 WebSettings 中禁止跨源资源访问,以减少攻击面。

示例

以下示例展示了“错误”和“正确”两种配置。在“错误”配置中,启用了 JavaScript 和允许访问设置,并且从外部控制的输入加载 URL。在“正确”配置中,禁用了 JavaScript,或者仅允许加载可信的 Web 内容。

public class UnsafeAndroidAccess extends Activity {
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.webview);

		// BAD: Have both JavaScript and cross-origin resource access enabled in webview while
		// taking remote user inputs
		{
			WebView wv = (WebView) findViewById(R.id.my_webview);
			WebSettings webSettings = wv.getSettings();

			webSettings.setJavaScriptEnabled(true);
			webSettings.setAllowUniversalAccessFromFileURLs(true);

			wv.setWebViewClient(new WebViewClient() {
				@Override
				public boolean shouldOverrideUrlLoading(WebView view, String url) {
					view.loadUrl(url);
					return true;
				}
			});

			String thisUrl = getIntent().getExtras().getString("url"); // dangerous remote input from  the intent's Bundle of extras
			wv.loadUrl(thisUrl);
		}

		// BAD: Have both JavaScript and cross-origin resource access enabled in webview while
		// taking remote user inputs
		{
			WebView wv = (WebView) findViewById(R.id.my_webview);
			WebSettings webSettings = wv.getSettings();

			webSettings.setJavaScriptEnabled(true);
			webSettings.setAllowUniversalAccessFromFileURLs(true);

			wv.setWebViewClient(new WebViewClient() {
				@Override
				public boolean shouldOverrideUrlLoading(WebView view, String url) {
					view.loadUrl(url);
					return true;
				}
			});

			String thisUrl = getIntent().getStringExtra("url"); //dangerous remote input from intent extra
			wv.loadUrl(thisUrl);
		}

		// GOOD: Have JavaScript and cross-origin resource access disabled by default on modern Android (Jellybean+) while taking remote user inputs
		{
			WebView wv = (WebView) findViewById(-1);
			WebSettings webSettings = wv.getSettings();

			wv.setWebViewClient(new WebViewClient() {
				@Override
				public boolean shouldOverrideUrlLoading(WebView view, String url) {
					view.loadUrl(url);
					return true;
				}
			});

			String thisUrl = getIntent().getExtras().getString("url"); // remote input
			wv.loadUrl(thisUrl);
		}

		// GOOD: Have JavaScript enabled in webview but remote user input is not allowed
		{
			WebView wv = (WebView) findViewById(-1);
			WebSettings webSettings = wv.getSettings();

			webSettings.setJavaScriptEnabled(true);

			wv.setWebViewClient(new WebViewClient() {
				@Override
				public boolean shouldOverrideUrlLoading(WebView view, String url) {
					view.loadUrl(url);
					return true;
				}
			});

			wv.loadUrl("https://www.mycorp.com");
		}
	}
}

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私