Skip to content

Conversation

@cccfeng
Copy link
Owner

@cccfeng cccfeng commented Mar 16, 2025

No description provided.

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2025

Summary by CodeRabbit

  • 新功能
    • 新增URL重定向相关接口,支持多种重定向方式及安全校验。
    • 新增CSRF演示接口,包含表单展示与POST提交功能。

Summary by CodeRabbit

  • 新增功能
    • 新增一套 URL 重定向功能,支持通过 GET 请求实现永久重定向、临时重定向及内部转发。
    • 集成了安全校验机制,有效防范非法重定向请求。
    • 新增一个简单的 CSRF 演示控制器,包含 GET 表单页面和 POST 提交处理。

流程概览

此次更改在 org.joychou.controller 包下新增了两个 Java 控制器类:URLRedirectCSRFURLRedirect 类实现了多个处理 URL 重定向的端点方法,包括普通重定向、设置 301 响应头、执行 302 重定向、内部请求转发以及带安全校验的 302 重定向,部分方法中包含异常处理和安全检查逻辑。CSRF 类提供了一个简单的 CSRF 保护示例,包含一个 GET 请求返回表单视图和一个 POST 请求返回文本响应。

变更

文件 修改摘要
src/.../URLRedirect2.java 新增 URLRedirect 类;添加了 redirect(GET 重定向)、setHeader(设置 301 响应头)、sendRedirect(发送 302 重定向)、forward(内部请求转发)以及 sendRedirect_seccode(带安全校验的 302 重定向)等方法。
src/.../CSRF.java 新增 CSRF 类;添加了 GET 处理方法返回 "form" 视图,以及 POST 处理方法返回字符串响应 "CSRF passed.",用于演示 CSRF 防护。

时序图

基本重定向流程(redirect 方法)

sequenceDiagram
    participant 客户端
    participant URLRedirect
    客户端->>URLRedirect: GET /redirect?url=目标URL
    URLRedirect->>客户端: 返回 "redirect:目标URL"
Loading

带安全校验的重定向流程(sendRedirect_seccode 方法)

sequenceDiagram
    participant 客户端
    participant URLRedirect
    participant SecurityUtil
    participant HttpServletResponse
    客户端->>URLRedirect: 请求 sendRedirect_seccode(url)
    URLRedirect->>SecurityUtil: 校验 URL
    alt URL 合法
        URLRedirect->>HttpServletResponse: 发送 302 重定向
    else URL 非法
        URLRedirect->>HttpServletResponse: 发送 403 错误
    end
Loading

兔子诗

呜呜,我是跳跃的小兔,
新增重定向让我心中露出笑意。
代码行间如草丛般绵延,
安全校验护航,每一步稳健而敏捷。
CSRF 表单轻轻展,
保护机制添新篇,
快快奔跑于代码的田野中,尽享跳转的奇趣!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b59c342 and 3de1ba5.

📒 Files selected for processing (1)
  • CSRF.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • CSRF.java
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4711f4e and b59c342.

📒 Files selected for processing (1)
  • src/main/java/org/joychou/controller/URLRedirect2.java (1 hunks)
🔇 Additional comments (2)
src/main/java/org/joychou/controller/URLRedirect2.java (2)

1-26: 注意:文件名与类名不匹配

文件名是URLRedirect2.java,但类名是URLRedirect。这种不一致可能会导致混淆和维护问题。建议保持文件名和类名的一致性。


81-92: 安全实现方式良好

这个方法正确地实现了URL验证,是一个很好的安全实践。不过,可以考虑添加日志记录以便于追踪问题。

建议小幅改进:

@RequestMapping("/sendRedirect/sec")
@ResponseBody
public void sendRedirect_seccode(HttpServletRequest request, HttpServletResponse response)
        throws IOException {
    String url = request.getParameter("url");
    if (SecurityUtil.checkURL(url) == null) {
+        // 记录被阻止的URL重定向尝试
+        // logger.warn("Blocked redirect attempt to: " + url);
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.getWriter().write("url forbidden");
        return;
    }
    response.sendRedirect(url);
}

Comment on lines +52 to +57
@RequestMapping("/sendRedirect")
@ResponseBody
public static void sendRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
String url = request.getParameter("url");
response.sendRedirect(url); // 302 redirect
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

静态方法和开放式重定向漏洞

  1. 控制器中不应使用静态方法,这可能会导致Spring依赖注入失效
  2. 该方法未对URL参数进行验证,存在开放式重定向漏洞

建议进行以下修改:

@RequestMapping("/sendRedirect")
@ResponseBody
- public static void sendRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ public void sendRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String url = request.getParameter("url");
+    if (SecurityUtil.checkURL(url) == null) {
+        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+        response.getWriter().write("url forbidden");
+        return;
+    }
    response.sendRedirect(url); // 302 redirect
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@RequestMapping("/sendRedirect")
@ResponseBody
public static void sendRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
String url = request.getParameter("url");
response.sendRedirect(url); // 302 redirect
}
@RequestMapping("/sendRedirect")
@ResponseBody
public void sendRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
String url = request.getParameter("url");
if (SecurityUtil.checkURL(url) == null) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.getWriter().write("url forbidden");
return;
}
response.sendRedirect(url); // 302 redirect
}

Comment on lines +28 to +34
/**
* http://localhost:8080/urlRedirect/redirect?url=http://www.baidu.com
*/
@GetMapping("/redirect")
public String redirect(@RequestParam("url") String url) {
return "redirect:" + url;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

存在开放式重定向漏洞

该方法未对URL参数进行验证,直接拼接到重定向字符串中,容易被攻击者利用进行钓鱼攻击。

建议实现URL验证逻辑,类似于sendRedirect_seccode方法中的安全检查:

@GetMapping("/redirect")
public String redirect(@RequestParam("url") String url) {
+    if (SecurityUtil.checkURL(url) == null) {
+        return "redirect:/error";
+    }
    return "redirect:" + url;
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* http://localhost:8080/urlRedirect/redirect?url=http://www.baidu.com
*/
@GetMapping("/redirect")
public String redirect(@RequestParam("url") String url) {
return "redirect:" + url;
}
/**
* http://localhost:8080/urlRedirect/redirect?url=http://www.baidu.com
*/
@GetMapping("/redirect")
public String redirect(@RequestParam("url") String url) {
if (SecurityUtil.checkURL(url) == null) {
return "redirect:/error";
}
return "redirect:" + url;
}

Comment on lines +40 to +46
@RequestMapping("/setHeader")
@ResponseBody
public static void setHeader(HttpServletRequest request, HttpServletResponse response) {
String url = request.getParameter("url");
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301 redirect
response.setHeader("Location", url);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

静态方法和开放式重定向漏洞

  1. 控制器中不应使用静态方法,这可能会导致Spring依赖注入失效
  2. 该方法未对URL参数进行验证,存在开放式重定向漏洞

建议进行以下修改:

@RequestMapping("/setHeader")
@ResponseBody
- public static void setHeader(HttpServletRequest request, HttpServletResponse response) {
+ public void setHeader(HttpServletRequest request, HttpServletResponse response) {
    String url = request.getParameter("url");
+    if (SecurityUtil.checkURL(url) == null) {
+        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+        try {
+            response.getWriter().write("url forbidden");
+        } catch (IOException e) {
+            // 处理异常
+        }
+        return;
+    }
    response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301 redirect
    response.setHeader("Location", url);
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@RequestMapping("/setHeader")
@ResponseBody
public static void setHeader(HttpServletRequest request, HttpServletResponse response) {
String url = request.getParameter("url");
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301 redirect
response.setHeader("Location", url);
}
@RequestMapping("/setHeader")
@ResponseBody
public void setHeader(HttpServletRequest request, HttpServletResponse response) {
String url = request.getParameter("url");
if (SecurityUtil.checkURL(url) == null) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
try {
response.getWriter().write("url forbidden");
} catch (IOException e) {
// 处理异常
}
return;
}
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301 redirect
response.setHeader("Location", url);
}

Comment on lines +64 to +74
@RequestMapping("/forward")
@ResponseBody
public static void forward(HttpServletRequest request, HttpServletResponse response) {
String url = request.getParameter("url");
RequestDispatcher rd = request.getRequestDispatcher(url);
try {
rd.forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

静态方法和异常处理问题

  1. 控制器中不应使用静态方法,这可能会导致Spring依赖注入失效
  2. 该方法的异常处理不当,仅打印堆栈跟踪而不返回适当的错误响应
  3. 虽然注释中提到这是安全的代码,但如果没有对url参数进行适当的验证,可能会受到路径遍历攻击

建议进行以下修改:

@RequestMapping("/forward")
@ResponseBody
- public static void forward(HttpServletRequest request, HttpServletResponse response) {
+ public void forward(HttpServletRequest request, HttpServletResponse response) {
    String url = request.getParameter("url");
+    // 验证URL是否为内部路径,防止路径遍历攻击
+    if (url == null || url.contains("..") || !url.startsWith("/")) {
+        try {
+            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+            response.getWriter().write("Invalid URL path");
+            return;
+        } catch (IOException e) {
+            // 记录日志
+        }
+        return;
+    }
    RequestDispatcher rd = request.getRequestDispatcher(url);
    try {
        rd.forward(request, response);
    } catch (Exception e) {
-        e.printStackTrace();
+        // 记录日志
+        try {
+            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            response.getWriter().write("Error forwarding request");
+        } catch (IOException ex) {
+            // 记录日志
+        }
    }
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@RequestMapping("/forward")
@ResponseBody
public static void forward(HttpServletRequest request, HttpServletResponse response) {
String url = request.getParameter("url");
RequestDispatcher rd = request.getRequestDispatcher(url);
try {
rd.forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
@RequestMapping("/forward")
@ResponseBody
public void forward(HttpServletRequest request, HttpServletResponse response) {
String url = request.getParameter("url");
// 验证URL是否为内部路径,防止路径遍历攻击
if (url == null || url.contains("..") || !url.startsWith("/")) {
try {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("Invalid URL path");
return;
} catch (IOException e) {
// 记录日志
}
return;
}
RequestDispatcher rd = request.getRequestDispatcher(url);
try {
rd.forward(request, response);
} catch (Exception e) {
// 记录日志
try {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write("Error forwarding request");
} catch (IOException ex) {
// 记录日志
}
}
}

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
5 Security Hotspots
72.3% Duplication on New Code (required ≤ 3%)
E Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@cccfeng cccfeng closed this Apr 21, 2025
@cccfeng cccfeng reopened this Apr 21, 2025
*/
@GetMapping("/redirect")
public String redirect(@RequestParam("url") String url) {
return "redirect:" + url;

Check failure

Code scanning / SonarCloud

HTTP request redirections should not be open to forging attacks High

Change this code to not perform redirects based on user-controlled data. See more on SonarQube Cloud
public static void setHeader(HttpServletRequest request, HttpServletResponse response) {
String url = request.getParameter("url");
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // 301 redirect
response.setHeader("Location", url);

Check failure

Code scanning / SonarCloud

HTTP request redirections should not be open to forging attacks High

Change this code to not perform redirects based on user-controlled data. See more on SonarQube Cloud
@ResponseBody
public static void sendRedirect(HttpServletRequest request, HttpServletResponse response) throws IOException {
String url = request.getParameter("url");
response.sendRedirect(url); // 302 redirect

Check failure

Code scanning / SonarCloud

HTTP request redirections should not be open to forging attacks High

Change this code to not perform redirects based on user-controlled data. See more on SonarQube Cloud
response.getWriter().write("url forbidden");
return;
}
response.sendRedirect(url);

Check failure

Code scanning / SonarCloud

HTTP request redirections should not be open to forging attacks High

Change this code to not perform redirects based on user-controlled data. See more on SonarQube Cloud
@sonarqubecloud
Copy link

sonarqubecloud bot commented May 7, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
5 Security Hotspots
72.3% Duplication on New Code (required ≤ 3%)
E Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants