【问题标题】:Encoded slash (%2F) with Spring RequestMapping path param gives HTTP 400带有 Spring RequestMapping 路径参数的编码斜杠 (%2F) 提供 HTTP 400
【发布时间】:2012-11-09 00:58:30
【问题描述】:

这不是重复的referenced question,因为它是 Spring 特定的。谁添加了这个(事实发生后 3 年!)并没有费心阅读问题或评论线程来查看真正的答案是什么。接受的答案并不完全是答案,但答案的作者从未像我要求的那样回来并对其进行编辑。

鉴于下面的 restful 方法,Spring 3.1 给出了 400 错误“客户端发送的请求在语法上不正确 ()”。当token 参数包含 URL 编码的斜杠 (%2F) 时,例如 "https://somewhere.com/ws/stuff/lookup/resourceId/287559/token/R4o6lI%2FbBx43/userName/jim" 没有 %2F 一切正常。第 3 方已经在调用此服务(当然!)所以我无法更改他们发送的内容,至少在短期内是这样。有关如何在服务器端解决此问题的任何想法?

https://jira.springsource.org/browse/SPR-8662 很好地描述了这个问题,尽管这个问题与我没有使用的 UriTemplate 有关,我可以说。

@RequestMapping("/ws/stuff/**")
@Controller
public class StuffController {
  @RequestMapping(value = "/ws/stuff/lookup/resourceId/{resourceId}/token/{token}/userName/{userName}", method = RequestMethod.GET)
   public @ResponseBody
   String provisionResource(@PathVariable("resourceId") String resourceId, @PathVariable("token") String token, @PathVariable("userName") String userName, ModelMap modelMap,
         HttpServletRequest request, HttpServletResponse response) {
      return handle(resourceId, userName, request, token, modelMap);
   }
}

注意:这是在 Glassfish 3.1.2 上,一开始是 Grizzly/Glassfish 不接受斜线,但是

-Dcom.sun.grizzly.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

解决了这个问题。

asadmin set configs.config.server-config.network-config.protocols.protocol.http-listener-2.http.encoded-slash-enabled=true

似乎没有帮助。

【问题讨论】:

标签: spring rest glassfish glassfish-3 spring-3


【解决方案1】:

对于spring-boot,下面的技巧

@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {

    public static void main(String[] args) throws Exception {
        System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setUrlDecode(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }

}

【讨论】:

  • 它帮助了上面提到的 UrlPathHelperFixed。因为否则会以双斜杠失败。它可以正确解析整个路径参数,不需要从请求中破解。
  • 我已经在jira.spring.io/browse/SPR-11101 中使用UrlPathHelperFixed 尝试过此操作,但没有成功
  • ...使用 Spring Boot 1.5.9-RELEASE
  • Spring Boot 2 也需要这个:stackoverflow.com/a/48636757/636849 以避免出现RequestRejectedException: The request was rejected because the URL contained a potentially malicious String "%2F" 等错误
【解决方案2】:

这可能是你的答案:urlencoded Forward slash is breaking URL

我建议不要将它放在路径中,而是将其移至请求参数。

解决方法:

您可以将 RequestMapping 更改为

@RequestMapping(value = "/ws/stuff/lookup/resourceId/**", method = RequestMethod.GET) 

然后从请求对象中手动解析路径变量。

【讨论】:

  • 很遗憾,我不能很快更改第 3 方的代码。如前所述,我没有使用 Apache,尽管 Grizzly 确实有类似的配置,但我已经将其关闭,如前所述。这个问题现在发生在 Spring 级别。
  • 在这种情况下,您可以将 RequestMapping 更改为 @RequestMapping(value = "/ws/stuff/lookup/resourceId/**", method = RequestMethod.GET) ,然后手动解析路径变量来自请求对象。
  • 让这个答案成为一个答案,锂,我会接受它:-) 这是一个简单而合理的方法来让它工作。我这么说是为了让后来发现这个问题的人很快就会看到一个好的解决方案。
  • 它对我不起作用。即使使用“/**”,如果路径中出现 %2F,我总是得到 400。
  • 简单的修复,但确实应该支持。 Spring 不应该在 找到相关映射之前解码路径。
【解决方案3】:

2019 年 Spring Boot 2+ / Spring(安全)5+ / Java 8+ 更新:

由于我对 iamiddy's answer 的编辑被拒绝,我还想提供 Spring Boot 2 + 的完整解决方案作为单独的答案。

WebMvcConfigurerAdapter 已被 Spring5 / Java8 弃用,可以直接替换为接口 WebMvcConfigurer 以结束:

@SpringBootApplication
public class Application extends WebMvcConfigurer {

    public static void main(String[] args) throws Exception {
        System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setUrlDecode(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}

另外,您还需要配置 Spring 的 (Strict)HttpFirewall 以避免使用错误消息 The request was rejected because the URL contained a potentially malicious String "%2F" 阻塞编码的斜线

@Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowUrlEncodedSlash(true);    
    return firewall;
}

Spring Boot 将在可用时使用上述HttpFirewall Bean - 否则可能需要配置WebSecurity,如here 所述:

【讨论】:

  • 两件事:首先,防火墙部分是可选的,如果你当然不使用 spring-security,其次 - 如果你使用 jetty,只需覆盖 configurePathMatch 方法。我没有发现任何关于码头的信息,只是它应该不像在 tomcat 中那样工作,但事实并非如此,我必须修复它。
  • 根据Tomcat 9 docs,属性UDecoder.ALLOW_ENCODED_SLASH 将被弃用。所以可能是@Beanpublic WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {return factory -> factory.addConnectorCustomizers(connector -> connector.setEncodedSolidusHandling(PASS_THROUGH.getValue()));}
  • @leonid 对我来说它与 DECODE connector -> connector.setEncodedSolidusHandling(EncodedSolidusHandling.DECODE.getValue())); 一起工作
【解决方案4】:

对于 Spring Boot 应用程序,这对我有用..

版本 1 添加

org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

到您的 application.properties 文件

第 2 版 像这样运行你的 Spring Boot 应用程序。

static void main(String[] args) {
    System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
    SpringApplication.run this, args
}

版本 3 或运行您的 java 应用程序 -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

这个为我修复的 %2F 编码斜线路径变量。

【讨论】:

    【解决方案5】:

    这是 Spring 3.2.4 的修复(也应该适用于其他版本)。必须覆盖默认的 UrlPathHelper

        public class UrlPathHelperFixed extends UrlPathHelper {
    
            public UrlPathHelperFixed() {
                super.setUrlDecode(false);
            }
    
            @Override
            public void setUrlDecode(boolean urlDecode) {
                if (urlDecode) {
                    throw new IllegalArgumentException("Handler [" + UrlPathHelperFixed.class.getName() + "] does not support URL decoding.");
                }
            }
    
            @Override
            public String getServletPath(HttpServletRequest request) {
                return getOriginatingServletPath(request);
            }
    
            @Override
            public String getOriginatingServletPath(HttpServletRequest request) {
                return request.getRequestURI().substring(request.getContextPath().length());
            }
        }
    

    并将其注入映射处理程序:

        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
            <property name="order" value="-1"></property>
            <property name="urlPathHelper">
                <bean class="com.yoochoose.frontend.spring.UrlPathHelperFixed"/>
            </property>
        </bean>
    

    经过一天的努力,它现在对我有用 :-)

    建议Spring团队使用https://jira.springsource.org/browse/SPR-11101

    【讨论】:

    • 不错。根据 tkt,它已在 Spring 3.2.8 中修复。
    • 使用这个修复仍然可以解决 Spring 4.3.8 的问题;只是按照其他地方的建议设置 urlDecode=false 似乎在所有情况下都不能正常工作(尽管它似乎对某些人来说工作正常)。
    【解决方案6】:

    我找到了适合我的解决方案;

    System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
    

    就在之前 springApplication.run(args);

    并在应用程序类中添加以下代码

     @Override
        public void configurePathMatch(PathMatchConfigurer configurer) {
            UrlPathHelper urlPathHelper = new UrlPathHelper();
            urlPathHelper.setUrlDecode(false);
            configurer.setUrlPathHelper(urlPathHelper);
        }
    

    【讨论】:

      【解决方案7】:

      为了避免手动解析变量,我做了以下操作:

      1. 在执行任何其他代码之前添加以下内容:
      System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
      
      1. 在控制器中,添加2个变量而不是1个,例如:
          @RequestMapping(value = "/api/devices-by-name/device={deviceId}/restconf/data/ietf-interfaces:interfaces-state/interface={dpuIdPrefix}/{dpuIdSuffix}",
                  method = RequestMethod.GET,
                  produces = "application/json")
          public ResponseEntity<String> getInterfaceState(@PathVariable(value = "deviceId") String deviceId,
                                                          @PathVariable(value = "dpuIdPrefix") String dpuIdPrefix,
                                                          @PathVariable(value = "dpuIdSuffix") String dpuIdSuffix) {
              String dpuId = dpuIdPrefix + "/" + dpuIdSuffix;
      

      然后我可以检索以下内容:

      curl -s -X GET http://localhost:9090/api/devices-by-name/device=ZNSDX16DPU03/restconf/data/ietf-interfaces:interfaces-state/interface=gfast%200%2F14
      

      如果斜线是可选的,那么您可能需要配置两个不同的请求映射。

      【讨论】:

        【解决方案8】:

        我们刚刚在我的办公室遇到了这个问题,我们根据您将它放在查询参数中的 Solubris said 做了上面的建议。唯一的额外要求是数据也可以有一个“&”,这会弄乱查询参数。我们所要做的就是在将文本发送到 URL 之前对其进行编码,甚至“&”也被过滤掉了。

        【讨论】:

          【解决方案9】:

          另一个答案是将"/" 编码两次,这将产生"%252F"
          在您映射的端点中,Spring 会将其解码回"%2F"。您只需要使用以下代码再次对其进行解码:

          URLDecoder.decode(encoded_URL, "UTF-8");

          【讨论】:

          • 这很聪明,但 %25 也被认为是恶意的。
          【解决方案10】:

          以下解决了 BACK_SLASH 问题:

          public static void main(String[] args) throws Exception {
            System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
            SpringApplication.run(Application.class, args);
          }
          

          但是,同样的功能可以通过 application.yml 来完成。

          org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH: true
          

          此设置无效。我没有找到方法,还在寻找它。

          【讨论】:

          • 为了澄清,“反斜杠”是指从左上角开始向下交叉到右下角的反斜杠,反斜杠则是反斜杠。例如,URL 有一个 SLASH (https://www.stackoverflow.com),Windows 路径有一个 BACK_SLASH (c:\windows)。
          猜你喜欢
          • 2010-12-29
          • 2019-04-17
          • 2019-02-09
          • 1970-01-01
          • 2012-11-16
          • 1970-01-01
          • 2023-03-10
          • 1970-01-01
          • 2016-10-20
          相关资源
          最近更新 更多