URL中的;jessionid=abcdefg是如何产生的

URL中的;jessionid=abcdefg是如何产生的

前提是调用String newurl = response.encodeRedirectURL("/workbench/abc/def");,也就是用response调用encodeRedirectURL这个方法。

最终会用到org.apache.catalina.connector.Response这个类
581行:

    public String encodeRedirectURL(String url) {
        return this.isEncodeable(this.toAbsolute(url)) ? this.toEncoded(url, this.request.getSessionInternal().getIdInternal()) : url;
    }

先判断是否需要编码this.isEncodeable(this.toAbsolute(url)).
在这个方法里

    protected boolean isEncodeable(final String location) {
        if (location == null) {
            return false;
        } else if (location.startsWith("#")) {
            return false;
        } else {
            final Request hreq = this.request;
            final Session session = hreq.getSessionInternal(false);
            if (session == null) {
                return false;
            } else if (hreq.isRequestedSessionIdFromCookie()) {
                return false;
            } else if (!hreq.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.URL)) {
                return false;
            } else {
                return SecurityUtil.isPackageProtectionEnabled() ? (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                    public Boolean run() {
                        return Response.this.doIsEncodeable(hreq, session, location);
                    }
                }) : this.doIsEncodeable(hreq, session, location);
            }
        }
    }

从方法里可以看到,

  1. 判断是否有session
  2. 在request的cookie里是否找到了session
  3. 以及servelt的模型是否允允许在URL上加session

以上三个条件都不满足,下边还会进行一个判断,没仔细看,主要是看最后一行this.doIsEncodeable(hreq, session, location);

private boolean doIsEncodeable(Request hreq, Session session, String location) {
        URL url = null;

        try {
            url = new URL(location);
        } catch (MalformedURLException var10) {
            return false;
        }

        if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol())) {
            return false;
        } else if (!hreq.getServerName().equalsIgnoreCase(url.getHost())) {
            return false;
        } else {
            int serverPort = hreq.getServerPort();
            if (serverPort == -1) {
                if ("https".equals(hreq.getScheme())) {
                    serverPort = 443;
                } else {
                    serverPort = 80;
                }
            }

            int urlPort = url.getPort();
            if (urlPort == -1) {
                if ("https".equals(url.getProtocol())) {
                    urlPort = 443;
                } else {
                    urlPort = 80;
                }
            }

            if (serverPort != urlPort) {
                return false;
            } else {
                String contextPath = this.getContext().getPath();
                if (contextPath != null) {
                    String file = url.getFile();
                    if (!file.startsWith(contextPath)) {
                        return false;
                    }

                    String tok = ";" + SessionConfig.getSessionUriParamName(this.request.getContext()) + "=" + session.getIdInternal();
                    if (file.indexOf(tok, contextPath.length()) >= 0) {
                        return false;
                    }
                }

                return true;
            }
        }
    }

在这里我觉得最重要的一个就是file.startsWith(contextPath),也就是url里是否包含了servletcontext,也就是应用名,如果包含了,就会执行最下边的返回true,返回了true就会在URL的后边加上jsessionid
像这样http://localhost:8080/workbench/abc/def;jessionid=BB42488246F80CC8A7072FF3E35F3014
多了这个在一些应用里会导致问题,因为URL匹配不上造成404或者因为包含而被认为是注入或者攻击行为

解决方法:

这里以spring boot为例
在application.yml文件里添加如下

server:
  port: 8080
  servlet:
    session:
      tracking-modes: cookie

问题重现方法

@RequestMapping("/test/encodeURL")
    public String th(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession(true);
        session.setAttribute("abc", "def");

        String newurl = response.encodeRedirectURL("/workbench/abc/def");

        return newurl;
    }

请求之前先清掉cookie里的jessionid,然后在浏览器访问,就可以得到一个带;jessionid的返回URL

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值