Aller au contenu

Index

Vulnérabilité d'injection HTML

Description

L'injection HTML est une vulnérabilité de sécurité qui se produit lorsque l'entrée manipulée par l'utilisateur dans une application mobile peut être utilisée pour insérer du code HTML arbitraire dans une webview vulnérable. Cette vulnérabilité peut être exploitée pour lancer diverses attaques, telles que le vol de jetons de session d'un utilisateur ou de jetons CSRF, qui peuvent ensuite être utilisés pour d'autres activités malveillantes. De plus, elle permet aux attaquants de modifier le contenu affiché aux victimes, leur donnant ainsi la possibilité d'insérer du code malveillant ou de défigurer la page avec leur propre message.

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'HTML Injection Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: WebViewScreen(),
    );
  }
}

class WebViewScreen extends StatefulWidget {
  @override
  _WebViewScreenState createState() => _WebViewScreenState();
}

class _WebViewScreenState extends State<WebViewScreen> {
  late WebViewController _webViewController;
  String? htmlInput;

  @override
  void initState() {
    super.initState();
    getHtmlInputFromIntent();
  }

  void getHtmlInputFromIntent() {
    // Retrieve the intent extras
    Map<String, dynamic>? extras = ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>?;

    // Extract the user input from the intent extras
    htmlInput = extras?['htmlInput'];
  }

  void _injectHtml() async {
    if (htmlInput != null) {
      await _webViewController.loadUrl(Uri.dataFromString(htmlInput!, mimeType: 'text/html').toString());
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('HTML Injection Demo'),
      ),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: _injectHtml,
            child: Text('Inject HTML'),
          ),
          Expanded(
            child: WebView(
              initialUrl: 'about:blank',
              onWebViewCreated: (WebViewController controller) {
                _webViewController = controller;
              },
            ),
          ),
        ],
      ),
    );
  }
}
import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate {

    var webView: WKWebView!
    var htmlInput: String?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Retrieve the user input from the intent extras
        if let extras = self.navigationController?.navigationBar.accessibilityUserInputLabels {
            htmlInput = extras["htmlInput"] as? String
        }

        // Create and configure the web view
        webView = WKWebView(frame: view.bounds)
        webView.navigationDelegate = self
        view.addSubview(webView)

        // Load the web page
        let htmlString = "<html><body><h1>\(htmlInput ?? "")</h1></body></html>"
        webView.loadHTMLString(htmlString, baseURL: nil)
    }
}
import android.annotation.SuppressLint
import android.os.Bundle
import android.webkit.WebSettings
import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    private lateinit var webView: WebView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        webView = findViewById(R.id.webView)

        val name = intent.getStringExtra("name")

        val html = "<html><body><h1>Hello, $name!</h1></body></html>"
        webView.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null)

        val webSettings: WebSettings = webView.settings
        webSettings.javaScriptEnabled = false
    }
}

Recommandation

Pour atténuer les risques associés aux vulnérabilités d'injection HTML, prenez en compte les recommandations suivantes :

  • Encodage contextuel des sorties : Encodez le contenu généré par l'utilisateur en fonction de son contexte. Différents contextes, tels que les attributs HTML, le code JavaScript ou les styles CSS, nécessitent des techniques d'encodage spécifiques pour prévenir les attaques par injection HTML. Utilisez des fonctions ou des bibliothèques d'encodage appropriées en fonction du contexte.

  • Assainir l'entrée de l'utilisateur : Effectuez une validation et un assainissement appropriés des données fournies par l'utilisateur en supprimant tous les caractères HTML spéciaux avant de les restituer en tant que partie du code HTML.

  • Désactiver Javascript si non nécessaire : dans le contexte des webviews mobiles, la désactivation de Javascript peut contribuer à réduire considérablement l'impact de toute injection HTML potentielle.

  • Utiliser des moteurs de modèles sans logique (Logic-less Templating Engines) : Les moteurs de modèles comme Mustache peuvent aider à prévenir l'injection HTML en gérant correctement l'entrée de l'utilisateur.

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:sanitize_html/sanitize_html.dart' show sanitizeHtml;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'HTML Injection Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: WebViewScreen(),
    );
  }
}

class WebViewScreen extends StatefulWidget {
  @override
  _WebViewScreenState createState() => _WebViewScreenState();
}

class _WebViewScreenState extends State<WebViewScreen> {
  late WebViewController _webViewController;
  String? htmlInput;

  @override
  void initState() {
    super.initState();
    getHtmlInputFromIntent();
  }

  void getHtmlInputFromIntent() {
    // Retrieve the intent extras
    Map<String, dynamic>? extras =
        ModalRoute.of(context)?.settings.arguments as Map<String, dynamic>?;

    // Extract the user input from the intent extras
    htmlInput = extras?['htmlInput'];
  }

  void _injectHtml() async {
    if (htmlInput != null) {
      final sanitizedHtml = sanitizeHtml(htmlInput);
      await _webViewController.loadUrl(
        Uri.dataFromString(sanitizedHtml, mimeType: 'text/html', encoding: Encoding.getByName('utf-8'))!.toString(),
      );
    }
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('HTML Injection Demo'),
      ),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: _injectHtml,
            child: Text('Inject HTML'),
          ),
          Expanded(
            child: WebView(
              initialUrl: 'about:blank',
              onWebViewCreated: (WebViewController controller) {
                _webViewController = controller;
              },
            ),
          ),
        ],
      ),
    );
  }
}
import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate {

        private var webView: WKWebView!

        override func viewDidLoad() {
                super.viewDidLoad()

                webView = WKWebView(frame: view.bounds)
                webView.navigationDelegate = self
                view.addSubview(webView)

                let name = "John Doe"
                let plainText = "Hello, \(name)!"
                let sanitizedText = sanitizeHTML(plainText)
                let html = "<html><body><h1>\(sanitizedText)</h1></body></html>"
                webView.loadHTMLString(html, baseURL: nil)
        }

        private func sanitizeHTML(_ html: String) -> String {
                // Replace any '<' and '>' characters with HTML entities
                let sanitized = html.replacingOccurrences(of: "<", with: "&lt;")
                                                        .replacingOccurrences(of: ">", with: "&gt;")
                return sanitized
        }
}
import android.annotation.SuppressLint
import android.os.Bundle
import android.webkit.WebSettings
import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    private lateinit var webView: WebView

    PolicyFactory policy = new HtmlPolicyBuilder()
        .allowElements("a")
        .allowUrlProtocols("https")
        .allowAttributes("href").onElements("a")
        .requireRelNofollowOnLinks()
        .build();

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        webView = findViewById(R.id.webView)

        val name = intent.getStringExtra("name")
        val sanitizedName = policy.sanitize(name)   

        val html = "<html><body><h1>Hello, $sanitizedName!</h1></body></html>"
        webView.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null)

        val webSettings: WebSettings = webView.settings
        webSettings.javaScriptEnabled = false
    }

}

Liens

Normes

  • OWASP_MASVS_L1:
    • MSTG_PLATFORM_5
    • MSTG_PLATFORM_7
    • MSTG_PLATFORM_2
  • OWASP_MASVS_L2:
    • MSTG_PLATFORM_5
    • MSTG_PLATFORM_7
    • MSTG_PLATFORM_2
  • PCI_STANDARDS:
    • REQ_6_2
    • REQ_6_3
    • REQ_6_4
    • REQ_11_3
  • OWASP_MASVS_v2_1:
    • MASVS_CODE_4
    • MASVS_PLATFORM_2
    • MASVS_PLATFORM_3
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_3_4
    • CC_4_1
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5
  • HIPAA_CONTROLS:
    • SECURITY212
    • SECURITY213
    • SECURITY255