Deprecated UIWebView Usage

ID

swift.deprecated_uiwebview

Severity

info

Resource

Misconfiguration

Language

Swift

Tags

CWE:477, NIST.SP.800-53, OWASP:2021:A06

Description

UIWebView is a deprecated iOS component that was officially deprecated by Apple in iOS 12.0 and removed from SDK documentation. Apple strongly recommends migrating to WKWebView from the WebKit framework, which provides significantly improved security, performance, and modern web standards support.

Using deprecated UIWebView in applications creates several risks:

  • No security updates: UIWebView no longer receives security patches, leaving applications vulnerable to known web-based exploits

  • App Store rejection: Apple may reject or remove applications that use UIWebView

  • Lack of process isolation: UIWebView runs web content in the same process as the application, meaning web content exploits can directly compromise the app

  • Poor JavaScript performance: Uses older JavaScript engine with limited optimization

  • Missing modern web features: Lacks support for modern web APIs and standards

  • No sandboxing: Web content has excessive access to application resources

WKWebView, introduced in iOS 8.0, addresses these issues by:

  • Running web content in a separate process with strong sandboxing

  • Using the modern Nitro JavaScript engine for better performance

  • Providing granular security controls and content filtering

  • Receiving ongoing security updates and improvements

  • Supporting modern web standards and APIs

  • Offering better memory management

Rationale

This detector reports the first occurrence of UIWebView usage in each source file. The detector identifies:

  • Variable declarations with UIWebView type: var webView: UIWebView

  • Property declarations with UIWebView type: @IBOutlet var webView: UIWebView!

  • UIWebView instance creation: UIWebView(frame: …​)

  • Class inheritance from UIWebView: class CustomView: UIWebView

  • Type references to UIWebView: let view: UIWebView?

The detector avoids reporting multiple issues in the same file to prevent noise and allows developers to migrate entire files at once.

The following example demonstrates vulnerable code:

import UIKit

// VULNERABLE: Using deprecated UIWebView
class LegacyWebViewController: UIViewController {
    // FLAW: UIWebView property declaration
    var webView: UIWebView?

    override func viewDidLoad() {
        super.viewDidLoad()
        // FLAW: Creating UIWebView instance
        webView = UIWebView(frame: view.bounds)
        webView?.delegate = self
        view.addSubview(webView!)
    }

    func loadWebpage(_ urlString: String) {
        if let url = URL(string: urlString) {
            let request = URLRequest(url: url)
            // FLAW: Loading content in deprecated UIWebView
            webView?.loadRequest(request)
        }
    }

    func loadHTMLContent(_ html: String) {
        // FLAW: Loading HTML in UIWebView without sandboxing
        webView?.loadHTMLString(html, baseURL: nil)
    }

    func executeJavaScript(_ script: String) {
        // FLAW: JavaScript execution in same process as app
        let result = webView?.stringByEvaluatingJavaScript(from: script)
        print("Script result: \(result ?? "")")
    }
}

Using UIWebView has several problems:

  1. Deprecated API: UIWebView is deprecated and no longer receives security updates from Apple.

  2. Security vulnerabilities: Any security flaws discovered in UIWebView will not be patched, leaving the application vulnerable to XSS, CSRF, and other web-based attacks.

  3. No process isolation: Web content runs in the same process as the application, meaning exploits in web content can directly compromise the app’s memory and data.

  4. App Store compliance: Apple actively discourages UIWebView usage and may reject applications during App Store review.

  5. Limited security controls: UIWebView provides minimal security configuration options compared to WKWebView.

Remediation

The recommended approach is to migrate to WKWebView. Replace all UIWebView usage with WKWebView from the WebKit framework.

You can use WKWebViewConfiguration to configure the web view to avoid security issues, particularly when using external, untrusted content:

import UIKit
import WebKit

// SECURE: Using modern WKWebView
class ModernWebViewController: UIViewController, WKNavigationDelegate {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // SECURE: Create WKWebView with configuration
        let configuration = WKWebViewConfiguration()

        // Enable additional security features
        configuration.preferences.javaScriptCanOpenWindowsAutomatically = false

        // iOS 14+: Control media playback
        if #available(iOS 14.0, *) {
            configuration.defaultWebpagePreferences.allowsContentJavaScript = true
        }

        // Create WKWebView with secure configuration
        webView = WKWebView(frame: view.bounds, configuration: configuration)
        webView.navigationDelegate = self
        webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(webView)
    }

    // SECURE: Load webpage with WKWebView
    func loadWebpage(_ urlString: String) {
        if let url = URL(string: urlString) {
            let request = URLRequest(url: url)
            webView.load(request)
        }
    }

    // SECURE: Load HTML content with WKWebView
    func loadHTMLContent(_ html: String) {
        webView.loadHTMLString(html, baseURL: nil)
    }

    // SECURE: Execute JavaScript with modern API
    func executeJavaScript(_ script: String) {
        webView.evaluateJavaScript(script) { result, error in
            if let error = error {
                print("JavaScript error: \(error)")
                return
            }
            print("Script result: \(result ?? "")")
        }
    }

    // SECURE: WKNavigationDelegate provides better security controls
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
                 decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        // Implement security policies
        guard let url = navigationAction.request.url else {
            decisionHandler(.cancel)
            return
        }

        // Only allow HTTPS connections
        if url.scheme != "https" && url.scheme != "file" {
            print("Blocked non-HTTPS URL: \(url)")
            decisionHandler(.cancel)
            return
        }

        // Implement domain whitelist
        let allowedDomains = ["example.com", "trusted-domain.com"]
        if let host = url.host, allowedDomains.contains(where: { url.host?.hasSuffix($0) ?? false }) {
            decisionHandler(.allow)
        } else {
            print("Blocked untrusted domain: \(url.host ?? "unknown")")
            decisionHandler(.cancel)
        }
    }

    // SECURE: Handle navigation errors
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        print("Navigation failed: \(error.localizedDescription)")
    }

    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!,
                 withError error: Error) {
        print("Provisional navigation failed: \(error.localizedDescription)")
    }
}

Configuration

This detector does not need any configuration.

References