Index
HTML 注入漏洞
描述
HTML 注入是一种安全漏洞,当移动应用程序中用户操纵的输入可用于将任意 HTML 代码插入易受攻击的 webview 时,就会发生这种漏洞。此漏洞可被用来发起各种攻击,例如窃取用户的会话令牌或 CSRF 令牌,然后将其用于进一步的恶意活动。此外,它允许攻击者修改显示给受害者的内容,使他们能够插入恶意代码或用自己的消息破坏页面。
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
}
}
建议
为了降低与 HTML 注入漏洞相关的风险,请考虑以下建议:
-
上下文输出编码: 根据其上下文对用户生成的内容进行编码。不同的上下文(如 HTML 属性、JavaScript 代码或 CSS 样式)需要特定的编码技术来防止 HTML 注入攻击。根据上下文使用适当的编码函数或库。
-
清理用户输入: 通过在将其作为 HTML 代码的一部分呈现之前剥离任何特殊 HTML 字符,对用户提供的数据执行适当的输入验证和清理。
-
如果不需要,请禁用 Javascript: 在移动 webview 的上下文中,禁用 Javascript 可以帮助显着降低任何潜在的 HTML 注入的影响。
-
使用无逻辑模板引擎: 像
Mustache这样的模板引擎可以通过正确处理用户输入来帮助防止 HTML 注入。
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: "<")
.replacingOccurrences(of: ">", with: ">")
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
}
}
链接
标准
- 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