有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

用于XSS预防的java ESAPI不起作用

我主要在JSP中解决代码中的跨站点脚本问题

下面是原始代码

 //scriplet code
    <% String userId = request.getParameter("sid"); 
    ...%>

在同一个Jsp中

     <input type = hidden name = "userID" value = "<%= userId %>" />

我做了一些修改,加入了esapi-2.1.0。在lib和ESAPI中使用jar。属性,验证。类路径中的属性。然后对scriplet代码进行以下更改,以修复上述代码

      //scriplet code
    <% String userId = ESAPI.encoder().encodeForHTML(request.getParameter("sid")); 
    ...%>

我原以为这会解决这个问题,但当我使用Fortify扫描代码时,这些行再次突出显示为存在XSS问题。如果你们对如何处理这件事有任何想法,请帮忙。谢谢

----更新

非常感谢@avgvstvs。这很有见地。遵循指导原则,不确定我是否遗漏了什么。密码-

          String              userSID=ESAPI.encoder().encodeForHTMLAttribute(request.getHeader("janus_sid")); session.setAttribute("username",userSID);<input type=hidden name="USERNAME" value="<%= userSID %>"

对于另一个varibale调试,下面是用法

       String debugFlag =  ESAPI.encoder().encodeForJavaScript(request.getParameter("debug"));var debugFlag = "<%= debugFlag%>";if(debugFlag == "y"){       
        document.title=   title + " (" + host + ")";
        defaultAppTitle = title + " (" + host +  ")";           
    }                                                           

最新的强化扫描仍将其列为漏洞:-(


共 (2) 个答案

  1. # 1 楼答案

    您需要问的第一个问题应该是“我要把这个值传递给什么代码解释器?”

    不幸的是,防止XSS并不是一项基于配方的任务,从外观上看,您的应用程序使用的是Scriptlet,这使得Fortify等静态代码扫描工具很难给出准确的结果。JSP是在运行时编译的,但Fortify只扫描源代码。您应该注意到,将来应该有任务/故事归档,以便将Scriptlet重构到JSTL。稍后您将为此感谢我。然后,您可以在这些用例中使用esapi标记库。Fortify在扫描纯Java代码方面做得很好,TagLib提供了这一点

    1. ESAPI.encoder().encodeForHTML(userId)只会在有问题的变量将被放置在标签之间的用例中保护您免受XSS的攻击,比如<span><%= userId %></span>这不是您的情况

    2. ESAPI.encoder().encodeForHTMLAttribute(userId)是您在特定的、狭窄的用例中想要的。这是因为Html属性中的转义规则与放置在标记中的数据不同。这会解决你眼前的问题

    3. 如果该值将由JavaScript独占使用,那么您需要ESAPI.encoder().encodeForJavaScript(userId)

    4. 如果该值是可呈现的HTML,则发送到将呈现标记的javascript函数,如element.innerHTML = “<HTML> Tags and markup”;您希望<%=Encoder.encodeForJS(Encoder.encodeForHTML(userId))%>

    这只是几个例子,here are a few more但我的答案最重要的要点是:您需要知道应用程序中每个变量的完整数据流,并且始终为适当的输出上下文编码。在安全领域,“上下文”意味着“数据正在被传递给一个新的代码解释器。”如果你能很好地实现这种理解,你就不需要再加强了!:-)

    增加了复杂性

    在您的评论中,您注意到该值后来被JavaScript使用。因此,在这种情况下,正确的解决方案可能是分叉两个不同的变量,每个变量都设置为正确的编码。对于HTML属性大小写:

    String escapedHtmlUserId = ESAPI.encoder().encodeForHTMLAttribute(userId);
    

    对于Javascript案例:

    String escapedJSUserId = ESAPI.encoder().encodeForJavaScript(userId);
    

    然后适当地使用这些值。如果使用JSTL/taglibs,就可以在正确的位置使用正确的esapi taglib,而不是拆分为两个单独的scriptlet变量

    还有一件事

    在评论中:

    我们有一个初始scriptlet声明:

    <% String userId = ESAPI.encoder().encodeForHTML(request.getParameter("sid")); 
    ...%>
    

    它稍后将用于javascript函数:

    <%= ESAPI.encoder().encodeForJavascripl(userId)%>`
    

    只需指出,正如前面所述,userId变量在初始化时不再是原始文本。实际上,javascript的编码是这样的:

    <% ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(request.getParameter("sid"))); 
    ...%>
    

    如果javascript将使用*呈现HTML。innerHTML()或*。这很好。否则,只需注意输入已从原始状态更改

    另外,注意一些JavaScript can undo what you've done的事实,并确保你的JavaScript没有做类似的事情

    ===============更多添加的代码,更多问题===================

    所以我们追踪了所有的数据路径,我们仔细检查了我们的JSP是否包含在另一个JSP中,该JSP为我们引入了新的上下文进行防御,在这一点上,我会闻到“假阳性”,但如果我是你,我会联系HP支持部门,提出假阳性问题。我对你的应用程序的细节知之甚少,除非我有权访问完整的源代码,否则我不会对你有更多的用处。因为您处理的是scriptlets,所以Fortify可能无法跟踪从变量实例化到最终输出的完整数据路径,所以失败速度很快,因此它至少可以警告您“到目前为止”发现了什么

  2. # 2 楼答案

    谢谢你们的帮助。最终找到了防止XSS问题并通过强化静态代码分析的解决方案。我和Anitsamy library一起使用了ESAPI。以下是所需的3个主要更改

    1. 实现Anitsamy过滤器

      添加一个新的过滤器并覆盖请求方法getParameter、getParameterValues,以去除请求中的任何可疑标记。筛选器加载一个策略文件,我们在其中定义规则,如

      a.需要从请求中删除的标签(如标签等)

      b.用于href、align等常见属性的正则表达式。

    过滤器的实现示例如下http://barrypitman.com/2011/04/14/using-input-validation-XSS/

    1. 使用ESAPI库执行输入验证

       String reportName = request.getParameter("reportName");
       ESAPI.validator().getValidInput("Report Name", 
                                        reportName, "ReportNamePattern", 100, false);
      

      在上面的代码中

      1. “报告名称”是上下文
      2. reportName是数据字段
      3. ReportNamePattern是ESAPI中定义的正则表达式模式。属性作为验证器。ReportNamePattern=^[a-zA-Z]{1}[0-9]{6}$
      4. 100是数据字段reportName的最大长度
      5. false是一个表示不允许空值的标志
    2. 执行输出编码
      正如@avgvstvs所指出的,输出编码也是必须的

      如果要在HTML中使用reportName字段,下面是如何编码

      <tr> <th> Report :     <%=ESAPI.encoder().encodeForHTML(reportName)%> </th> </tr>
      

      如果要在javascript代码中使用reportName字段,下面是如何编码

       var reportName = "<%= ESAPI.encoder().encodeForJavaScript(reportName)%>";
      

      如果要在HTML属性中使用reportName字段,下面是如何编码

      <input type=hidden name="USERNAME" value="<%=ESAPI.encoder().encodeForHTMLAttribute
          (reportName)%>"/>