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

本文于2016年4月完成,发布在个人博客网站上。


诡异的问题

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

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

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

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

     BOGUS /index.jsp HTTP/1.1Host: 127.0.0.1:8080Cache-Control: max-age=0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36Accept-Encoding: gzip, deflate, sdchAccept-Language: zh-CN,zh;q=0.8Connection: 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;@Overridepublic 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页面;

     @Overridepublic 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方法详解
  • HTTP六种请求方法
  • HTTP请求方法对照表
  • HTTP协议的几种请求方法
  • HTTP请求的方法

其它

  • burpsuite,强大的渗透测试神器
  • switchysharp,Google Chrome浏览器上目前最好用的代理程序
  • Struts2,Struts2官网
  • Filtering Requests and Responses,关于Filter的介绍材料
  • tomcat on GitHub,托管在GitHub上的官方镜像仓库
  • tomcat 7.0.x SVN,7.0.x版本的官方SVN仓库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/603923.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

物理机与vm文件共享与传输的设置方法

今天跟各位小伙伴&#xff0c;分享一下物理机与vm虚拟机文件共享与传输的设置方法&#xff0c;以供大家参考&#xff01; 一、物理机与虚拟机文件共享设置方法 第一步&#xff1a;先关闭虚拟机&#xff08;客户机&#xff09; 第二步&#xff1a;选择编辑虚拟机设置 第三步&am…

Nacos和Eureka的全面对比

学习目标&#xff1a; 了解Nacos和Eureka的基本概念和特点。理解Nacos和Eureka在服务注册与发现、配置管理、服务路由、负载均衡等方面的区别。掌握Nacos和Eureka的部署和使用方法。比较Nacos和Eureka在性能、可靠性、扩展性等方面的优劣。理解Nacos和Eureka在微服务架构中的应…

leetcode经典【双指针】例题

删除有序数组中的重复项&#xff1a; https://leetcode.cn/problems/remove-duplicates-from-sorted-array/ 解题思路&#xff1a; 首先注意数组是有序的&#xff0c;那么重复的元素一定会相邻。 注: 要求删除重复元素&#xff0c;实际上就是将不重复的元素移到数组的左侧。 考…

【面试高频算法解析】算法练习2 回溯(Backtracking)

前言 本专栏旨在通过分类学习算法&#xff0c;使您能够牢固掌握不同算法的理论要点。通过策略性地练习精选的经典题目&#xff0c;帮助您深度理解每种算法&#xff0c;避免出现刷了很多算法题&#xff0c;还是一知半解的状态 专栏导航 二分查找回溯&#xff08;Backtracking&…

PyQT5安装配置测试打包教程

文章目录 PyQT5安装配置配置环境变量Pycharm配置Qt Designer和PyUIC 测试测试QT Designer设计的界面软件打包 PyQT5 安装 pip3 install PyQt5 pip3 install pyqt5-tools 配置 配置环境变量 添加xxx\Lib\site-packages\pyqt5_tools至环境变量 Pycharm配置Qt Designer和PyU…

深度解读《Java编程思想》:面向对象导论

深度解读《Java编程思想》&#xff1a;面向对象导论 前言: 欢迎来到本篇博客&#xff0c;我们将深入探讨经典之作《Java编程思想》中的面向对象导论。这本由Bruce Eckel所著的书籍深入浅出&#xff0c;为Java编程提供了一系列深刻的思考和实践经验。 1. Java 编程思想简介&a…

【leetcode】力扣算法之旋转图像【难度中等】

题目描述 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 用例 输入&#xff1a; matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&…

1.分组

#include<bits/stdc.h> using namespace std; int main() {unsigned long long a,b,c0,d,s0;cin>>a>>b;for(long long i1;i<a;i){cin>>d;cd;if(c>b){c0;s;}}cout<<s;return 0; }

Mac开发 app名称 如何国际化

在 macOS 应用程序中&#xff0c;您可以通过将应用程序的名称进行国际化来实现多语言支持。这样&#xff0c;应用程序的名称将根据用户的语言设置自动显示对应的翻译。以下是一种实现国际化应用程序名称的方法&#xff1a; 在 Xcode 中&#xff0c;导航到项目的根目录&#xff…

处cp社交类微信小程序前端开源(二)

在上一篇文章介绍如何用SpringBoot整合websocket实现在线聊天&#xff0c;这篇文章介绍如何将uniapp社交类前端源码打包部署微信小程序&#xff0c;和如何上线微信小程序&#xff0c;上线需要的资料&#xff0c;并且介绍我是如何获取用户&#xff0c;如何变现&#xff0c;现在的…

java网络文件地址url的转换为MultipartFile文件流

废话不多说&#xff0c;直接上代码 一、异常捕捉类 public class BusinessException extends RuntimeException {public BusinessException(String msg){super(msg);} }二、转换类 package com.example.answer_system.utils;import org.springframework.mock.web.MockMultipa…

第一个Flask项目(pycharm社区版)

本文章只作为个人笔记. 前言 第一个flask项目,打开debug模式,修改host,修改port. from flask import Flaskapp Flask(__name__)app.route(/) def hello_world():return Hello world!# 1.debug模式 # 1.1 开启debug模式后,只要修改代码后保存,就会重新加载,不用手动重启项目 #…

DockerUI本地如何部署并结合内网穿透实现远程访问管理界面

文章目录 前言1. 安装部署DockerUI2. 安装cpolar内网穿透3. 配置DockerUI公网访问地址4. 公网远程访问DockerUI5. 固定DockerUI公网地址 前言 DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基…

Jmeter相关知识介绍

Jmeter 是Apache 组织开发的基于JAVA 的压力测试工具,用于对软件做压力测试,特别适合于WEB 应用测试(包括压力,接口测试) 今天简单介绍Jemeter的入门相关概念的理解 一、在安装目录下有一个Bin\Jmeter.bat 双击打开 打开之后是一个这样的界面 二、测试计划 1、添加和删…

FPGA时序分析与时序约束(三)——I/O接口约束

为了准确地对设计中的外部时序上下文进行建模&#xff0c;必须提供输入和输出端口的时序信息。因此要进行输入输出延时约束&#xff0c;延迟约束用的是set_input_delay和set_output_delay&#xff0c;分别用于input端和output端&#xff0c;其时钟源可以是时钟输入管脚&#xf…

如何向嵌入式设备中添加tcpdump工具

说明&#xff1a;tcpdump是一个在网络设备调试中一个非常重要的工具&#xff0c;它并不像hexdump等工具集成在busybox里面&#xff0c;也不像其他的软件一样只需要依赖linux标准的库就可以实现&#xff0c;它需要pcap相关的库和加密的相关库。 本文主要是基于realtek 83系列的…

文献阅读:Sparse Low-rank Adaptation of Pre-trained Language Models

文献阅读&#xff1a;Sparse Low-rank Adaptation of Pre-trained Language Models 1. 文章简介2. 具体方法介绍 1. SoRA具体结构2. 阈值选取考察 3. 实验 & 结论 1. 基础实验 1. 实验设置2. 结果分析 2. 细节讨论 1. 稀疏度分析2. rank分析3. 参数位置分析4. 效率考察 4.…

鸿蒙应用开发 给应用添加通知

通知介绍 通知旨在让用户以合适的方式及时获得有用的新消息&#xff0c;帮助用户高效地处理任务。应用可以通过通知接口发送通知消息&#xff0c;用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用&#xff0c;通知主要有以下使用场景&#xff1a; 显示接…

【数据库原理】(12)SQL数据操纵功能

SQL 中,对基本表的数据操纵功能是指对基本表中数据的插入、修改和删除。 一.插入数据 SQL 的数据插人语句INSERT 有两种形式:一种是插入一个元组,另一种是插人子查询结果。 1.插入单个元组 插入单个元组&#xff08;或记录&#xff09;的 INSERT 语句用于向表中添加一行数据…

Qt 的流式布局 FlowLayout

一直苦寻于一个比较智能的布局方式&#xff0c;能够满足软件界面进行resize的时候&#xff0c;对已经存在的布局进行重新布局。能够合理的判断界面的size,在界面放大的时候&#xff0c;显示的item的行数减少&#xff0c;相反&#xff0c;界面缩小的时候&#xff0c;显示的 item…