Background
I'm currently working on a project that looks at various HTTP passive fingerprinting techniques for the purpose of security. Some aspects of the request I plan to fingerprint include the client hello, header order, HTTP2 frame settings, and HTTP2 pseudo header order. So far I have implemented a solution to retrieve the cipher suites, compression methods, and extensions from the client hello by extending Jetty's org.eclipse.jetty.util.ssl.SslContextFactory.Server
class to wrap SSLEngine instances. I can then access the client hello data in a Zuul filter as shown below:
private static final String SSL_SESSION_ATTRIBUTE = "org.eclipse.jetty.servlet.request.ssl_session";
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
SSLSession sslSession = (SSLSession) request.getAttribute(SSL_SESSION_ATTRIBUTE);
ClientHello clientHello = (ClientHello) sslSession.getValue("client-hello");
return null;
}
More information about HTTP2 fingerprinting:
Issue
Although Spring, Netflix Zuul, and Jetty embedded server have thorough documentation I have been unable to find a way to achieve a similar sort of solution for retrieving HTTP2 frame setting.
A minimal code example to elaborate on @sbordet's answer.
You can extend HTTP2ServerConnectionFactory and override protected > ServerSessionListener newSessionListener(Connector connector, EndPoint > endPoint) to return your custom implementation (that may delegate to the original implementation).
MyServerSessionListener.java
public class MyServerSessionListener implements ServerSessionListener {
private final ServerSessionListener delegate;
public MyServerSessionListener(ServerSessionListener delegate) {
this.delegate = delegate;
}
...
@Override
public void onSettings(Session session, SettingsFrame settingsFrame) {
Map<Integer, Integer> settings = settingsFrame.getSettings();
RequestContext context = RequestContext.getCurrentContext();
context.set("http2-frame-settings", settings);
delegate.onSettings(session, settingsFrame);
}
}
MyHTTP2ConnectionFactory.java
public class MyHTTP2ServerConnectionFactory extends HTTP2ServerConnectionFactory {
public MyHTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration) {
super(httpConfiguration);
}
public MyHTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration, String... protocols) {
super(httpConfiguration, protocols);
}
@Override
protected ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint) {
ServerSessionListener delegate = super.newSessionListener(connector, endPoint);
return new MyServerSessionListener(delegate);
}
}
MyFilter.java
public class MyFilter extends ZuulFilter {
...
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
Map<Integer, Integer> http2FrameSettings = (Map<Integer, Integer>) context.get("http2-frame-settings");
return null;
}
}