使用安全约束、码头排除 HTTP 方法
Excluding HTTP methods using security constraint, jetty
我试图阻止除 GET、PUT 和 POST 以外的所有 http 方法访问我的 Web 应用程序,但它禁止所有 HTTP 方法,甚至是此约束中省略的方法。
<security-constraint>
<web-resource-collection>
<web-resource-name>Disable everything</web-resource-name>
<url-pattern>/</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>PUT</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
但是,如果我包含 <http-method>
列出要阻止的各个方法,它会按预期工作,但我想知道为什么我的原始约束不起作用。
根据 Servlet XSD ...
<http-method>
Each http-method names an HTTP method to which the constraint applies.
<http-method-omission>
Each http-method-omission names an HTTP method to which the constraint
does not apply.
通常您会同时使用两者,但会受到不同的限制。
举个例子(来自Jettywebdefault.xml
)
<security-constraint>
<web-resource-collection>
<web-resource-name>Disable TRACE</web-resource-name>
<url-pattern>/</url-pattern>
<http-method>TRACE</http-method>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Enable everything but TRACE</web-resource-name>
<url-pattern>/</url-pattern>
<http-method-omission>TRACE</http-method-omission>
</web-resource-collection>
</security-constraint>
第一个约束拒绝 TRACE(空 auth-constraint)。
第二个约束启用除 TRACE 之外的所有方法。
确保您使用的是最新版本的 Jetty,因为在 9.4.38 之前的版本中存在遗漏的方法合并错误(它仅适用于根上下文)。
https://github.com/eclipse/jetty.project/issues/5909
我建议阅读那个问题,因为有很多关于行为的建议取决于 context-path(或不)、根 url-pattern、默认 url-pattern、基于上下文的 url-patterns 等。甚至是针对您的特定上下文替换 webdefault.xml
的配置。
您使用的是嵌入式 Jetty 吗?
如果是这样,您可能会发现使用 HttpConfiguration.Customizer
更容易。
package jetty;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.EnumSet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
public class RejectHttpMethodsDemo
{
public static class BanHttpMethods implements HttpConfiguration.Customizer
{
private final EnumSet<HttpMethod> bannedMethods;
public BanHttpMethods(EnumSet<HttpMethod> bannedMethods)
{
this.bannedMethods = bannedMethods;
}
@Override
public void customize(Connector connector, HttpConfiguration channelConfig, Request request)
{
HttpMethod httpMethod = HttpMethod.fromString(request.getMethod());
if (bannedMethods.contains(httpMethod))
{
request.setHandled(true);
request.getResponse().setStatus(HttpStatus.METHOD_NOT_ALLOWED_405);
}
}
}
public static void main(String[] args) throws Exception
{
Server server = new Server();
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.addCustomizer(new BanHttpMethods(EnumSet.of(HttpMethod.TRACE, HttpMethod.MOVE)));
ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
connector.setPort(9090);
server.addConnector(connector);
HandlerList handlers = new HandlerList();
handlers.addHandler(new AbstractHandler()
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
response.setCharacterEncoding("utf-8");
response.setContentType("text/plain");
response.getWriter().printf("Hello, You asked to %s %s, that is all%n", baseRequest.getMethod(), baseRequest.getRequestURI());
}
});
handlers.addHandler(new DefaultHandler());
server.setHandler(handlers);
server.start();
try
{
HttpClient httpClient = HttpClient.newHttpClient();
demoRequest(httpClient, server.getURI().resolve("/apple"), "GET");
demoRequest(httpClient, server.getURI().resolve("/banana"), "TRACE");
demoRequest(httpClient, server.getURI().resolve("/cherry"), "MOVE");
}
catch (Throwable t)
{
t.printStackTrace();
}
finally
{
server.stop();
}
}
private static void demoRequest(HttpClient httpClient, URI path, String method)
{
try
{
HttpRequest httpRequest = HttpRequest.newBuilder(path)
.method(method, HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
System.out.printf("HTTP %s %s Response Status: %d%n", httpRequest.method(), httpRequest.uri(), httpResponse.statusCode());
System.out.println(httpResponse.body());
}
catch (IOException | InterruptedException e)
{
e.printStackTrace();
}
}
}
我试图阻止除 GET、PUT 和 POST 以外的所有 http 方法访问我的 Web 应用程序,但它禁止所有 HTTP 方法,甚至是此约束中省略的方法。
<security-constraint>
<web-resource-collection>
<web-resource-name>Disable everything</web-resource-name>
<url-pattern>/</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>PUT</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
但是,如果我包含 <http-method>
列出要阻止的各个方法,它会按预期工作,但我想知道为什么我的原始约束不起作用。
根据 Servlet XSD ...
<http-method>
Each http-method names an HTTP method to which the constraint applies.
<http-method-omission>
Each http-method-omission names an HTTP method to which the constraint does not apply.
通常您会同时使用两者,但会受到不同的限制。
举个例子(来自Jettywebdefault.xml
)
<security-constraint>
<web-resource-collection>
<web-resource-name>Disable TRACE</web-resource-name>
<url-pattern>/</url-pattern>
<http-method>TRACE</http-method>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Enable everything but TRACE</web-resource-name>
<url-pattern>/</url-pattern>
<http-method-omission>TRACE</http-method-omission>
</web-resource-collection>
</security-constraint>
第一个约束拒绝 TRACE(空 auth-constraint)。
第二个约束启用除 TRACE 之外的所有方法。
确保您使用的是最新版本的 Jetty,因为在 9.4.38 之前的版本中存在遗漏的方法合并错误(它仅适用于根上下文)。
https://github.com/eclipse/jetty.project/issues/5909
我建议阅读那个问题,因为有很多关于行为的建议取决于 context-path(或不)、根 url-pattern、默认 url-pattern、基于上下文的 url-patterns 等。甚至是针对您的特定上下文替换 webdefault.xml
的配置。
您使用的是嵌入式 Jetty 吗?
如果是这样,您可能会发现使用 HttpConfiguration.Customizer
更容易。
package jetty;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.EnumSet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
public class RejectHttpMethodsDemo
{
public static class BanHttpMethods implements HttpConfiguration.Customizer
{
private final EnumSet<HttpMethod> bannedMethods;
public BanHttpMethods(EnumSet<HttpMethod> bannedMethods)
{
this.bannedMethods = bannedMethods;
}
@Override
public void customize(Connector connector, HttpConfiguration channelConfig, Request request)
{
HttpMethod httpMethod = HttpMethod.fromString(request.getMethod());
if (bannedMethods.contains(httpMethod))
{
request.setHandled(true);
request.getResponse().setStatus(HttpStatus.METHOD_NOT_ALLOWED_405);
}
}
}
public static void main(String[] args) throws Exception
{
Server server = new Server();
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.addCustomizer(new BanHttpMethods(EnumSet.of(HttpMethod.TRACE, HttpMethod.MOVE)));
ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig));
connector.setPort(9090);
server.addConnector(connector);
HandlerList handlers = new HandlerList();
handlers.addHandler(new AbstractHandler()
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
response.setCharacterEncoding("utf-8");
response.setContentType("text/plain");
response.getWriter().printf("Hello, You asked to %s %s, that is all%n", baseRequest.getMethod(), baseRequest.getRequestURI());
}
});
handlers.addHandler(new DefaultHandler());
server.setHandler(handlers);
server.start();
try
{
HttpClient httpClient = HttpClient.newHttpClient();
demoRequest(httpClient, server.getURI().resolve("/apple"), "GET");
demoRequest(httpClient, server.getURI().resolve("/banana"), "TRACE");
demoRequest(httpClient, server.getURI().resolve("/cherry"), "MOVE");
}
catch (Throwable t)
{
t.printStackTrace();
}
finally
{
server.stop();
}
}
private static void demoRequest(HttpClient httpClient, URI path, String method)
{
try
{
HttpRequest httpRequest = HttpRequest.newBuilder(path)
.method(method, HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
System.out.printf("HTTP %s %s Response Status: %d%n", httpRequest.method(), httpRequest.uri(), httpResponse.statusCode());
System.out.println(httpResponse.body());
}
catch (IOException | InterruptedException e)
{
e.printStackTrace();
}
}
}