dromara/Sa-Token · error · SaSsoException

CODE_30015

CODE_30015

Error message

无效的 allow-url 配置(*通配符只允许出现在最后一位):{url}

What it means

Thrown by checkAllowUrlList at server startup or on first use: an entry in the client's allow-url config has a '*' wildcard somewhere other than the last character. The code comment explains why — a mid-string '*' (e.g. http://*.client1.com/sso/login) lets attacker URLs like http://sa-token.com/a.client1.com/sso/login pass suffix/contains matching, causing ticket hijacking.

Source

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

                //      sa-token.sso-server.allow-url=http://*.sa-sso-client1.com
                //
                //  开发者原意是为了允许 sa-sso-client1.com 下的所有子域名都可以下放ticket
                //      例如:http://shop.sa-sso-client1.com
                //
                //  但是如果攻击者精心构建一个url:
                //       http://sa-sso-server.com:9000/sso/auth?redirect=http://sa-token.com/a.sa-sso-client1.com/sso/login
                //
                //  那么这个 url 就会绕过 allow-url 的校验,ticket 被下发到了第三方服务器地址:
                //       http://sa-token.com/a.sa-sso-client1.com/sso/login?ticket=v2KKMUFK7dDsMMzXLQ3aWGsyGUjrA0dBB2jeOWrpCnC8b5ScmXXQSv20mIwPK7Cx
                //
                //  造成了 ticket 参数劫持
                //  所以此处需要禁止 allow-url 配置项的中间位置出现 * 字符(出现在末尾是没有问题的)
                //
                //  这么一刀切的做法,可能会导致正常场景下的子域名url也无法通过校验,例如:
                //       http://sa-sso-server.com:9000/sso/auth?redirect=http://shop.sa-sso-client1.com/sso/login
                //
                //  但是为了安全起见,这么做还是有必要的
                throw new SaSsoException("无效的 allow-url 配置(*通配符只允许出现在最后一位):" + url).setCode(SaSsoErrorCode.CODE_30015);
            }
        }
    }


    // ------------------- 单点注销 -------------------

    /**
     * 为指定账号 id 注册应用接入信息(模式三)
     *
     * @param loginId 账号id
     * @param client 指定客户端标识,可为null
     * @param sloCallbackUrl 单点注销时的回调URL
     */
    public void registerSloCallbackUrl(Object loginId, String client, String sloCallbackUrl) {
        // 如果提供的参数是空值,则直接返回,不进行任何操作
        if(SaFoxUtil.isEmpty(loginId)) {
            return;

View on GitHub (pinned to ac2c7f6e94)

Solutions

  1. Use the wildcard only as a trailing suffix, e.g. http://example.com/* — subdomain-level wildcards are intentionally not supported
  2. List each concrete subdomain explicitly: http://shop.example.com/sso/login,http://api.example.com/sso/login
  3. If many subdomains are needed, front them with one shared callback host and route internally

Example fix

# before
allow-url: http://*.example.com/sso/login   # CODE_30015

# after
allow-url: http://shop.example.com/sso/login,http://api.example.com/sso/login
Defensive patterns

Strategy: validation

Validate before calling

for(String u : allowUrlList) {
    int i = u.indexOf('*');
    if(i != -1 && i != u.length() - 1) {
        // fix config before server starts rejecting it
    }
}

Prevention

When it happens

Trigger: Configuring allow-url: http://*.example.com/sso/login (leading or middle '*') on the sso-server; the check iterates every entry and rejects the offending one.

Common situations: Admin tries to whitelist all subdomains with a leading-star pattern and hits this deliberate restriction; migrating from an older sa-token that did not validate this.

Related errors


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