首页 > 其他分享 >修复HTTP动词篡改导致的认证旁路问题的方法

修复HTTP动词篡改导致的认证旁路问题的方法

时间:2023-12-31 18:11:21浏览次数:56  
标签:HTTP 请求 Tomcat 旁路 jsp 篡改 method out

本文于2016年4月完成,发布在个人博客网站上。 考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来。


诡异的问题

分析AppScan扫描报告的时候,发现报告里提示“HTTP动词篡改导致的认证旁路”,一个名字很长,很怪异的问题。咨询度娘没有获取到必要的信息,于是只好按照AppScan报告里给出的重现步骤,实地操作来看看。

AppScan给出的复现步骤很简单,如下:

  1. 使用burpsuite拦截浏览器发出的HTTP请求,如下为样例:

     GET /index.jsp HTTP/1.1
     Host: 127.0.0.1:8080
     Cache-Control: max-age=0
     Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
     Upgrade-Insecure-Requests: 1
     User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
     Accept-Encoding: gzip, deflate, sdch
     Accept-Language: zh-CN,zh;q=0.8
     Connection: close
    
  2. 修改HTTP方法,比如把GET修改为BOGUS,然后点击Forward,把请求转发给Web服务器。

     BOGUS /index.jsp HTTP/1.1
     Host: 127.0.0.1:8080
     Cache-Control: max-age=0
     Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
     Upgrade-Insecure-Requests: 1
     User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36
     Accept-Encoding: gzip, deflate, sdch
     Accept-Language: zh-CN,zh;q=0.8
     Connection: close
    
  3. 令人大跌眼镜的事情发生了,Web服务器居然返回了HTTP 200,同时正确的返回了页面;

顿时让人有点小郁闷。按照产品线要求,当前所在项目使用的是平台部门基于Apache Tomcat 7.0.x源码做过加固的版本,按理说不该存在类似的安全问题。

对照Tomcat加固要求,重新检查了$CATALINA_BASE/conf/web.xml,确认其中包含了如下配置,这说明已经屏蔽了不安全的HTTP方法,应该是没有问题才对。

<security-constraint>
    <web-resource-collection>
        <http-method>HEAD</http-method>
        <http-method>PUT</http-method>
        <http-method>DELETE</http-method>
        <http-method>OPTIONS</http-method>
        <http-method>TRACE</http-method>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name></role-name>
    </auth-constraint>
</security-constraint>

那么为什么AppScan扫描报告中出现了前述问题,Jackie一时有些想不明白。

项目的技术特点

当前所在项目使用了Spring+Struts2+iBatis,从技术组合上可以说非常传统,但在技术应用上存在很大不同,比如:

  • 浏览器请求页面时,使用通用Action将请求重定向至对应的jsp页面;
  • 页面上使用jQuery提供的ajax对象来加载呈现需要的数据;
  • 为了实现项目国际化的需求,要求所有对jsp的请求都需要经过通用Action的转发;
  • 页面代码使用Struts2的s标签来提取国际化信息;

这样的应用方式其实有不得以的苦衷,项目刚成立的时候,组内全是新人,对Struts2仅有名义上的理解,没有人在项目中实际运用中使用Struts2,另外项目进度压的很紧,没时间给大家去了解和学习;而使用ajax来实现页面与Web服务之间通信,实现和使用都简单,于是一直沿用至今。

Struts2的配置

Struts2在web.xml中的配置如下:

<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

简化后的struts.xml配置文件,内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />
    <constant name="struts.action.extension" value="jsp,action"/>
    <constant name="struts.ui.theme" value="java"></constant>
    <constant name="struts.objectFactory" value="spring" />
    <constant name="struts.i18n.encoding" value="UTF-8" />
    <package name="default" namespace="/" extends="struts-default">

        <interceptors>
            <interceptor-stack name="myStack">  
                <interceptor-ref name="basicStack"></interceptor-ref>  
            </interceptor-stack> 
        </interceptors>  
  
        <default-interceptor-ref name="myStack" /> 
        
        <global-results>
            <result name="error">/error.jsp</result>
        </global-results>

        <global-exception-mappings>
            <exception-mapping exception="java.lang.Exception" result="error"/>
        </global-exception-mappings>

        <action name="*" class="MainAction">
            <result name="success">{1}.jsp</result>
        </action>
    </package>
</struts>

通用Action类,简化后的MainAction代码如下

import com.opensymphony.xwork2.ActionSupport;

public class MainAction extends ActionSupport {
	private static final long serialVersionUID = 928135783255954591L;
	@Override
	public String execute() throws Exception {
		return ActionSupport.SUCCESS;
	}
}

从配置上讲,中规中矩,并没有什么特别的地方。

分析过程

访问jsp页面的流程

按照前述配置,当用户在浏览器地址栏里输入后缀为.jsp的url,敲击回车后,发生的事件如下:

  1. 由于在struts.xml文件中有如下配置,用户请求先被Struts2拦截;

     <constant name="struts.action.extension" value="jsp,action"/>
    
  2. 由于在struts.xml中有如下配置,请求会被转发给MainAction来处理;

     <action name="*" class="MainAction">
         <result name="success">{1}.jsp</result>
     </action>
    
  3. 由于MainAction类的execute方法只返回了"success",于是请求又被重定向回了对应的jsp页面;

     @Override
     public String execute() throws Exception {
     	return ActionSupport.SUCCESS;
     }
    
  4. 这时,对jsp页面的访问就由Tomcat接管了;

与9.0.x版本的Tomcat做对比

按照上面的分析,在第4步,如果Tomcat遇到了异常的请求方法,应该拒绝响应才是,不应当返回HTTP 200和页面。那么会不会是Tomcat实现存在问题?

平台发布加固后的Tomcat版本时并没有附带源码,于是从官网获取Tomcat发布的9.0.x版本做对比验证。执行前述的复现步骤,Tomcat 9.0.x版本给浏览器返回了如下响应:

HTTP Status 405 - JSPs only permit GET POST or HEAD
type Status report
message JSPs only permit GET POST or HEAD
description The specified HTTP method is not allowed for the requested resource.

检查9.0.x版本Tomcat生成的servlet代码,发现在_jspService中增加了对HTTP方法有效性的校验,只允许jsp编译生成的servlet响应GET、POST或HEAD方法,如下。

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
      throws java.io.IOException, javax.servlet.ServletException {

    final java.lang.String _jspx_method = request.getMethod();
    if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
      return;
    }

生成上述代码的实现位于org.apache.jasper.compiler.Generator类中,如下所示

// Method check
if (!pageInfo.isErrorPage()) {
    out.printil("final java.lang.String _jspx_method = request.getMethod();");
    out.printin("if (!\"GET\".equals(_jspx_method) && !\"POST\".equals(_jspx_method) && !\"HEAD\".equals(_jspx_method) && ");
    out.println("!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {");
    out.pushIndent();
    out.printin("response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, ");
    out.println("\"" + Localizer.getMessage("jsp.error.servlet.invalid.method") + "\");");
    out.printil("return;");
    out.popIndent();
    out.printil("}");
    out.println();
}

分析结论

这说明高版本的Tomcat已经意识到前述问题,并做了修复。

但此时还有一事不明,当请求HTTP请求中的方法不正确时,7.0.x版本的Tomcat依然可以正常返回页面信息。由于手上没有平台加固过的Tomcat的源码,这事情只好不了了之。

解决之道

显而易见,最直接的解决方法是更换Tomcat的版本,直接使用官网上发布的9.0.x版本。但官网发布的Tomcat没有经过安全加固,在项目中使用时需要自行做加固,难度不低,工作量不小。

所以不能换版本,得另想办法。

当前的诉求很简单,只允许Web服务器响应GET和POST请求,如果用户发起了其它请求,则清理会话、并跳转至错误页面。聪明的朋友一定想到了,使用J2EE标准中提供的Filter即可满足。

参考资料

关于HTTP方法

其它

标签:HTTP,请求,Tomcat,旁路,jsp,篡改,method,out
From: https://www.cnblogs.com/jackieathome/p/17936492.html

相关文章

  • Web服务器启用HTTPS的配置方法
    本文于2016年3月完成,发布在个人博客网站上。考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来。nginx的配置方法可以参考JerryQu的本博客Nginx配置之完整篇。Tomcat的配置方法以Java语言实现的Connector为例,介绍配置方法。创建证书Windows......
  • httpclient
    java-httpclient1.maven<!--主要的jar--><dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version></dependency><dependency> <g......
  • HTTP协议安全头部的笔记
    本文于2016年3月完成,发布在个人博客网站上。考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来。近日项目组对当前开发、维护的Web系统做了AppScan扫描,扫描的结果惨不忍睹,问题很多。报告中报到“缺乏HTTP安全头部”。之前对HTTP协议的安全头部了解不......
  • HttpOnly的笔记
    HttpOnly是什么简单的说:HttpOnly是Cookie的属性;Web服务器通过为Cookie设置这个属性,告诉浏览器应当避免页面端的脚本访问对应Cookie的值,保证被Cookie承载的敏感信息不被恶意读取;Web服务器可以保存一些用户的敏感数据到Cookie中,实现比如SSO的功能;当然是否安全,光靠Web服务器设......
  • HTTP协议安全头部X-Content-Type-Options引入的问题
    本文于2016年4月完成,发布在个人博客网站上。考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来。前段时间测试MM反馈了一个问题,在富文本编辑器里上传的图片无法正常呈现。因为Jackie在本机的环境上没有观察类似的现象,而恰好那天测试环境的某个重要配......
  • https初识
    1.服务器环境,两台服务器做前端代理,两台服务器做后端真实服务器。这里都是nginx代理服务器后端服务器172.16.5.50172.16.5.52172.16.5.51172.16.5.532、 后端两台服务器修改nginx配置文件:cd/etc/nginx/conf.dvimwww_hello80.conf###server{li......
  • HTTP类型接口之请求&响应详解
    一、接口介绍接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换,传递和控制管理过程,以及系统间的相互逻辑依赖关系等。接口常见的分类有:二、HTTP类型接口通过Fiddler抓......
  • Java+SpringBoot+Maven+TestNG+httpclient+Allure+Jenkins实现接口自动化
    一、方案需求目标:测试左移,测试介入研发过程,验证单接口正常及异常逻辑选用工具:Java、SpringBoot、Maven、TestNG、httpclient、Allure、Jenkins方案:创建测试接口测试工程,参照研发设计文档和设计思路,编写正常及异常用例,直接调用服务端接口,覆盖接口逻辑和验证异常处理,提升接口健壮......
  • grpc是基于http/2协议的高性能的rpc框架
    师傅领进门,修行在个人,跟着官方脚手架demo了grpc后,之后就需要扩展前后知识边界,下面总结grpc的前世今生和最佳实践。https://www.cnblogs.com/JulianHuang/p/14441952.htmlgrpc是基于http/2协议的高性能的rpc框架为什么已经有http?还需要grpc?八股文都说grpc是基于http2的rpc框......
  • HTTPS 通信中的对称加密和非对称加密
    HTTPS是一种基于SSL/TLS协议的加密传输协议,它采用了对称加密和非对称加密技术来保证通信安全。在HTTPS通信中,对称加密和非对称加密各有不同的作用。对称加密对称加密是指加密和解密所使用的密钥是相同的加密方式。在对称加密算法中,只有持有密钥的人才能够解密被加密的信息。对称加......