CodeQL 文档

从远程来源进行 URL 重定向

ID: java/unvalidated-url-redirection
Kind: path-problem
Security severity: 6.1
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-601
Query suites:
   - java-code-scanning.qls
   - java-security-extended.qls
   - java-security-and-quality.qls

点击查看 CodeQL 代码库中的查询

在没有验证输入的情况下,直接将用户输入合并到 URL 重定向请求中,会助长网络钓鱼攻击。在这些攻击中,毫无戒心的用户可能会被重定向到一个看起来非常像他们打算访问的真实网站的恶意网站,但该网站实际上由攻击者控制。

建议

为了防范不受信任的 URL 重定向,建议不要将用户输入直接放到重定向 URL 中。相反,在服务器上维护一个授权重定向列表;然后根据用户提供的输入从该列表中选择。

如果这不可行,则应以其他方式验证用户输入,例如,验证目标 URL 是否与当前页面位于同一主机上。

示例

以下示例显示了 HTTP 请求参数在没有验证输入的情况下直接用于 URL 重定向,这会助长网络钓鱼攻击

public class UrlRedirect extends HttpServlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // BAD: a request parameter is incorporated without validation into a URL redirect
    response.sendRedirect(request.getParameter("target"));
  }
}

解决问题的一种方法是在进行重定向之前,针对已知的固定字符串验证用户输入

public class UrlRedirect extends HttpServlet {
  private static final List<String> VALID_REDIRECTS = Arrays.asList(
    "http://cwe.mitre.org/data/definitions/601.html",
    "http://cwe.mitre.org/data/definitions/79.html"
  );

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // GOOD: the request parameter is validated against a known list of strings
    String target = request.getParameter("target");
    if (VALID_REDIRECTS.contains(target)) {
        response.sendRedirect(target);
    } else {
        response.sendRedirect("/error.html");
    }
  }
}

或者,我们可以通过检查 URL 是相对的还是在已知的良好主机上,来检查目标 URL 是否不会重定向到不同的主机

public class UrlRedirect extends HttpServlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
      String urlString = request.getParameter("page");
      URI url = new URI(urlString);

      if (!url.isAbsolute()) {
        response.sendRedirect(url.toString()); // GOOD: The redirect is to a relative URL
      }

      if ("example.org".equals(url.getHost())) {
        response.sendRedirect(url.toString()); // GOOD: The redirect is to a known host
      }
    } catch (URISyntaxException e) {
        // handle exception
    }
  }
}

请注意,按上述写法,上述代码将允许重定向到 example.com 上的 URL,这虽然无害,但可能不是预期。您可以将自己的域(如果已知)替换为 example.com 来防止这种情况。

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私