禁用 Netty HTTP 标头验证¶
ID: java/netty-http-request-or-response-splitting
Kind: problem
Security severity: 6.1
Severity: error
Precision: high
Tags:
- security
- external/cwe/cwe-93
- external/cwe/cwe-113
Query suites:
- java-code-scanning.qls
- java-security-extended.qls
- java-security-and-quality.qls
将用户输入(例如,HTTP 请求参数)直接写入 HTTP 标头可能会导致 HTTP 请求拆分或响应拆分漏洞。
HTTP 响应拆分可能导致 XSS 和缓存中毒等漏洞。
HTTP 请求拆分允许攻击者将其他 HTTP 请求注入到客户端的传出套接字连接中。这可能允许攻击者执行类似 SSRF 的攻击。
在 servlet 容器的上下文中,如果用户输入包含空行,并且 servlet 容器不转义空行,则远程用户可能导致响应变为两个单独的响应。然后,远程用户可以控制一个或多个响应,这也是 HTTP 响应拆分。
建议¶
以与防范跨站脚本相同的方式防范 HTTP 标头拆分。在将任何数据传递到 HTTP 标头之前,请检查数据中是否有特殊字符,或转义存在的任何特殊字符。
如果代码直接调用 Netty API,请确保将 validateHeaders
参数设置为 true
。
示例¶
以下示例显示了以两种不同方式将“name”参数写入 cookie 的情况。第一种方式直接将其写入 cookie,因此容易受到响应拆分攻击。第二种方式首先删除所有特殊字符,从而避免了潜在问题。
public class ResponseSplitting extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// BAD: setting a cookie with an unvalidated parameter
Cookie cookie = new Cookie("name", request.getParameter("name"));
response.addCookie(cookie);
// GOOD: remove special characters before putting them in the header
String name = removeSpecial(request.getParameter("name"));
Cookie cookie2 = new Cookie("name", name);
response.addCookie(cookie2);
}
private static String removeSpecial(String str) {
return str.replaceAll("[^a-zA-Z ]", "");
}
}
示例¶
以下示例展示了使用带有 HTTP 响应拆分验证配置的“netty”库。第二种方法将在使用参数构建 HTTP 响应之前验证这些参数。
import io.netty.handler.codec.http.DefaultHttpHeaders;
public class ResponseSplitting {
// BAD: Disables the internal response splitting verification
private final DefaultHttpHeaders badHeaders = new DefaultHttpHeaders(false);
// GOOD: Verifies headers passed don't contain CRLF characters
private final DefaultHttpHeaders goodHeaders = new DefaultHttpHeaders();
// BAD: Disables the internal response splitting verification
private final DefaultHttpResponse badResponse = new DefaultHttpResponse(version, httpResponseStatus, false);
// GOOD: Verifies headers passed don't contain CRLF characters
private final DefaultHttpResponse goodResponse = new DefaultHttpResponse(version, httpResponseStatus);
}
示例¶
以下示例展示了使用带有 HTTP 请求拆分验证配置的 netty 库。示例中推荐的第二种方法将在使用参数构建 HTTP 请求之前验证这些参数。
public class NettyRequestSplitting {
// BAD: Disables the internal request splitting verification
private final DefaultHttpHeaders badHeaders = new DefaultHttpHeaders(false);
// GOOD: Verifies headers passed don't contain CRLF characters
private final DefaultHttpHeaders goodHeaders = new DefaultHttpHeaders();
// BAD: Disables the internal request splitting verification
private final DefaultHttpRequest badRequest = new DefaultHttpRequest(httpVersion, method, uri, false);
// GOOD: Verifies headers passed don't contain CRLF characters
private final DefaultHttpRequest goodResponse = new DefaultHttpRequest(httpVersion, method, uri);
}