WebView: 안전하지 않은 URI 로드
컬렉션을 사용해 정리하기
내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.
OWASP 카테고리: MASVS-CODE: 코드 품질
개요
안전하지 않은 URI 로드는 Android 애플리케이션이 WebView에 로드하기 전에 URI의 유효성을 올바르게 평가하지 못하는 경우 발생합니다.
이러한 유형의 취약점이 발생하는 근본 원인은 URI가 여러 부분으로 구성되며 그중 최소한 스키마와 호스트(권한 부분)는 URI를 WebView에 로드하거나 애플리케이션에서 내부적으로 사용하기 전에 확인해야 한다는 것입니다(예: 허용 목록에 추가).
가장 흔한 실수는 다음과 같습니다.
- 호스트는 확인하고 스키마는 확인하지 않아 공격자가 인증된 호스트로
http://
, content://
또는 javascript://
와 같은 스키마를 사용할 수 있습니다.
- 특히 URI가 문자열로 수신되는 경우 URI를 올바르게 파싱하지 못합니다.
- 스키마는 확인하고 호스트는 확인하지 않습니다(호스트 검증이 충분하지 않음).
마지막 사례의 경우 이러한 문제는 일반적으로 애플리케이션이 기본 도메인의 임의 하위 도메인을 허용해야 할 때 발생합니다. 따라서 호스트 이름이 올바르게 추출되었더라도 앱은 java.lang.String
클래스의 startsWith
, endsWith,
또는 contains
와 같은 메서드를 사용하여, 추출된 문자열 섹션에서 기본 도메인이 있는지 확인합니다. 이러한 메서드를 잘못 사용하면 잘못된 결과가 나올 수 있으며 애플리케이션이 잠재적으로 악의적인 호스트를 부적절하게 신뢰하게 될 수 있습니다.
영향
호스트가 사용되는 컨텍스트에 따라 영향은 다를 수 있습니다. WebView에서 악성 URI(필터링/허용 목록을 우회한 URI)를 로드하면 계정 탈취(예: 피싱 사용), 코드 실행(예: 악성 JavaScript 로드) 또는 기기 손상(하이퍼링크를 통해 전송된 악용 코드)이 발생할 수 있습니다.
완화 조치
문자열 URI를 처리할 때 문자열을 URI로 파싱하고 스키마와 호스트를 모두 검증하는 것이 중요합니다.
Kotlin
fun isUriTrusted(incomingUri: String, trustedHostName: String): Boolean {
try {
val uri = Uri.parse(incomingUri)
return uri.scheme == "https" && uri.host == trustedHostName
} catch (e: NullPointerException) {
throw NullPointerException("incomingUri is null or not well-formed")
}
}
Java
public static boolean isUriTrusted(String incomingUri, String trustedHostName)
throws NullPointerException {
try {
Uri uri = Uri.parse(incomingUri);
return uri.getScheme().equals("https") &&
uri.getHost().equals(trustedHostName);
} catch (NullPointerException e) {
throw new NullPointerException(
"incomingUri is null or not well-formed");
}
}
호스트 유효성 검사의 경우 해당 URI 부분을 격리한 후에는 호스트를 신뢰할 수 있는지 정확하게 식별하기 위해 부분이 아닌 전체를 확인하는 것이 중요합니다. startsWith
또는 endsWith
와 같은 메서드를 사용해야 하는 경우 올바른 문법을 사용하고 필요한 문자나 기호를 간과하지 않는 것이 중요합니다. 예를 들어 endsWith
는 정확한 일치를 위해 '.
' 점 문자가 도메인 이름 앞에 필요합니다. 이러한 문자를 무시하면 일치 항목이 부정확해지고 보안이 침해될 수 있습니다. 하위 도메인은 무한 중첩될 수 있으므로 정규 표현식 일치는 호스트 이름을 검증하는 데 권장되는 전략이 아닙니다.
도움을 주신 분들: Microsoft Threat Intelligence의 Dimitrios Valsamaras 및 Michael Peck
리소스
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2024-02-16(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2024-02-16(UTC)"],[],[],null,["# Webviews – Unsafe URI Loading\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-CODE: Code Quality](https://mas.owasp.org/MASVS/10-MASVS-CODE)\n\n\nOverview\n--------\n\nAn unsafe URI Loading occurs when an Android application fails to correctly\nevaluate the validity of a URI before loading it into a WebView.\n\nThe underlying reason behind this type of vulnerability is that a\n[URI consists of multiple parts](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/net/URI.html), of which, at a minimum, the scheme and the\nhost (of the authority part) must be verified (e.g. allowlisted) before the URI\ngets loaded to a WebView or is used internally by the application.\n\nThe most common mistakes include:\n\n- Checking the host but not the scheme, allowing an attacker to use schemes like `http://`, `content://` or `javascript://` with an authenticated host.\n- Failing to parse the URI correctly, especially in cases where the URI is received as a string.\n- Validating the scheme but not the host (insufficient host validation).\n\nRegarding the last case, this usually occurs when the application needs to allow\narbitrary subdomains of a primary domain. So, even if the hostname has been\nextracted correctly, the app uses methods such as `startsWith`, `endsWith,` or\n`contains` of the `java.lang.String` class to validate the presence of a primary\ndomain in the extracted string section. Used incorrectly, these methods may lead\nto faulty results and force the application to improperly trust a potentially\nmalicious host.\n\nImpact\n------\n\nDepending on the context in which the host is used, the impact can vary. In\ncases where loading a malicious URI (i.e., one that bypassed\nfiltering/allowlist) in a WebView could potentially lead to account takeover\n(e.g. using phishing), code execution (e.g., loading malicious JavaScript), or\ndevice compromise (exploit code delivered using hyperlink).\n\nMitigations\n-----------\n\nWhen handling string URIs, it is important to parse the string as a URI and\nvalidate both the scheme and the host: \n\n### Kotlin\n\n fun isUriTrusted(incomingUri: String, trustedHostName: String): Boolean {\n try {\n val uri = Uri.parse(incomingUri)\n return uri.scheme == \"https\" && uri.host == trustedHostName\n } catch (e: NullPointerException) {\n throw NullPointerException(\"incomingUri is null or not well-formed\")\n }\n }\n\n### Java\n\n public static boolean isUriTrusted(String incomingUri, String trustedHostName)\n throws NullPointerException {\n try {\n Uri uri = Uri.parse(incomingUri);\n return uri.getScheme().equals(\"https\") &&\n uri.getHost().equals(trustedHostName);\n } catch (NullPointerException e) {\n throw new NullPointerException(\n \"incomingUri is null or not well-formed\");\n }\n }\n\nFor host validation, after isolating the corresponding URI part, it is important\nto validate it entirely (rather than partially) to accurately identify whether\nthe host is trusted or not. When using methods like `startsWith` or `endsWith`\ncan't be avoided, it is important to use the correct syntax and not overlook\nnecessary characters or symbols (for example, `endsWith` requires the \"`.`\" dot\ncharacter before the domain name for an accurate match). Neglecting these\ncharacters may lead to inaccurate matches and compromise security. Since\nsubdomains can be infinitely nested, regular expression matching is not a\nrecommended strategy for validating hostnames.\n\nContributors: Dimitrios Valsamaras and Michael Peck of Microsoft Threat\nIntelligence\n\nResources\n---------\n\n- [getHost() documentation](/reference/java/net/URI#getHost())\n- [getScheme() documentation](/reference/java/net/URI#getScheme())"]]