Servlet3.0规范中的<tracking-mode>允许你定义JSESSIONID是存储在cookie中还是URL参数中。如果会话ID存储在URL中,那么它可能会被无意的存储
在多个地方,包括浏览器历史、代理服务器日志、引用日志和web日志等。暴露了会话ID使得网站被session劫持攻击的几率大增。
在用CAS做系统单点登录时,在成功的跳转后,链接会带上;jsessionid=xxx的情况,下面就是如何去掉jssessionid的方法:
1.在项目的web.xml中加上下面的配置
<session-config><session-timeout>30</session-timeout><tracking-mode>COOKIE</tracking-mode>
</session-config>
2.如果上面的方法没有解决问题,可以尝试下面的方法(html带上;jsessionid=xxx会报错,所以,要在跳转前讲;jsessionid=xxx去掉,
默认第一次访问的时候,如果session没值,就会带上;jsessionid=xxx):
public static final String cleanupUrl(final String url) { if (url == null) {return null;}final int jsessionPosition = url.indexOf(";jsession");if (jsessionPosition == -1) {return url;}final int questionMarkPosition = url.indexOf("?");if (questionMarkPosition < jsessionPosition) {return url.substring(0, url.indexOf(";jsession"));}return url.substring(0, jsessionPosition)+ url.substring(questionMarkPosition);}
default:
//return new ExternalRedirect(serviceResponse.getUrl());//注释源码
return new ExternalRedirect(UrlUtils.cleanupUrl(serviceResponse.getUrl()));//清除url中jsessionid
(注意版本的不同,但是只要找到处理链接的的文件就可以,在3.5.2的版本中,只需要修改CommonUtils的文件即可)
/*** Licensed to Jasig under one or more contributor license* agreements. See the NOTICE file distributed with this work* for additional information regarding copyright ownership.* Jasig licenses this file to you under the Apache License,* Version 2.0 (the "License"); you may not use this file* except in compliance with the License. You may obtain a* copy of the License at:** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing,* software distributed under the License is distributed on* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY* KIND, either express or implied. See the License for the* specific language governing permissions and limitations* under the License.*/package org.jasig.cas.client.util;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.jasig.cas.client.validation.ProxyList;
import org.jasig.cas.client.validation.ProxyListEditor;import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.net.URL;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.TimeZone;/*** Common utilities so that we don't need to include Commons Lang.** @author Scott Battaglia* @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep* 2007) $* @since 3.0*/
public final class CommonUtils {/** Instance of Commons Logging. */private static final Log LOG = LogFactory.getLog(CommonUtils.class);/*** Constant representing the ProxyGrantingTicket IOU Request Parameter.*/private static final String PARAM_PROXY_GRANTING_TICKET_IOU = "pgtIou";/*** Constant representing the ProxyGrantingTicket Request Parameter.*/private static final String PARAM_PROXY_GRANTING_TICKET = "pgtId";private CommonUtils() {// nothing to do}public static String formatForUtcTime(final Date date) {final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));return dateFormat.format(date);}/*** Check whether the object is null or not. If it is, throw an exception and* display the message.** @param object* the object to check.* @param message* the message to display if the object is null.*/public static void assertNotNull(final Object object, final String message) {if (object == null) {throw new IllegalArgumentException(message);}}/*** Check whether the collection is null or empty. If it is, throw an* exception and display the message.** @param c* the collecion to check.* @param message* the message to display if the object is null.*/public static void assertNotEmpty(final Collection<?> c,final String message) {assertNotNull(c, message);if (c.isEmpty()) {throw new IllegalArgumentException(message);}}/*** Assert that the statement is true, otherwise throw an exception with the* provided message.** @param cond* the codition to assert is true.* @param message* the message to display if the condition is not true.*/public static void assertTrue(final boolean cond, final String message) {if (!cond) {throw new IllegalArgumentException(message);}}/*** Determines whether the String is null or of length 0.** @param string* the string to check* @return true if its null or length of 0, false otherwise.*/public static boolean isEmpty(final String string) {return string == null || string.length() == 0;}/*** Determines if the String is not empty. A string is not empty if it is not* null and has a length > 0.** @param string* the string to check* @return true if it is not empty, false otherwise.*/public static boolean isNotEmpty(final String string) {return !isEmpty(string);}/*** Determines if a String is blank or not. A String is blank if its empty or* if it only contains spaces.** @param string* the string to check* @return true if its blank, false otherwise.*/public static boolean isBlank(final String string) {return isEmpty(string) || string.trim().length() == 0;}/*** Determines if a string is not blank. A string is not blank if it contains* at least one non-whitespace character.** @param string* the string to check.* @return true if its not blank, false otherwise.*/public static boolean isNotBlank(final String string) {return !isBlank(string);}/*** Constructs the URL to use to redirect to the CAS server.** @param casServerLoginUrl* the CAS Server login url.* @param serviceParameterName* the name of the parameter that defines the service.* @param serviceUrl* the actual service's url.* @param renew* whether we should send renew or not.* @param gateway* where we should send gateway or not.* @return the fully constructed redirect url.*/public static String constructRedirectUrl(final String casServerLoginUrl,final String serviceParameterName, final String serviceUrl,final boolean renew, final boolean gateway) {try {return casServerLoginUrl+ (casServerLoginUrl.indexOf("?") != -1 ? "&" : "?")+ serviceParameterName + "="+ URLEncoder.encode(serviceUrl, "UTF-8")+ (renew ? "&renew=true" : "")+ (gateway ? "&gateway=true" : "");} catch (final UnsupportedEncodingException e) {throw new RuntimeException(e);}}public static void readAndRespondToProxyReceptorRequest(final HttpServletRequest request,final HttpServletResponse response,final ProxyGrantingTicketStorage proxyGrantingTicketStorage)throws IOException {final String proxyGrantingTicketIou = request.getParameter(PARAM_PROXY_GRANTING_TICKET_IOU);final String proxyGrantingTicket = request.getParameter(PARAM_PROXY_GRANTING_TICKET);if (CommonUtils.isBlank(proxyGrantingTicket)|| CommonUtils.isBlank(proxyGrantingTicketIou)) {response.getWriter().write("");return;}if (LOG.isDebugEnabled()) {LOG.debug("Received proxyGrantingTicketId [" + proxyGrantingTicket+ "] for proxyGrantingTicketIou [" + proxyGrantingTicketIou+ "]");}proxyGrantingTicketStorage.save(proxyGrantingTicketIou,proxyGrantingTicket);if (LOG.isDebugEnabled()) {LOG.debug("Successfully saved proxyGrantingTicketId ["+ proxyGrantingTicket + "] for proxyGrantingTicketIou ["+ proxyGrantingTicketIou + "]");}response.getWriter().write("<?xml version=\"1.0\"?>");response.getWriter().write("<casClient:proxySuccess xmlns:casClient=\"http://www.yale.edu/tp/casClient\" />");}/*** Constructs a service url from the HttpServletRequest or from the given* serviceUrl. Prefers the serviceUrl provided if both a serviceUrl and a* serviceName.** @param request* the HttpServletRequest* @param response* the HttpServletResponse* @param service* the configured service url (this will be used if not null)* @param serverName* the server name to use to constuct the service url if the* service param is empty* @param artifactParameterName* the artifact parameter name to remove (i.e. ticket)* @param encode* whether to encode the url or not (i.e. Jsession).* @return the service url to use.*/public static String constructServiceUrl(final HttpServletRequest request,final HttpServletResponse response, final String service,final String serverName, final String artifactParameterName,final boolean encode) {if (CommonUtils.isNotBlank(service)) {return encode ? response.encodeURL(service) : service;}final StringBuilder buffer = new StringBuilder();if (!serverName.startsWith("https://")&& !serverName.startsWith("http://")) {buffer.append(request.isSecure() ? "https://" : "http://");}buffer.append(serverName);buffer.append(request.getRequestURI());if (CommonUtils.isNotBlank(request.getQueryString())) {final int location = request.getQueryString().indexOf(artifactParameterName + "=");if (location == 0) {final String returnValue = encode ? response.encodeURL(buffer.toString()) : buffer.toString();if (LOG.isDebugEnabled()) {LOG.debug("serviceUrl generated: " + returnValue);}return cleanupUrl(returnValue);}buffer.append("?");if (location == -1) {buffer.append(request.getQueryString());} else if (location > 0) {final int actualLocation = request.getQueryString().indexOf("&" + artifactParameterName + "=");if (actualLocation == -1) {buffer.append(request.getQueryString());} else if (actualLocation > 0) {buffer.append(request.getQueryString().substring(0,actualLocation));}}}final String returnValue = encode ? response.encodeURL(buffer.toString()) : buffer.toString();if (LOG.isDebugEnabled()) {LOG.debug("serviceUrl generated: " + returnValue);}return cleanupUrl(returnValue);}/*** Safe method for retrieving a parameter from the request without* disrupting the reader UNLESS the parameter actually exists in the query* string.* <p>* Note, this does not work for POST Requests for "logoutRequest". It works* for all other CAS POST requests because the parameter is ALWAYS in the* GET request.* <p>* If we see the "logoutRequest" parameter we MUST treat it as if calling* the standard request.getParameter.** @param request* the request to check.* @param parameter* the parameter to look for.* @return the value of the parameter.*/public static String safeGetParameter(final HttpServletRequest request,final String parameter) {if ("POST".equals(request.getMethod())&& "logoutRequest".equals(parameter)) {LOG.debug("safeGetParameter called on a POST HttpServletRequest for LogoutRequest. Cannot complete check safely. Reverting to standard behavior for this Parameter");return request.getParameter(parameter);}return request.getQueryString() == null|| request.getQueryString().indexOf(parameter) == -1 ? null: request.getParameter(parameter);}/*** Contacts the remote URL and returns the response.** @param constructedUrl* the url to contact.* @param encoding* the encoding to use.* @return the response.*/public static String getResponseFromServer(final URL constructedUrl,final String encoding) {return getResponseFromServer(constructedUrl,HttpsURLConnection.getDefaultHostnameVerifier(), encoding);}/*** Contacts the remote URL and returns the response.** @param constructedUrl* the url to contact.* @param hostnameVerifier* Host name verifier to use for HTTPS connections.* @param encoding* the encoding to use.* @return the response.*/public static String getResponseFromServer(final URL constructedUrl,final HostnameVerifier hostnameVerifier, final String encoding) {URLConnection conn = null;try {conn = constructedUrl.openConnection();if (conn instanceof HttpsURLConnection) {((HttpsURLConnection) conn).setHostnameVerifier(hostnameVerifier);}final BufferedReader in;if (CommonUtils.isEmpty(encoding)) {in = new BufferedReader(new InputStreamReader(conn.getInputStream()));} else {in = new BufferedReader(new InputStreamReader(conn.getInputStream(), encoding));}String line;final StringBuilder stringBuffer = new StringBuilder(255);while ((line = in.readLine()) != null) {stringBuffer.append(line);stringBuffer.append("\n");}return stringBuffer.toString();} catch (final Exception e) {LOG.error(e.getMessage(), e);throw new RuntimeException(e);} finally {if (conn != null && conn instanceof HttpURLConnection) {((HttpURLConnection) conn).disconnect();}}}/*** Contacts the remote URL and returns the response.** @param url* the url to contact.* @param encoding* the encoding to use.* @return the response.*/public static String getResponseFromServer(final String url, String encoding) {try {return getResponseFromServer(new URL(url), encoding);} catch (final MalformedURLException e) {throw new IllegalArgumentException(e);}}public static ProxyList createProxyList(final String proxies) {if (CommonUtils.isBlank(proxies)) {return new ProxyList();}final ProxyListEditor editor = new ProxyListEditor();editor.setAsText(proxies);return (ProxyList) editor.getValue();}/*** Sends the redirect message and captures the exceptions that we can't* possibly do anything with.** @param response* the HttpServletResponse. CANNOT be NULL.* @param url* the url to redirect to.*/public static void sendRedirect(final HttpServletResponse response,final String url) {try {response.sendRedirect(url);} catch (final Exception e) {LOG.warn(e.getMessage(), e);}}/*** cleanup jsessionid* * @param url* @return*/public static final String cleanupUrl(final String url) {if (url == null) {return null;}final int jsessionPosition = url.indexOf(";jsessionid");if (jsessionPosition == -1) {return url;}final int questionMarkPosition = url.indexOf("?");if (questionMarkPosition < jsessionPosition) {return url.substring(0, url.indexOf(";jsessionid"));}return url.substring(0, jsessionPosition)+ url.substring(questionMarkPosition);}
}