跳转至

Template Injection

模板注入

描述

模板注入是一种漏洞,允许攻击者将恶意代码注入到模板渲染的文本中,然后由服务器执行。这可能导致一系列攻击,包括数据窃取、权限提升和远程代码执行。模板注入攻击特别危险,因为它们可能难以检测并且可以为攻击者提供危险的功能。

在这里,代码存在漏洞,因为我们使用用户输入(userName)的直接连接来创建模板字符串,从而允许用户控制模板的结构。如果用户提供包含Mustache模板标签的字符串,这可能导致模板注入。

import 'dart:io';
import 'package:mustache_template/mustache_template.dart';

Future main() async {
  var server = await HttpServer.bind(
    InternetAddress.loopbackIPv4,
    8080,
  );
  print('Listening on localhost:${server.port}');

  await for (HttpRequest request in server) {
    final userName = request.uri.queryParameters['name'] ?? 'guest';
    // Vulnerable to template injection due to template string concatenation
    final template = 'Hello, ${userName}';
    final output = Template(template, lenient: true, htmlEscapeValues: false)
        .renderString({});
    request.response
      ..write(output)
      ..close();
  }
}
import com.github.mustachejava.DefaultMustacheFactory
import com.github.mustachejava.Mustache
import io.ktor.application.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.http.Parameters

fun main() {
    embeddedServer(Netty, port = 8080) {
        routing {
            get("/") {
                val parameters: Parameters = call.request.queryParameters
                val userName = parameters["name"] ?: "guest"

                // Vulnerable to template injection due to template string concatenation
                val mf = DefaultMustacheFactory()
                val mustache: Mustache = mf.compile("template", "Hello, $userName")

                val writer = StringWriter()
                mustache.execute(writer, emptyMap<String, Any>())
                writer.flush()

                call.respondText(writer.toString())
            }
        }
    }.start(wait = true)
}

建议

为了缓解此漏洞,重要的是确保所有用户输入在传递给服务器端模板引擎之前都经过适当的清理和验证。

模板引擎通常会有一个render方法,该方法接受一个将安全嵌入到文本中的上下文。

import 'dart:io';
import 'package:mustache_template/mustache_template.dart';

Future main() async {
  var server = await HttpServer.bind(
    InternetAddress.loopbackIPv4,
    8080,
  );
  print('Listening on localhost:${server.port}');

  await for (HttpRequest request in server) {
    final userName = request.uri.queryParameters['name'] ?? 'guest';
    // Vulnerable to template injection due to template string concatenation
    final template = 'Hello, {{ username }}';
    final output = Template(template, lenient: true, htmlEscapeValues: false)
        .renderString({'username': username});
    request.response
      ..write(output)
      ..close();
  }
}
import com.github.mustachejava.DefaultMustacheFactory
import com.github.mustachejava.Mustache
import io.ktor.application.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.http.Parameters
import java.io.StringWriter

fun main() {
    embeddedServer(Netty, port = 8080) {
        routing {
            get("/") {
                val parameters: Parameters = call.request.queryParameters
                val userName = parameters["name"] ?: "guest"

                // Use a predefined template and pass untrusted data as values
                val mf = DefaultMustacheFactory()
                val mustache: Mustache = mf.compile("template", "Hello, {{name}}")

                val writer = StringWriter()
                mustache.execute(writer, mapOf("name" to userName))
                writer.flush()

                call.respondText(writer.toString())
            }
        }
    }.start(wait = true)
}

链接

标准

  • OWASP_MASVS_L1:
    • MSTG_PLATFORM_2
  • OWASP_MASVS_L2:
    • MSTG_PLATFORM_2
  • PCI_STANDARDS:
    • REQ_2_2
    • REQ_6_2
    • REQ_6_3
    • REQ_11_3
  • OWASP_MASVS_v2_1:
    • MASVS_CODE_4
  • 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