WebView: 안전하지 않은 파일 포함

OWASP 카테고리: MASVS-STORAGE: 저장소

개요

이 문서에서는 유사한 완화 조치를 공유하는 파일 포함과 관련된 여러 문제를 다룹니다. 이러한 문제는 WebView 내 파일 액세스에서 비롯되는 취약점을 중심으로 하며, 파일 액세스를 허용하거나 JavaScript를 사용 설정하는 위험한 WebSettings부터 파일 선택 요청을 만드는 WebKit 메서드에 이르기까지 다양합니다. 이 문서는 file:// 스킴 사용, 로컬 파일에 대한 제한되지 않은 액세스, 교차 사이트 스크립팅으로 인해 발생하는 WebView 내 문제 해결에 관한 안내를 찾고 있다면 유용합니다.

구체적으로 이 문서에서는 다음 주제를 다룹니다.

  • WebSettings는 WebView의 설정 상태를 관리하는 메서드가 포함된 클래스입니다. 이러한 메서드는 나중에 설명할 다양한 공격에 WebView를 열 수 있습니다. 이 문서에서는 파일에 액세스하는 방법과 JavaScript 실행을 허용하는 설정과 관련된 메서드를 살펴봅니다.
  • setAllowFileAccess, setAllowFileAccessFromFileURLs, setAllowUniversalAccessFromFileURLs 메서드는 파일 스키마 URL(file://)을 사용하여 로컬 파일에 대한 액세스 권한을 부여하는 데 사용할 수 있습니다. 하지만 악성 스크립트에서 이를 악용하여 애플리케이션에 액세스할 수 있는 임의의 로컬 파일(예: 자체 /data/ 폴더)에 액세스할 수 있습니다. 이러한 이유로 이러한 메서드는 안전하지 않은 것으로 신고되었으며 API 30에서 WebViewAssetLoader와 같은 더 안전한 대안으로 대체되었습니다.
  • setJavascriptEnabled 메서드를 사용하여 WebView 내에서 JavaScript 실행을 사용 설정할 수 있습니다. 이로 인해 애플리케이션이 파일 기반 XSS에 취약해집니다. 특히 로컬 파일 또는 실행 파일 코드가 포함될 수 있는 신뢰할 수 없는 웹 콘텐츠의 로드를 허용하도록 구성되거나, 외부 소스에서 생성하거나 변경할 수 있는 파일에 대한 액세스를 허용하도록 구성되거나, WebView에서 JavaScript를 실행하도록 허용되는 경우 사용자와 사용자의 데이터가 위험에 노출됩니다.
  • WebChromeClient.onShowFileChooser는 웹 탐색 도구를 제공하는 android.webkit 패키지에 속한 메서드입니다. 이 메서드는 사용자가 WebView 내에서 파일을 선택할 수 있도록 하는 데 사용할 수 있습니다. 그러나 WebView는 선택되는 파일에 제한을 적용하지 않으므로 이 기능이 악용될 수 있습니다.

영향

파일 포함의 영향은 WebView에서 구성된 WebSettings에 따라 달라질 수 있습니다. 파일 권한이 지나치게 광범위하면 공격자가 로컬 파일에 액세스하여 민감한 정보, 개인 식별 정보 (PII) 또는 비공개 앱 데이터를 도용할 수 있습니다. JavaScript 실행을 사용 설정하면 공격자가 WebView 내부 또는 사용자 기기에서 JavaScript를 실행할 수 있습니다. onShowFileChooser 메서드를 사용하여 선택된 파일은 메서드나 WebView에서 파일 소스가 신뢰할 수 있는지 확인할 방법이 없으므로 사용자 보안을 손상시킬 수 있습니다.

위험: file://을 통한 파일 액세스 위험

setAllowFileAccess, setAllowFileAccessFromFileURLs, setAllowUniversalAccessFromFileURLs를 사용 설정하면 file:// 컨텍스트가 있는 악의적인 인텐트와 WebView 요청이 WebView 쿠키 및 앱 비공개 데이터를 비롯한 임의의 로컬 파일에 액세스할 수 있습니다. 또한 onShowFileChooser 메서드를 사용하면 사용자가 신뢰할 수 없는 출처에서 파일을 선택하고 다운로드할 수 있습니다.

이러한 메서드는 모두 애플리케이션 구성에 따라 PII, 로그인 사용자 인증 정보 또는 기타 민감한 정보가 유출될 수 있습니다.

완화 조치

파일 URL 확인

앱에서 file:// URL을 통해 파일에 액세스해야 하는 경우 일반적인 실수를 피하면서 유효한 것으로 알려진 특정 URL만 허용 목록에 추가하는 것이 중요합니다.

WebViewAssetLoader 사용

언급된 메서드 대신 WebViewAssetLoader를 사용하세요. 이 메서드는 file:// 스키마 대신 http(s)//: 스키마를 사용하여 로컬 파일 시스템 애셋에 액세스하며 설명된 공격에 취약하지 않습니다.

Kotlin

val assetLoader: WebViewAssetLoader = Builder()
  .addPathHandler("/assets/", AssetsPathHandler(this))
  .build()

webView.setWebViewClient(object : WebViewClientCompat() {
  @RequiresApi(21)
  override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest): WebResourceResponse {
    return assetLoader.shouldInterceptRequest(request.url)
  }

  @Suppress("deprecation") // for API < 21
  override fun shouldInterceptRequest(view: WebView?, url: String?): WebResourceResponse {
    return assetLoader.shouldInterceptRequest(Uri.parse(url))
  }
})

val webViewSettings: WebSettings = webView.getSettings()
// Setting this off for security. Off by default for SDK versions >= 16.
webViewSettings.allowFileAccessFromFileURLs = false
// Off by default, deprecated for SDK versions >= 30.
webViewSettings.allowUniversalAccessFromFileURLs = false
// Keeping these off is less critical but still a good idea, especially if your app is not
// using file:// or content:// URLs.
webViewSettings.allowFileAccess = false
webViewSettings.allowContentAccess = false

// Assets are hosted under http(s)://appassets.androidplatform.net/assets/... .
// If the application's assets are in the "main/assets" folder this will read the file
// from "main/assets/www/index.html" and load it as if it were hosted on:
// https://appassets.androidplatform.net/assets/www/index.html
webView.loadUrl("https://appassets.androidplatform.net/assets/www/index.html")

자바

final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
         .addPathHandler("/assets/", new AssetsPathHandler(this))
         .build();

webView.setWebViewClient(new WebViewClientCompat() {
    @Override
    @RequiresApi(21)
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        return assetLoader.shouldInterceptRequest(request.getUrl());
    }

    @Override
    @SuppressWarnings("deprecation") // for API < 21
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        return assetLoader.shouldInterceptRequest(Uri.parse(url));
    }
});

WebSettings webViewSettings = webView.getSettings();
// Setting this off for security. Off by default for SDK versions >= 16.
webViewSettings.setAllowFileAccessFromFileURLs(false);
// Off by default, deprecated for SDK versions >= 30.
webViewSettings.setAllowUniversalAccessFromFileURLs(false);
// Keeping these off is less critical but still a good idea, especially if your app is not
// using file:// or content:// URLs.
webViewSettings.setAllowFileAccess(false);
webViewSettings.setAllowContentAccess(false);

// Assets are hosted under http(s)://appassets.androidplatform.net/assets/... .
// If the application's assets are in the "main/assets" folder this will read the file
// from "main/assets/www/index.html" and load it as if it were hosted on:
// https://appassets.androidplatform.net/assets/www/index.html
webview.loadUrl("https://appassets.androidplatform.net/assets/www/index.html");

위험한 WebSettings 메서드 사용 중지

setAllowFileAccess(), setAllowFileAccessFromFileURLs(), setAllowUniversalAccessFromFileURLs() 메서드의 값은 기본적으로 API 수준 29 이하에서는 TRUE로, API 수준 30 이상에서는 FALSE로 설정됩니다.

다른 WebSettings를 구성해야 하는 경우, 특히 API 수준이 29 이하인 앱의 경우 이러한 메서드를 명시적으로 사용 중지하는 것이 가장 좋습니다.


위험: 파일 기반 XSS

setJavacriptEnabled 메서드를 TRUE로 설정하면 JavaScript를 WebView 내에서 실행할 수 있으며, 앞서 설명한 대로 사용 설정된 파일 액세스와 함께 임의의 파일 내에서 코드를 실행하거나 WebView 내에서 열려 있는 악성 웹사이트를 통해 파일 기반 XSS가 가능합니다.

완화 조치

WebView에서 로컬 파일을 로드하지 못하도록 방지

이전 위험과 마찬가지로 setAllowFileAccess(), setAllowFileAccessFromFileURLs(), setAllowUniversalAccessFromFileURLs()FALSE로 설정하면 파일 기반 XSS를 방지할 수 있습니다.

WebView에서 JavaScript 실행 방지

JavaScript가 WebView 내에서 실행되지 않도록 메서드 setJavascriptEnabledFALSE로 설정합니다.

WebView에서 신뢰할 수 없는 콘텐츠를 로드하지 않도록 방지

WebView 내에서 이러한 설정을 사용 설정해야 하는 경우도 있습니다. 이 경우 신뢰할 수 있는 콘텐츠만 로드되도록 하는 것이 중요합니다. JavaScript 실행을 개발자가 제어하는 실행으로 제한하고 임의의 JavaScript를 허용하지 않는 것이 콘텐츠의 신뢰성을 보장하는 좋은 방법 중 하나입니다. 그렇지 않으면 일반 텍스트 트래픽이 로드되지 않도록 하면 위험한 설정이 포함된 WebView에서 적어도 HTTP URL을 로드할 수 없게 됩니다. 이는 매니페스트를 통해 android:usesCleartextTrafficFalse로 설정하거나 HTTP 트래픽을 허용하지 않는 Network Security Config를 설정하여 할 수 있습니다.


리소스