dromara/Sa-Token · error · SaSsoException

CODE_30001

CODE_30001

Error message

无效redirect:{url}

What it means

First-stage rejection in checkRedirectUrl: the redirect value fails SaFoxUtil.isUrl(url), i.e. it is not a well-formed URL at all (no scheme, malformed host). The server validates redirect targets before handing out tickets to prevent open-redirect abuse.

Source

Thrown at sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/template/SaSsoServerTemplate.java:416

        String back = url.substring(index + length);
        back = SaFoxUtil.encodeUrl(back);

        // 放回url中
        url = url.substring(0, index + length) + back;
        return url;
    }

    /**
     * 校验重定向 url 合法性
     *
     * @param client 应用标识
     * @param url 下放ticket的url地址
     */
    public void checkRedirectUrl(String client, String url) {

        // 1、是否是一个有效的url
        if( ! SaFoxUtil.isUrl(url) ) {
            throw new SaSsoException("无效redirect:" + url).setCode(SaSsoErrorCode.CODE_30001);
        }

        // 2、截取掉?后面的部分
        int qIndex = url.indexOf("?");
        if(qIndex != -1) {
            url = url.substring(0, qIndex);
        }

        // 3、不允许出现@字符
        if(url.contains("@")) {
            //  为什么不允许出现 @ 字符呢,因为这有可能导致 redirect 参数绕过 AllowUrl 列表的校验
            //
            //  举个例子 配置文件:
            //       sa-token.sso-server.allow-url=http://sa-sso-client1.com*
            //
            //  开发者原意是为了允许 sa-sso-client1.com 下的所有地址都可以下放ticket
            //
            //  但是如果攻击者精心构建一个url:

View on GitHub (pinned to ac2c7f6e94)

Solutions

  1. Send a fully-qualified URL as redirect, e.g. http://client.com/sso/login
  2. URL-encode the redirect parameter exactly once when embedding it in the auth URL
  3. Check proxy/gateway rewrite rules are not stripping the scheme from the query string

Example fix

// before (client)
String authUrl = server + "/sso/auth?redirect=/sso/login";

// after
String authUrl = server + "/sso/auth?redirect=" + URLEncoder.encode("http://client.com/sso/login", "UTF-8");
Defensive patterns

Strategy: validation

Validate before calling

if(!SaFoxUtil.isUrl(redirect)) {
    // reject / rebuild the redirect as an absolute URL before sending to /sso/auth
}

Prevention

When it happens

Trigger: /sso/auth (mode=simple) is called with a redirect parameter like '/back' or '127.0.0.1/callback' — anything that is not a parseable absolute URL.

Common situations: Client builds the redirect from a relative path; reverse proxy rewrites the query and truncates the scheme; URL-encoding bugs mangle the parameter (e.g. http%3A%2F%2F decoded twice or not at all).

Related errors


AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14). Data as JSON: /api/errors/6f73ba5618835e22. Report an issue: GitHub.