首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >坏消息400:折叠头

坏消息400:折叠头
EN

Stack Overflow用户
提问于 2018-08-08 13:26:19
回答 1查看 5.3K关注 0票数 1

我们最近从Jetty 6_1_26转向了9_4_11。

我们遵循下面的url:http://jetty.4.x6.nabble.com/Configuring-option-2-of-RFC-7230-paragraph-5-HTTP-header-folding-td4966330.html

并对代码进行了必要的更改,以将遵从模式设置为RFC2616,因为我们需要产品中的多行标头支持。

我们就是这样设置的:

代码语言:javascript
复制
public class JettyPsServerConnector extends ServerConnector {
  public JettyServerConnector(Server server, PsSelectorProvider psProvider,Map<String,String> configMap, boolean useSSL) throws Exception{

    super(server,0,-1, new SslConnectionFactory( getSSLContextFactory(configMap),HttpVersion.HTTP_1_1.asString()),
                           new HttpConnectionFactory( getHTTPConfiguration(), HttpCompliance.RFC2616 ));

    }

我们已经使用下面的代码成功地验证了遵从模式正在被改变。

代码语言:javascript
复制
Connector[] connectorArray = server.getConnectors();
for(Connector conn: connectorArray){
    Collection col = conn.getConnectionFactories();
    for(ConnectionFactory con: col){
        if (con instanceof HttpConnectionFactory)
            System.out.println("HTTP Compliance Mode:"+((HttpConnectionFactory)con).getHttpCompliance());
                    }
        }

此输出模式为“RFC2616 2616”。

但是即使在将遵从模式设置为RFC2616之后--我们仍然会看到这个问题。

代码语言:javascript
复制
Bad Message 400: Folding Header

我们正在通过中间的代理服务器访问服务器代码。

我们无法弄清楚是什么原因造成的。

EN

回答 1

Stack Overflow用户

发布于 2018-08-08 15:19:37

首先,不要扩展ServerConnector,除非您完全(我的意思是100%)理解Jetty9.x中的整个HttpConnectionFactoryEndpoint行为。一个小小的错误,你就会打破许多东西。这不是一个可扩展的公共API,很可能在未来版本的Jetty中被标记为final。

如果您需要自定义行为,从查看HttpConfiguration.Customizer开始,然后如果仍然需要其他定制,则使用自定义HttpConnectionFactory代替。

接下来,要知道HttpCompliance只是HttpComplianceSection设置的集合/集合的持有者。您可能希望确保所选的HttpComplianceSection.NO_FIELD_FOLDING设置中没有包含该HttpCompliance

最后,确保您确定并修复了那些有问题的客户端,由于放松的行为(如您的行折叠)导致/创建了许多安全问题,近年来对HTTP的要求越来越严格。有一天,即使您的负载均衡器,代理,路由器等也将拒绝这些类型的请求。

由于许多原因,过时的RFC2616被更新了,其中很大一部分是专门使用MUST NOT (在RFC2119第2节中明确定义的一个短语)等语言将某些行为(例如行折叠)称为危险的,这使得行为对于更新的规范来说是不可选的。IETF在2013年不赞成页眉字段行折叠的原因是与头部注入漏洞的变化相关的许多安全问题。启用页眉字段行折叠后,您将无法防止响应拆分、会话固定、跨站点脚本编写、安全源检查和恶意重定向。

许多现代防火墙/网关/路由器/负载平衡器不支持头折叠。

还请注意,HTTP/2不支持头折叠。

如果不可能纠正这些有问题的客户端(无论出于什么原因),那么您的唯一选择就是从这里开始不升级任何服务器软件,以延迟当天的发生。(其他超出您控制范围的中介可能会在这些请求到达您之前就失败!)

您的必须解决客户端中过时的头折叠问题,因为您控制范围之外的许多事情已经拒绝了这个概念,将在一天内结束您唯一的选择就是修复客户端的行为。

无论如何,这里有一个具有RFC2616遵从模式和行折叠的行为的独立演示。

代码语言:javascript
复制
package jetty;

import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.URI;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.http.HttpCompliance;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.IO;

public class HttpComplianceDemo
{
    public static void main(String[] args) throws Exception
    {
        Server server = new Server();

        HttpConfiguration http_config = new HttpConfiguration();
        http_config.setSendServerVersion(true);

        HttpCompliance compliance = HttpCompliance.RFC2616;
        ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(http_config, compliance));
        connector.setPort(9090);
        server.addConnector(connector);

        ServletContextHandler context = new ServletContextHandler();
        context.setContextPath("/");
        context.addServlet(DumpServlet.class, "/dump");
        context.addServlet(DefaultServlet.class, "/");

        HandlerList handlers = new HandlerList();
        handlers.addHandler(context);
        handlers.addHandler(new DefaultHandler());

        server.setHandler(handlers);

        try
        {
            server.start();

            testLineFolding(server.getURI().resolve("/"));
        }
        finally
        {
            server.stop();
        }
    }

    private static void testLineFolding(URI serverUri) throws IOException
    {
        String host = serverUri.getHost();
        int port = serverUri.getPort();

        try (Socket socket = new Socket(host, port);
             OutputStream out = socket.getOutputStream();
             InputStream in = socket.getInputStream())
        {
            StringBuilder rawRequest = new StringBuilder();
            rawRequest.append("GET /dump HTTP/1.1\r\n");
            rawRequest.append("Host: ").append(serverUri.getRawAuthority()).append("\r\n");
            rawRequest.append("Connection: close\r\n");
            rawRequest.append("X-Foo: name\r\n"); // the header with line folding
            rawRequest.append(" extra\r\n");
            rawRequest.append("\r\n");

            byte bufRequest[] = rawRequest.toString().getBytes(UTF_8);
            System.out.println("--request--");
            System.out.println(new String(bufRequest, UTF_8));
            out.write(bufRequest);
            out.flush();

            ByteArrayOutputStream outBuf = new ByteArrayOutputStream();
            IO.copy(in, outBuf);
            String response = new String(outBuf.toByteArray(), UTF_8);
            System.out.println("--Response--");
            System.out.println(response);
        }
    }

    public static class DumpServlet extends HttpServlet
    {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
        {
            resp.setContentType("text/plain");
            PrintWriter out = resp.getWriter();
            Enumeration<String> enNames = req.getHeaderNames();
            while (enNames.hasMoreElements())
            {
                String name = enNames.nextElement();
                String value = req.getHeader(name);
                out.printf("- [HEADER:%s=%s]\n", name, value);
            }
        }
    }
}

输出..。

代码语言:javascript
复制
2018-08-08 11:21:27.811:INFO::main: Logging initialized @338ms to org.eclipse.jetty.util.log.StdErrLog
2018-08-08 11:21:27.946:INFO:oejs.Server:main: jetty-9.4.11.v20180605; built: 2018-06-05T18:24:03.829Z; git: d5fc0523cfa96bfebfbda19606cad384d772f04c; jvm 9.0.4+11
2018-08-08 11:21:28.004:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@78aab498{/,null,AVAILABLE}
2018-08-08 11:21:28.204:INFO:oejs.AbstractConnector:main: Started ServerConnector@15ff3e9e{HTTP/1.1,[http/1.1]}{0.0.0.0:9090}
2018-08-08 11:21:28.205:INFO:oejs.Server:main: Started @739ms
--request--
GET /dump HTTP/1.1
Host: 192.168.0.119:9090
Connection: close
X-Foo: name
 extra


--Response--
HTTP/1.1 200 OK
Connection: close
Date: Wed, 08 Aug 2018 16:21:28 GMT
Content-Type: text/plain;charset=iso-8859-1
Content-Length: 91
Server: Jetty(9.4.11.v20180605)

- [HEADER:Connection=close]
- [HEADER:X-Foo=name extra]
- [HEADER:Host=192.168.0.119:9090]

2018-08-08 11:21:28.307:INFO:oejs.AbstractConnector:main: Stopped ServerConnector@15ff3e9e{HTTP/1.1,[http/1.1]}{0.0.0.0:9090}
2018-08-08 11:21:28.310:INFO:oejsh.ContextHandler:main: Stopped o.e.j.s.ServletContextHandler@78aab498{/,null,UNAVAILABLE}

如果将HttpCompliance模式更改为RFC7230,则会得到不同的结果。

代码语言:javascript
复制
--request--
GET /dump HTTP/1.1
Host: 192.168.0.119:9090
Connection: close
X-Foo: name
 extra


--Response--
HTTP/1.1 400 Header Folding
Content-Type: text/html;charset=iso-8859-1
Content-Length: 57
Connection: close
Server: Jetty(9.4.11.v20180605)

<h1>Bad Message 400</h1><pre>reason: Header Folding</pre>
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51747916

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档