Java代码审计漏洞-XSS漏洞

Java代码审计漏洞-XSS漏洞

基础知识
https://www.cnblogs.com/-meditation-/p/16168961.html
个人学习笔记,直接看代码,不写奇怪的东西,分析代码写注释。

情况一:反射型XSS

//1. 
/**
     * Vuln Code.
     * ReflectXSS
     * http://localhost:8080/xss/reflect?xss=<script>alert(1)</script>
     *
     * @param xss unescape string
     */
    @RequestMapping("/reflect")
    @ResponseBody
    public static String reflect(String xss) {
        return xss;
    }
/**
	客户端传入xss参数,服务端获取值后直接返回
*/

//2.
@WebServlet("/demo")
public class xssServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html");// 设置响应类型
        String content = request.getParameter("content");  //获取content传参数据
        request.setAttribute("content", content);  //content共享到request域
        request.getRequestDispatcher("/WEB-INF/pages/xss.jsp").forward(request, response);  //转发到xxs.jsp页面中

    }
}

//xss.jsp代码:
  <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    ${requestScope.content}
</head>
<body>

</body>
</html>
  
/**
	和上面的情况一样,但是中间加了共享到request域,转发到目标页面,EL表达式获取直接输出
*/

情况二:存储型XSS

//1.
/**
     * Vul Code.
     * StoredXSS Step1
     * http://localhost:8080/xss/stored/store?xss=<script>alert(1)</script>
     *
     * @param xss unescape string
     */
    @RequestMapping("/stored/store")
    @ResponseBody
    public String store(String xss, HttpServletResponse response) {
        Cookie cookie = new Cookie("xss", xss);
        response.addCookie(cookie);
        return "Set param into cookie";
    }
/**
	客户端传入xss参数,服务端获取值后传入cookie的XSS键返回给客户端
*/


 /**
     * Vul Code.
     * StoredXSS Step2
     * http://localhost:8080/xss/stored/show
     *
     * @param xss unescape string
     */
    @RequestMapping("/stored/show")
    @ResponseBody
    public String show(@CookieValue("xss") String xss) {
        return xss;
    }
/**
	前面已经将XSS写入Cookie,同一浏览器访问http://localhost:8080/xss/stored/show,服务端获取Cookie中XSS的值并返回客户端
*/


//2.
//输入点
public void StoreXss(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // TODO Auto-generated method stub

        String name = req.getParameter("name");
        String mail = req.getParameter("mail");
        String message = req.getParameter("message");
        if(!name.equals(null) && !mail.equals(null) && !message.equals(null)){

            MessageInfoService msginfo = new MessageInfoServiceImpl();
            msginfo.MessageInfoStoreService(name, mail, message);
          
            resp.getWriter().flush();
            resp.getWriter().close();
        }
    }
//控制器
public void ShowMessage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
				
        MessageInfoService msginfo = new MessageInfoServiceImpl();
				//MessageInfoShowService主要是用于实例化MessageInfoDaoImpl()
        List<MessageInfo> msg = msginfo.MessageInfoShowService();
        if( msg != null){
            req.setAttribute("msg", msg);
            req.getRequestDispatcher("/message.jsp").forward(req, resp);
            return ;
        }
    }

//MessageInfoShowService()
try {
            ....
						//主要执行的是从message表中查询所有数据,然后将 name、mail、message 的值加到 messageinfo List 中,最后返回给 servlet 层。
            String sql = "select * from message";
            ps = conns.prepareStatement(sql);
            rs = ps.executeQuery();
            messageinfo = new ArrayList<MessageInfo>();
            while(rs.next()){
                MessageInfo msg = new MessageInfo();

                msg.setName(rs.getString("name"));
                msg.setMail(rs.getString("mail"));
                msg.setMessage(rs.getString("message"));

                messageinfo.add(msg);
            }

        ....

        return messageinfo;
    }
}
/**
	return messageinfo; 把查询的name、mail、message 的值返回给List<MessageInfo> msg
	req.getRequestDispatcher("/message.jsp").forward(req, resp); 转发到 message.jsp
*/ 


<%
  //直接获取msg输出
    List<MessageInfo> msginfo = (ArrayList<MessageInfo>)request.getAttribute("msg");
    for(MessageInfo m:msginfo){
 %>
<table>

    <tr><td class="klytd"> 留言人:</td>
        <td class ="hvttd"> <%=m.getName() %></td>
    </tr> 
    <tr><td class="klytd"> e-mail:</td><td class ="hvttd"> <%=m.getMail() %></td>
        </tr>
    <tr><td class="klytd"> 内容:</td><td class ="hvttd"> <%=m.getMessage() %></td></tr>

</table> <% } %>
</div>

安全代码

//1.定义转义输入字符函数
/**
     * safe Code.
     * http://localhost:8080/xss/safe
     */
    @RequestMapping("/safe")
    @ResponseBody
    public static String safe(String xss) {
        return encode(xss);
    }

    private static String encode(String origin) {
        origin = StringUtils.replace(origin, "&", "&amp;");
        origin = StringUtils.replace(origin, "<", "&lt;");
        origin = StringUtils.replace(origin, ">", "&gt;");
        origin = StringUtils.replace(origin, "\"", "&quot;");
        origin = StringUtils.replace(origin, "'", "&#x27;");
        origin = StringUtils.replace(origin, "/", "&#x2F;");
        return origin;
    }



//2.全局过滤器过滤
<filter>  
        <filter-name>XssSafe</filter-name>  
        <filter-class>XssFilter</filter-class>  
    </filter>  
    <filter-mapping>  
        <filter-name>XssSafe</filter-name>  
        <url-pattern>/\*</url-pattern>   //格式问题加了个转移字符 ‘/*’
    </filter-mapping>
    
//过滤器的内容
//XssFilter实现:

public class XssFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);
    }

}

//XssHttpServletRequestWrapper实现

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @SuppressWarnings("rawtypes")
    public Map<String,String[]> getParameterMap(){
        Map<String,String[]> request_map = super.getParameterMap();
        Iterator iterator = request_map.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry me = (Map.Entry)iterator.next();
            String[] values = (String[])me.getValue();
            for(int i = 0 ; i < values.length ; i++){
                values[i] = xssClean(values[i]);
            }
        }

        return request_map;
    }
     public String[] getParameterValues(String paramString)
      {
        String[] arrayOfString1 = super.getParameterValues(paramString);
        if (arrayOfString1 == null)
          return null;
        int i = arrayOfString1.length;
        String[] arrayOfString2 = new String[i];
        for (int j = 0; j < i; j++){
            arrayOfString2[j] = xssClean(arrayOfString1[j]);
        }
        return arrayOfString2;
      }

      public String getParameter(String paramString)
      {
        String str = super.getParameter(paramString);
        if (str == null)
          return null;
        return xssClean(str);
      }

      public String getHeader(String paramString)
      {
        String str = super.getHeader(paramString);
        if (str == null)
          return null;
        str = str.replaceAll("\r|\n", "");
        return xssClean(str);
      }


      private String xssClean(String value) {
        //ClassLoaderUtils.getResourceAsStream("classpath:antisamy-slashdot.xml", XssHttpServletRequestWrapper.class)
        if (value != null) {
            // NOTE: It's highly recommended to use the ESAPI library and
            // uncomment the following line to
            // avoid encoded attacks.
            // value = encoder.canonicalize(value);
            value = value.replaceAll("\0", "");

            // Avoid anything between script tags
            Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>",
                    Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid anything in a src='...' type of expression
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                            | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            // Avoid anything in a href='...' type of expression
            scriptPattern = Pattern.compile("href[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
                                Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                        | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");


            // Remove any lonesome </script> tag
            scriptPattern = Pattern.compile("</script>",
                    Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Remove any lonesome <script ...> tag
            scriptPattern = Pattern.compile("<script(.*?)>",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                            | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid eval(...) expressions
            scriptPattern = Pattern.compile("eval\\((.*?)\\)",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                            | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid expression(...) expressions
            scriptPattern = Pattern.compile("expression\\((.*?)\\)",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                            | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid javascript:... expressions
            scriptPattern = Pattern.compile("javascript:",
                    Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid vbscript:... expressions
            scriptPattern = Pattern.compile("vbscript:",
                    Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid onload= expressions
            scriptPattern = Pattern.compile("onload(.*?)=",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                            | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
        }  
          return value; 
          }
}

//3.使用工具类xssProtect
/**
	这是谷歌提供的一个用于过滤来自用户输入字段的XSS攻击的Java库
	项目中需要引入 xssProtect-0.1.jar、antlr-3.0.1.jar、antlr-runtime-3.0.1.jar等3个 jar 包
*/

protectedAgainstXSS(String html){StringReader reader = new StringReader(html); StringWriter writer = new StringWriter();
  try {
      // 从“ html”变量解析传入的字符串
      HTMLParser.process( reader, writer, new XSSFilter(), true );

      // 返回经过解析和处理的字符串
      return writer.toString();
  } catch (HandlingException e) {
  }
}
//具体的使用方式可以参考:https://www.iteye.com/blog/liuzidong-1744023

找XSS的方法:

1.扫描器直接扫描,再去回溯
2.拿到一个项目主要是去看看,这个项目有没有一些过滤之类的组件。
  假设没有找到类似的过滤组件,则去随机找几个点去看看是不是存在XSS,

参考文章

https://github.com/JoyChou93/java-sec-code/blob/master/README_zh.md

https://xz.aliyun.com/t/6937#toc-6

posted @ 2022-04-18 18:14  九天揽月丶  阅读(742)  评论(0编辑  收藏  举报