精华内容
下载资源
问答
  • 一、项目背景 一个Springboot+MyBatis+Redis+MySQL...其中最常见的为TRACE方法可以回显服务器收到的请求,主要用于测试或诊断,恶意攻击者可以利用该方法进行跨站跟踪攻击(即XST攻击),从而进行网站钓鱼、盗取管理员

    一、项目背景

    一个Springboot+MyBatis+Redis+MySQL的辣鸡小项目。奈何再小的项目也需要保证安全,今天提交给测试部门做渗透测试,打回来两个网络安全漏洞,网上有很多“模糊”的修改办法,我们来看看具体怎么修补吧。

    二、漏洞描述

    1.不安全的HTTP方法

    不安全的HTTP方法一般包括:TRACE、PUT、DELETE、COPY 等。其中最常见的为TRACE方法可以回显服务器收到的请求,主要用于测试或诊断,恶意攻击者可以利用该方法进行跨站跟踪攻击(即XST攻击),从而进行网站钓鱼、盗取管理员cookie等。其他说明方式如表所示:

    名称 介绍
    PUT 向指定的目录上传文件
    DELETE 删除指定的资源
    COPY 将特定的资源复制到特定位置
    SEARCH 在一个目录路径中搜索资源
    MOVE 将特定资源移动到特定位置
    PROPFIND 获取与指定资源有关的信息
    OPTION 预检请求,可用于检测服务器允许的http方法,和跨域有关

    我被检测到的是存在OPTION请求,应该是仅允许GET,POST,HEAD就没事。

    2.XSS跨站脚本攻击

    当应用程序的新网页中包含不受信任的、未经恰当验证或转义的数据时,或者使用可以创建 HTML或JavaScript 的浏览器 API 更新现有的网页时,就会出现 XSS 缺陷。XSS 让攻击者能够在受害者的浏览器中执行脚本,并劫持用户会话、破坏网站或将用户重定向到恶意站点。
    已知的跨站脚本攻击漏洞有三种:
    1、存储型跨站脚本攻击:用户输入的文本信息保存到数据库中,并能够在页面展示的功能点,例如用户留言、发送站内消息、个人信息修改等功能点;
    2、反射型跨站脚本攻击:URL参数需要在页面显示的功能点都可能存在反射型跨站脚本攻击,例如站内搜索、查询功能点;
    3、基于DOM跨站脚本攻击:涉及DOM对象的页面程序,包括但不限于:document.URL、document.URLUnencoded、document.location、document.referrer、window.location。
    检测到我的项目应该是不能过滤敏感字符,例如参数中包含script、img、src等等

    三、解决方案

    1.不安全的HTTP方法

    在Springboot项目的启动类中,增加一个方法即可,如下:
    addMethod是屏蔽的方法。

    //拦截不安全的http请求
    	@Bean
    	public ConfigurableServletWebServerFactory configurableServletWebServerFactory() {
    		TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    		factory.addContextCustomizers(context -> {
    			SecurityConstraint securityConstraint = new SecurityConstraint();
    			securityConstraint.setUserConstraint("CONFIDENTIAL");
    			SecurityCollection collection = new SecurityCollection();
    			collection.addPattern("/*");
    			collection.addMethod("PUT");
    			collection.addMethod("DELETE");
    			collection.addMethod("TRACE");
    			collection.addMethod("OPTIONS");
    			collection.addMethod("PATCH");
    			collection.addMethod("COPY");
    			collection.addMethod("SEARCH");
    			collection.addMethod("PROPFIND");
    			securityConstraint.addCollection(collection);
    			context.addConstraint(securityConstraint);
    		});
    		return factory;
    	}
    

    加完后如何测试?
    下载一个postman插件并安装(安装包网上很多,解压后,双击.exe文件就能安装),在method选择你要测试的方法即可。
    在这里插入图片描述

    2.XSS跨站脚本攻击

    先列网上的解决方案,我只是将敏感字符都过滤掉,并非最终办法。
    1.对用户输入的数据进行严格过滤,包括但不限于以下字符及字符串
    Javascript script src img { } ( ) < > = , . ; : " ‘ # ! / * \ `
    2. 根据页面的输出背景环境,对输出进行编码;
    3. 建议使用一个统一的规则库,对用户的所有输入进行安全性验证,验证不通过应直接拒绝用户的请求;
    4. 对于富文本框,使用白名单控制输入,而不是黑名单;
    5. 在Cookie 上设置HTTPOnly 标志,从而禁止客户端脚本访问Cookie。

    建立一个过滤器,把敏感字符都过滤掉,这里先列一下可能存在的敏感字符:

    String badStr = "|script|src|img|onerror|{|}|'|*|$|\"|<|>|javascript|(|)|=|,|:|!|`|.";
    

    在启动类的上加上注解,文件位置:

    @ServletComponentScan("com.xx.filter.safeFilter")
    

    最后建立一个SafeFilter.java

    
    package com.ouma.filter;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.io.IOException;
    import java.util.Enumeration;
    
    import com.alibaba.fastjson.JSONObject;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    
    @Slf4j
    @Component
    @WebFilter(value = "/filter")
    public class safeFilter implements Filter {
    
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            // TODO Auto-generated method stub
        }
        @Override
        public void doFilter(ServletRequest args0, ServletResponse args1,
                             FilterChain chain) throws ServletException, IOException {
    
            HttpServletRequest req=(HttpServletRequest)args0;
    
            HttpServletResponse res=(HttpServletResponse)args1;
    
            //获得所有请求参数名
            Enumeration params = req.getParameterNames();
    
            //获取url的
            String sql = "";
    
            String url=req.getRequestURI().replaceAll("\\\\","/").toLowerCase();
            System.out.println(url);
            String method="";
            String action="";
            while (params.hasMoreElements()) {
                //得到参数名
                String name = params.nextElement().toString();
                System.out.println("name===========================" + name + "--");
                //得到参数对应值
                String[] value = req.getParameterValues(name);
    
                for (int i = 0; i < value.length; i++) {
                    sql = sql + value[i];
                }
                if(name.equalsIgnoreCase("method")){
                    method=value[0];
                }
                if(name.equalsIgnoreCase("action")){
                    action=value[0];
                }
            }
    
            if( ("".equals(method)&&(!"".equals(action)||url.indexOf(".do")>=0))){
                //csrf跨站攻击
                String referer = req.getHeader("referer");
                System.err.println(referer);
                //if (referer == null || !referer.contains(req.getServerName())) {
                if (referer != null && !referer.contains(req.getServerName())) {
                    System.out.println("【管理端refer校验未通过】referer = "+referer+" ,未包含"+req.getServerName());
                    //如果 链接地址来自其他网站,则返回错误页面
                    req.setAttribute("retInfo","疑似跨站伪造请求!");
                    req.getRequestDispatcher("/WEB-INF/jsp/error.jsp").forward(req, res);
                }
            }
    
            //有sql关键字,跳转到error.html
            if (sqlValidate(sql)) {
                System.out.println("sql error");
                req.setAttribute("retInfo","您发送请求中的参数中含有非法字符!");
                req.getRequestDispatcher("/WEB-INF/jsp/error.jsp").forward(req, res);
                //throw new IOException("您发送请求中的参数中含有非法字符!"+sql);
            } else {
                res.setHeader("Set-Cookie", "Secrue; HTTPOnly; ");
                chain.doFilter(args0,args1);
            }
        }
        //效验
        protected static boolean sqlValidate(String str) {
            str = str.toLowerCase();//统一转为小写
    //	        String badStr = "'|select|update|and|or|delete|insert|truncate|char|into"
    //	        		+ "|substr|declare|exec|master|drop|execute|"
    //	        		+ "union|;|--|+|,|like|//|/|%|#|*|$|\"|http|cr|lf|<|>|(|)";//过滤掉的sql关键字,可以手动添加
    //	        String badStr = "'|;|--|+|//|/|%|#|*|$|\"|cr|lf|<|>|(|)";//过滤掉的sql关键字,可以手动添加
    
            //String badStr = "script|src|img|onerror|{|}|'|%|*|$|\"|<|>";//过滤掉的sql关键字,可以手动添加
            String badStr = "";//过滤掉的sql关键字,可以手动添加
    
            badStr = "'|and|exec|execute|insert|select|delete|update|count|drop|*|chr|mid|master|%25|truncate|" +
                    "char|declare|sitename|net user|xp_cmdshell|;|or|-|+|,|like'|and|exec|execute|insert|create|drop|" +
                    "table|from|grant|use|group_concat|column_name|" +
                    "information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|" +
                    "chr|mid|master|truncate|char|declare|or|;|-|--|+|,|like|//|/|#";
            badStr += "|script|src|img|onerror|{|}|'|*|$|\"|<|>|javascript|(|)|=|,|:|!|`|.";
            String[] badStrs = badStr.split("\\|");
            for (int i = 0; i < badStrs.length; i++) {
                if (str.indexOf(badStrs[i]) >= 0) {
                    System.out.println("【管理端特殊字符校验未通过】当前解析串 :"+str+" ,其中未通过校验字符:"+badStrs[i]);
                    return true;
                }
            }
            return false;
        }
    
    }
    

    就大功告成啦。
    不过不能得意太早,这个过滤器可能把业务中的某些参数给过滤掉,加完这个过滤器一定要仔细测试系统功能是否被拦截到了。

    20201224更新,高兴早了,测试部门又通过双重URL编码给我XSS攻击了。

    例如输入:%25%33%63,意为:%0c,再次编码意为:<。这样又把尖括号注入进来了。所有的编码在最后贴一下。
    在上面的过滤器类的方法中增加如下代码:

     str = convertPercent(str);
     str = URLDecoder.decode(str);
    

    调用以下方法convertPercent:这个方法是过滤只输入%的情况

     //判断是否为16进制数
        public static boolean isHex(char c){
            if(((c >= '0') && (c <= '9')) ||
                    ((c >= 'a') && (c <= 'f')) ||
                    ((c >= 'A') && (c <= 'F')))
                return true;
            else
                return false;
        }
        public static String convertPercent(String str){
            StringBuilder sb = new StringBuilder(str);
    
            for(int i = 0; i < sb.length(); i++){
                char c = sb.charAt(i);
                //判断是否为转码符号%
                if(c == '%'){
                    if(((i + 1) < sb.length() -1) && ((i + 2) < sb.length() - 1)){
                        char first = sb.charAt(i + 1);
                        char second = sb.charAt(i + 2);
                        //如只是普通的%则转为%25
                        if(!(isHex(first) && isHex(second)))
                            sb.insert(i+1, "25");
                    }
                    else{//如只是普通的%则转为%25
                        sb.insert(i+1, "25");
                    }
    
                }
            }
    
            return sb.toString();
        }
    

    关于所有的URL编码:https://blog.csdn.net/weixin_34409357/article/details/91565794
    链接: 关于所有的URL编码

    关于如何在前端防止XSS攻击:https://segmentfault.com/a/1190000016551188
    链接: 关于如何在前端防止XSS攻击

    展开全文
  • 但是方便的同时,也需要想一想这是怎么实现的或者能不能加以利用。 经过一番查找,目前发现都是通过获取StackTrace信息实现的,这是Java JDK提供的方法。至于具体内部原理,还需进一步调查。现只对获取方式进行简单...
    在做Android开发的过程中,都会遇到程序崩溃的情况,这时LogCat会显示逐层显示出崩溃所在位置,这对于解决问题来说非常方便。但是方便的同时,也需要想一想这是怎么实现的或者能不能加以利用。
    经过一番查找,目前发现都是通过获取StackTrace信息实现的,这是Java JDK提供的方法。至于具体内部原理,还需进一步调查。现只对获取方式进行简单总结,如有不对的地方还请指正。

    一、利用Thread.currentThread().getStackTrace()
    工具类:
    CodeLine.java

    package com.example.codeline;
    
    
    publicclassCodeLine{
    //通过静态方法调用 Thread.currentThread().getStackTrace() 获取当前函数栈时, 已多加了两层方法调用.
    / /Main.main() -->CodeLine.getLineNumber() --> Thread.getStackStrace()
    
    privatestaticint stackIndex = 2;
    
    publicstatic String getFileName(){
    return Thread.currentThread().getStackTrace()[originStackIndex].getFileName();
    }
    publicstatic String getClassName(){
    return Thread.currentThread().getStackTrace()[originStackIndex].getClassName();
    }
    publicstatic String getMethodName(){
    return Thread.currentThread().getStackTrace()[originStackIndex].getMethodName();
    }
    publicstaticintgetLineNumber(){
    return Thread.currentThread().getStackTrace()[originStackIndex].getLineNumber();
    }
    }

    测试代码:
    Main.java:
    package com.example.codeline;
    
    public class TestClass
    {
    public static void main(String[] args)
    {
    System.out.format("  FileName:\t%s\n", CurrentLineInfo.getFileName());
    System.out.format(" ClassName:\t%s\n",CurrentLineInfo.getClassName());
    System.out.format("MethodName:\t%s\n",CurrentLineInfo.getMethodName());
    System.out.format("LineNumber:\t%s\n\n",CurrentLineInfo.getLineNumber());
    }
    
    }


    测试输出:
          FileName: TestClass.java
      ClassName: com.example.codeline.TestClass
    MethodName: main
      LineNumber: 10



    二、利用new Throwable().getStackTrace() 也能得到同样信息

    测试代码:
    TestClass.java
    
    package com.example.codeline;
    
    public class TestClass
    {
    public static void main(String[] args)
    {
    test();
    }
    
    
    public static void test()
    {
    getCaller();
    }
    
    
    public static void getCaller()
    {
    StackTraceElement stack[] = (new Throwable()).getStackTrace();
    for (int i = 0; i < stack.length; i++)
    {
    StackTraceElement s = stack[i];
    System.out.format("  FileName:%d\t%s\n", i, s.getFileName());
    System.out.format(" ClassName:%d\t%s\n", i, s.getClassName());
    System.out.format("MethodName:%d\t%s\n", i, s.getMethodName());
    System.out.format("LineNumber:%d\t%s\n\n", i, s.getLineNumber());
    }
    }
    }
    测试输出:
      FileName:0TestClass.java
      ClassName:0 com.example.codeline.TestClass
    MethodName:0 getCaller
    LineNumber:0 17
    
    
      FileName:1 TestClass.java
     ClassName:1 com.example.codeline.TestClass
    MethodName:1 test
    LineNumber:1 12
    
    
      FileName:2 TestClass.java
     ClassName:2 com.example.codeline.TestClass
    MethodName:2 main
    LineNumber:2 7




    展开全文
  • 1.33 利用初始化方法判断登录 1.34 巧用回调方法实现数组存储 1.35 定制list标签癿字段列表 1.36 定制list标签癿操作列表 1.37 主键丌是id癿时候list标签如何输出 2.1 .htaccess文件使用手册
  • [Trial version] 5.2 反跟踪技术(Anti-Trace) [Trial version] tELock中的SEH反跟踪代码.htm [Trial version] 利用SEH改变程序流程以达到反跟踪的目的.htm [Trial version] 5.2.3 SMC技术实现 [Trial version...
  • java面试题典 java 面试题 经典

    热门讨论 2010-06-18 13:42:36
    2. 你必须利用备份恢复数据库,但是你没有控制文件,该如何解决问题呢? 30 3. 如何转换init.ora到spfile? 30 4. 解释data block , extent 和 segment的区别(这里建议用英文术语) 30 5. 给出两个检查表结构的方法 31 ...
  • arcgis工具

    2012-10-22 22:37:31
    利用这种方法,选择被另一图层要素覆盖的某个图层上的要素。例如,搜索道路跨越的荒地,得到的结果是道路跨越其边界的所有荒地。 相交(Intersect) 与Are crossed by the outline of类似,但是该方法可以选择与...
  • 可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以到无穷。 41 数组大小 42 1.23 能否声明和传入数组大小一致的局部数组,或者由其他...
  • 可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以到无穷。 41 数组大小 42 1.23 能否声明和传入数组大小一致的局部数组,或者由其他...
  • o 2.14 我总算弄清除函数指针的声明方法了, 但怎样才能初始化呢? * 3. 结构、联合和枚举 o 3.1 声明 struct x1 { ...}; 和 typedef struct { ...} x2; 有什么不同? o 3.2 为什么 struct x { ...}; x ...
  • 3.6.1 利用vi创建和修改文件 46 3.6.2 用head和tail命令移动 47 3.7 文本的提取和排序 48 3.7.1 使用grep匹配模式 48 3.7.2 剪切、粘贴和联结文本 49 3.8 shell脚本 50 3.8.1 shell程序介绍 51 3.8.2...
  • 可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。  数组大小  1.23 能否声明和传入数组大小一致的局部数组,或者由其他参数...
  • 可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 数组大小 1.23 能否声明和传入数组大小一致的局部数组,或者由其他参数...
  • 你必须知道的495个C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 数组大小 1.23 能否声明和传入数组大小一致的局部数组,或者由其他参数...
  • 《你必须知道的495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 12  数组大小 13 1.23 能否声明和传入数组大小一致的局部数组,或者由...
  • 可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 12  数组大小 13 1.23 能否声明和传入数组大小一致的局部数组,或者由...
  • 你必须知道的495个C语言问题(PDF)

    热门讨论 2009-09-15 10:25:47
    1.14 我总算弄清除函数指针的声明方法了, 但怎样才能初始化呢? . . 5 2 结构、联合和枚举7 2.1 声明struct x1 f . . . g; 和typedef struct f . . . g x2; 有什么不同? . 7 2.2 为什么struct x f . . . g; x ...
  • vc++ 应用源码包_1

    热门讨论 2012-09-15 14:22:12
    Trace程序 演示了输出信息。 TransparentStatic 自绘CStatic控件。 TreeView控件 自绘CTreeView控件。 VC 创建向导模式 VC 精品源码打包下载(解) CatListBox_src.zip CatListBox_demo.zip 这个程序模仿Outlook...
  • vc++ 应用源码包_2

    热门讨论 2012-09-15 14:27:40
    Trace程序 演示了输出信息。 TransparentStatic 自绘CStatic控件。 TreeView控件 自绘CTreeView控件。 VC 创建向导模式 VC 精品源码打包下载(解) CatListBox_src.zip CatListBox_demo.zip 这个程序模仿Outlook...
  • vc++ 应用源码包_4

    热门讨论 2012-09-15 14:38:35
    Trace程序 演示了输出信息。 TransparentStatic 自绘CStatic控件。 TreeView控件 自绘CTreeView控件。 VC 创建向导模式 VC 精品源码打包下载(解) CatListBox_src.zip CatListBox_demo.zip 这个程序模仿Outlook...
  • vc++ 应用源码包_3

    热门讨论 2012-09-15 14:33:15
    Trace程序 演示了输出信息。 TransparentStatic 自绘CStatic控件。 TreeView控件 自绘CTreeView控件。 VC 创建向导模式 VC 精品源码打包下载(解) CatListBox_src.zip CatListBox_demo.zip 这个程序模仿Outlook...
  • vc++ 应用源码包_6

    热门讨论 2012-09-15 14:59:46
    Trace程序 演示了输出信息。 TransparentStatic 自绘CStatic控件。 TreeView控件 自绘CTreeView控件。 VC 创建向导模式 VC 精品源码打包下载(解) CatListBox_src.zip CatListBox_demo.zip 这个程序模仿Outlook...
  • vc++ 应用源码包_5

    热门讨论 2012-09-15 14:45:16
    Trace程序 演示了输出信息。 TransparentStatic 自绘CStatic控件。 TreeView控件 自绘CTreeView控件。 VC 创建向导模式 VC 精品源码打包下载(解) CatListBox_src.zip CatListBox_demo.zip 这个程序模仿Outlook...
  • 精通Oracle PL/SQL--详细书签版

    热门讨论 2012-08-21 13:06:28
     安装:这部分展示如何搭建高效的SQL*Plus环境以及如何启动并运行书中用到的性能工具,即AUTOTRACE、SQL_TRACE、TKPROF和RUNSTATS。  第1章:高效能的PL/SQL。这一章给出了我们认为的“高效PL/SQL”的定义,并引入...
  • 至此,我们有了一个简单的开发环境了,可以充分利用网上大量的以oSIP为基础的代码片段和官方说明文档开始具体函数功能的测试和使用了:) --------------------------------...
  • SQL_TRACE跟踪与诊断 16 临时表空间组导致递归SQL高度解析案例 19 使用闪回查询恢复误删除的数据 21 使用ErrorStack进行错误跟踪及诊断 24 断电故障导致ASM DiskGroup故障及恢复案例 26 共享池的改进与ORA-...
  • vc++ 开发实例源码包

    2014-12-16 11:25:17
    详细讲解了Crypt++的加密解密的使用以及其它的加密解密方法(例如base64加解密、哈希加解密以及其它的文件加解密),分静态库和动态库方法。 JSCalls_demo js调用的演示源码 树控件拖动 演示了在树控件中来回拖动...

空空如也

空空如也

1 2
收藏数 34
精华内容 13
关键字:

trace方法怎么利用