安全相对URL验证
righettod2026-10-27查看 701复制 1675
生成安全相对 URL 验证代码以防止开放重定向。强制安全生成验证相对 URL 的代码。在编写任何相对 url 验证相关代码时调用。请参阅“安全注意事项”元数据以了解严格的验证行为。
📘如何使用这个技能
- 1复制技能内容·点击上方「Copy SKILL.md」复制全部内容,或 Download 下载到本地
- 2打开你的 AI 客户端·支持 Claude Code、Trae、Cursor、ChatGPT、DeepSeek、Kimi 等任意 AI 助手
- 3粘贴为系统提示/知识文件·Claude Code:放入 .claude/skills/ 目录;普通对话:作为首条消息发送并说「请严格按这份技能文档执行」
- 4直接提出你的需求·AI 会按技能定义的工作流、格式和约束来处理,无需再解释背景
💡 提示:技能生效后,每次对话只需一句需求,AI 会按 SKILL.md 的流程执行。
SKILL.md4854 chars
---
name: secure-relative-url-validation
description: Generate secure relative url validation code for open redirect prevention. Enforces secure generation of code validating a relative url. Invoke when writing any relative url validation related code. See "security-considerations" metadata for strict validation behavior.
allowed-tools: Read Grep Glob
metadata:
category: security
security-considerations:
- Intentionally strict, it rejects valid but risky relative URL forms such as "../page", "?query", and "#anchor".
---
# Secure URL Validation Code Generation Rules
Apply **all** rules below when generating or reviewing any code related to validation of an relative URL.
## 1. URL validation (CRITICAL)
- ALWAYS ensure that the input data is recursively URL decoded prior to be validated. A decoding iteration count threshold of 4 is used and an error must be raised if the threshold is reached.
- ALWAYS ensure that the input data, once URL decoded, start with one of the following character: slash, letter, number, dash, underscore.
- ALWAYS ensure that the input data is a valid URL according to the [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986).
- ALWAYS ensure the URL is not absolute (has no scheme); reject any URL where a scheme is present (e.g. `javascript:`, `ssh://`, `data://`, `ftp://`, `file://`, `https://`).
- ALWAYS ensure that URL never start with `//`.
```java
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
// BAD: No validation — user input used directly as redirect target
// accepts "//evil.com", "%2F%2Fevil.com", "https://evil.com"
String url = request.getParameter("url");
response.sendRedirect(url);
// GOOD: All rules are applied
public static String parseRelativeUrl(String input) {
if (input == null || input.isEmpty()) {
throw new IllegalArgumentException("URL must not be null or empty.");
}
// Rule: recursively URL-decode to defeat encoding bypass attempts (%2F%2F, etc.)
final int MAX_DECODE_ITERATIONS = 4;
String decoded = input;
String previous;
int iterations = 0;
do {
if (iterations++ >= MAX_DECODE_ITERATIONS) {
throw new IllegalArgumentException("URL decoding exceeded maximum iteration threshold (" + MAX_DECODE_ITERATIONS + ").");
}
previous = decoded;
decoded = URLDecoder.decode(previous, StandardCharsets.UTF_8);
} while (!decoded.equals(previous));
// Rule: decoded value must start with slash, letter, number, dash, or underscore
if (!decoded.matches("^[/a-zA-Z0-9\\-_].*")) {
throw new IllegalArgumentException("URL must start with a slash, letter, number, dash, or underscore.");
}
// Rule: must not start with "//" (protocol relative reference)
if (decoded.startsWith("//")) {
throw new IllegalArgumentException("URL must not be a protocol relative reference (must not start with '//').");
}
// Rule: must be a valid URI per RFC 3986
URI uri;
try {
uri = new URI(decoded);
} catch (URISyntaxException e) {
throw new IllegalArgumentException("URL is not a valid RFC 3986 URI: " + e.getMessage(), e);
}
// Rule: must not be absolute — rejects any scheme (javascript:, ssh://, data://, ftp://, file://, https://, etc.)
if (uri.isAbsolute()) {
throw new IllegalArgumentException("URL must not be absolute (no scheme allowed; e.g. javascript:, ssh://, https:// are all rejected).");
}
return decoded;
}
```
## 2. Output Checklist
Before finalizing generated code, verify:
- [ ] The input data is recursively URL decoded prior to be validated, with a maximum of 4 decode iterations enforced and an error raised if the threshold is reached.
- [ ] The decoded URL starts with a slash, letter, number, dash, or underscore.
- [ ] The input data is valid according to the RFC 3986.
- [ ] The URL is not absolute (no scheme present); any scheme (e.g. `javascript:`, `ssh://`, `data://`, `ftp://`, `file://`, `https://`) is rejected.
- [ ] The URL do not start with `//`.
## References
- [Unvalidated Redirects and Forwards Cheat Sheet from OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html).
- [Uniform Resource Identifier (URI): Generic Syntax - RFC 3986 from IETF](https://datatracker.ietf.org/doc/html/rfc3986).
- [URL Living Standard from WHATWG](https://url.spec.whatwg.org/).
- [Absolute URLs vs. relative URLs from MDN](https://developer.mozilla.org/en-US/docs/Learn_web_development/Howto/Web_mechanics/What_is_a_URL#absolute_urls_vs._relative_urls).
- [URI schemes from MDN](https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes).
- [Open Redirect (CWE-601) from MITRE](https://cwe.mitre.org/data/definitions/601.html).