会话或Cookie混淆 [英] Session or cookie confusion

查看:749
本文介绍了会话或Cookie混淆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在某些网站上看到用户登录了他们的帐户,然后关闭了浏览器。



关闭并重新打开浏览器后,仍然登录。



但有些网站不能这样做。



我很困惑,会话或cookie?



如果我希望我的网站以这样的方式登录,我必须设置 session.setMaxInactiveInterval c $ c>或 cookie.setMaxAge()

解决方案

[PART 1]:SESSION OBJECT



HTTP请求是单独处理的,因此为了保持每个请求之间的信息(例如,关于用户的信息),必须在服务器 - 服务器上创建会话对象



一些网站根本不需要一个会话。用户不能修改任何内容的网站不必管理会话(例如,在线简历)。



建立工作阶段: >

在servlet中,使用来自HttpServletRequest对象的方法 request.getSession(true)创建一个新的HttpSession对象。请注意,如果您使用 request.getSession(false),如果尚未创建会话,将返回 null 查看此答案了解详情



设置/获取属性:



会话的目的是在每个请求之间保留服务器端的信息。例如,保留用户的名字:

  session.setAttribute(name,MAGLEFF ); 
// Cast
String name =(String)session.getAttribute(name);

销毁会话 >

如果保持非活动状态太多时间,会话将被自动销毁。 查看此答案了解详情。但是,在注销操作的情况下,您可以手动强制会话被销毁:

  HttpSession session = request.getSession(true); 
session.invalidate();

[第二部分]:所以...加入黑暗的一面,我们有COOKIES?



这里有cookies。



JSESSIONID:



每次使用请求创建会话时,都会在用户的计算机上创建 JSESSIONID cookie .getSession()。为什么?因为在服务器端创建的每个会话都有一个ID。您无法访问其他用户的会话,除非您没有正确的ID。此ID保存在JSESSIONID cookie中,并允许用户查找其信息。 有关详情,请查看此答案





JSESSIONID没有到期日期:它是一个会话cookie 。作为所有会话Cookie,当浏览器关闭时,它将被删除。如果您使用基本的JSESSIONID机制,则在关闭并重新打开浏览器之后,会话将无法访问,因为JSESSIONID cookie已删除。



请注意,会话是客户端无法访问的,但仍在服务器端运行。设置 MaxInactiveInterval 允许服务器在会话停用时间过长时自动失效。



of JSESSIONID



只是为了好玩,有一天我在项目中找到了这个代码。它用于通过使用javascript删除JSESSIONID cookie来使会话无效:

 < SCRIPT language =JavaScripttype =text / javascript> 

function delete_cookie(check_name){
//首先我们将这个cookie分成名/值对
//注意:document.cookie只返回name = value,不是其他组件
var a_all_cookies = document.cookie.split(';');
var a_temp_cookie ='';
var cookie_name ='';
var cookie_value ='';
var b_cookie_found = false; // set boolean t / f default f
// var check_name ='JSESSIONID';
var path = null;

for(i = 0; i {
//现在我们将每个名称=值对分开
a_temp_cookie = a_all_cookies [i] .split('=');
//和修剪左/右空格,当我们在它
cookie_name = a_temp_cookie [0] .replace(/ ^ \s + | \s + $ / g,'');
// alert(cookie_name);

//如果提取的名称匹配传递check_name
if(cookie_name.indexOf(check_name)> -1)
{
b_cookie_found = true;
//我们需要处理cookie没有值但存在(no = sign,也就是)的情况:
if(a_temp_cookie.length> 1)
{
cookie_value = unescape(a_temp_cookie [1] .replace(/ ^ \s + | \s + $ / g,''));
document.cookie = cookie_name +=+ cookie_value +
; path = /+
; expires = Thu,1970年1月1日00:00:01 GMT
// alert(cookie deleted+ cookie_name);
}
}
a_temp_cookie = null;
cookie_name ='';
}
return true;
}
// DESTROY
delete_cookie(JSESSIONID);

< / SCRIPT>

再看看这个答案。使用JavaScript,JSESSIONID可以读取,修改,会话丢失或被劫持。



[第3部分]:在关闭浏览器后保持会话


关闭并重新打开浏览器后,他们的帐户仍然是
登录。
但是有些网站,不能这样做。
我很困惑,它被认为是会话或cookie?


这是cookie。



我们看到当JSESSIONID会话cookie被Web浏览器删除时,服务器端的会话对象丢失。如果没有正确的ID,就无法再次访问它。


如果我希望我的网站登录,设置
session.setMaxInactiveInterval()或者cookie.setMaxAge()?


我们还看到 session.setMaxInactiveInterval()是为了防止无限期地运行丢失的会话。 JSESSIONID cookie cookie.setMaxAge()也不会让我们到任何地方。



与会话ID:



在阅读以下主题后,我来到此解决方案:





主要思想是在Map中注册用户的会话,并将其放入servlet上下文。每次创建会话时,都会将其添加到Map的JSESSIONID值为key;



当您关闭网络浏览器时,JSESSIONID会被创建为记住JSESSIONID值,以便在JSESSIONID cookie被销毁后找到会话。销毁。但是所有的HttpSession对象地址已经被保存在服务器端的一个Map中,你可以访问正确的会话,并将值保存到持久性cookie中。



在web.xml部署描述符中添加两个侦听器。

 < listener> 
< listener-class>
fr.hbonjour.strutsapp.listeners.CustomServletContextListener
< / listener-class>

< listener>
< listener-class>
fr.hbonjour.strutsapp.listeners.CustomHttpSessionListener
< / listener-class>
< / listener>

CustomServletContextListener在上下文初始化时创建映射。此地图将注册用户在此应用程序上创建的所有会话。

  / ** 
*创建一个HashMap用于保存对会话对象的引用,
*将它绑定到上下文范围。
*同时构建模拟数据库(UserDB)并将其绑定到
*上下文范围。
* @author本·苏瑟; ben@souther.us
* @since Sun May 8 18:57:10 EDT 2005
* /
public class CustomServletContextListener implements ServletContextListener {

public void contextInitialized ServletContextEvent event){
ServletContext context = event.getServletContext();

//
//实例化地图以存储对所有活动的
//会话的引用并将其绑定到上下文范围。
//
HashMap activeUsers = new HashMap();
context.setAttribute(activeUsers,activeUsers);
}

/ **
*需要ServletContextListener接口。
* /
public void contextDestroyed(ServletContextEvent event){
//为了克服在服务器重新启动期间丢失会话引用
//的问题,请将代码放在这里序列化
// activeUsers HashMap。然后将代码放在contextInitialized
//方法中,如果存在...则读取并重新加载它...
}
}

CustomHttpSessionListener在创建时会将会话放入activeUsers地图中。

  / ** 
*监听会话事件,并相应地向上下文范围的HashMap添加或删除对
*的引用。
* @author本·苏瑟; ben@souther.us
* @since Sun May 8 18:57:10 EDT 2005
* /
public class CustomHttpSessionListener实现HttpSessionListener {

public void init ServletConfig config){
}

/ **
*在上下文范围的HashMap开始时添加会话。
* /
public void sessionCreated(HttpSessionEvent event){
HttpSession session = event.getSession();
ServletContext context = session.getServletContext();
HashMap< String,HttpSession> activeUsers =(HashMap< String,HttpSession>)context.getAttribute(activeUsers);

activeUsers.put(session.getId(),session);
context.setAttribute(activeUsers,activeUsers);
}

/ **
*在上下文范围的HashMap到期时删除会话
*或无效。
* /
public void sessionDestroyed(HttpSessionEvent event){
HttpSession session = event.getSession();
ServletContext context = session.getServletContext();
HashMap< String,HttpSession> activeUsers =(HashMap< String,HttpSession>)context.getAttribute(activeUsers);
activeUsers.remove(session.getId());
}

}

使用基本表单测试用户通过名称/密码验证。

 <!DOCTYPE html PUBLIC  - // W3C // DTD HTML 4.01 Transitional // ENhttp://www.w3.org/TR/html4/loose.dtd\"> 
< html>
< head>
< meta http-equiv =Content-Typecontent =text / html; charset = ISO-8859-1>
< title>< bean:message key =formulaire1Title/>< / title&
< / head>
< body>
< form action =login.gomethod =get>
< input type =textname =username/>
< input type =passwordname =password/>
< input type =submit/>
< / form>
< / body>
< / html>

我们去。这个java servlet在用户不在会话中时转发到登录页面,而在他处于另一个页面时转发到另一个页面。它只用于测试持续会话!

  public class Servlet2 extends AbstractServlet {

@Override
protected void doGet(HttpServletRequest pRequest,
HttpServletResponse pResponse)throws IOException,ServletException {
String username =(String)pRequest.getParameter(username);
String password =(String)pRequest.getParameter(password);
//会话对象
HttpSession l_session = null;

String l_sessionCookieId = getCookieValue(pRequest,JSESSIONID);
String l_persistentCookieId = getCookieValue(pRequest,MY_SESSION_COOKIE);

//如果已创建会话cookie
if(l_sessionCookieId!= null)
{
//如果还没有持久会话cookie
if(l_persistentCookieId == null)
{
addCookie(pResponse,MY_SESSION_COOKIE,l_sessionCookieId,1800);
}
}
//如果已创建持久会话cookie
if(l_persistentCookieId!= null)
{
HashMap< String,HttpSession> l_activeUsers =(HashMap< String,HttpSession>)pRequest.getServletContext()。getAttribute(activeUsers);
//获取现有会话
l_session = l_activeUsers.get(l_persistentCookieId);
}
//否则没有创建会话
if(l_session == null)
{
//创建一个新会话
l_session = pRequest.getSession();
}

//如果用户信息在会话中,则前进到另一个页面
String forward =/pages/displayUserInfo.jsp;

//获取用户
用户user =(User)l_session.getAttribute(user);

//如果没有用户
if(user == null)
{
//将用户加入会话
if(username!= null&&& password!= null)
{
l_session.setAttribute(user,new User(username,password));
}
//再次正确登录
else
{
forward =/pages/login.jsp;
}
}
//转发
this.getServletContext()。getRequestDispatcher(forward).forward(pRequest,pResponse);

}

MY_SESSION_COOKIE cookie将保存JSESSIONID cookie的值。当JSESSIONID cookie被销毁时,MY_SESSION_COOKIE仍然存在会话ID。



JSESSIONID不在网络浏览器会话中,但我们选择使用持久和简单cookie,以及放入应用程序上下文中的所有活动会话的映射。



不要忘记BalusC提供的添加/获取/删除Cookie的有用方法:

  / ** 
*
* @author BalusC
* /
public static String getCookieValue(HttpServletRequest request,String name){
Cookie [] cookies = request.getCookies();
if(cookies!= null){
for(Cookie cookie:cookies){
if(name.equals(cookie.getName())){
return cookie.getValue ();
}
}
}
return null;
}

/ **
*
* @author BalusC
* /
public static void addCookie(HttpServletResponse response,String name, String value,int maxAge){
Cookie cookie = new Cookie(name,value);
cookie.setPath(/);
cookie.setMaxAge(maxAge);
response.addCookie(cookie);
}

/ **
*
* @author BalusC
* /
public static void removeCookie(HttpServletResponse response,String name) {
addCookie(response,name,null,0);
}

}

最后一个解决方案在本地主机,与chrome为webbrowser,在windows上。它只取决于一个单一的cookie,你不需要一个数据库。但实际上,我不知道这种机制的局限性。



THANKS

这是一个非常好的方法,

我还在学习,请告诉我,如果我的答案有任何错误。谢谢,@ +


I've seen in some websites that user signed in into their accounts and then closed the browser.

After closed and re-opened the browser and their accounts are still signed in.

But some websites, cannot do like that.

I'm confused that it's considered session or cookie?

If I want my website to be signed in like that, do I have to set session.setMaxInactiveInterval() or cookie.setMaxAge()?

解决方案

Your question is about session tracking.

[PART 1] : SESSION OBJECT

HTTP-request are processed separately, so in order to keep information between each request (for instance, information about the user), a session object has to be created on server-side.

Some websites doesn't need a session at all. A website where users can't modify any content won't have to manage a session (for instance, an online CV). You won't need any cookie or session on such a website.

Create a session :

In a servlet, use the method request.getSession(true) from the HttpServletRequest object to create a new HttpSession object. Note that if you use request.getSession(false), null will be returned if the session has not already been created. Look at this answer for more details.

Set / Get attributes :

The purpose of a session is to keep information on server-side between each request. For instance, keeping the user's name :

session.setAttribute("name","MAGLEFF");
// Cast
String name = (String) session.getAttribute("name");

Destroy a session :

A session will be automatically destroyed if kept inactive too much time. Look at this answer for more details. But you can manually force the session to be destroyed, in the case of a logout action for example :

HttpSession session = request.getSession(true); 
session.invalidate();

[PART 2] : So... join the dark side, we have COOKIES ?

Here comes the cookies.

JSESSIONID :

A JSESSIONID cookie is created on the user's computer each time a session is created with request.getSession(). Why? Because each session created on server side has an ID. You can't access another user's session, unless you don't have the right ID. This ID is kept in JSESSIONID cookie, and allow the user to find his information. Look at this answer for more details !

When does a JSESSIONID get deleted ?

JSESSIONID doesn't have an expiration date : it's a session cookie. As all session cookies, it will be deleted when the browser is closed. If you use the basic JSESSIONID mechanism, then the session will become unreachable after you close and re-open the browser, because the JSESSIONID cookie is deleted.

Note that the session is unreachable by the client, but is still running on server-side. Setting a MaxInactiveInterval allows the server to automatically invalidate the session when it has been inactive for too long.

Evil destruction of JSESSIONID

Just for fun, one day I found this code on a project. It was used to invalidate the session by deleting the JSESSIONID cookie with javascript :

<SCRIPT language="JavaScript" type="text/javascript">

    function delete_cookie( check_name ) {
        // first we'll split this cookie up into name/value pairs
        // note: document.cookie only returns name=value, not the other components
        var a_all_cookies = document.cookie.split( ';' );
        var a_temp_cookie = '';
        var cookie_name = '';
        var cookie_value = '';
        var b_cookie_found = false; // set boolean t/f default f
        // var check_name = 'JSESSIONID';
        var path = null;

        for ( i = 0; i < a_all_cookies.length; i++ )
        {
            // now we'll split apart each name=value pair
            a_temp_cookie = a_all_cookies[i].split( '=' );
            // and trim left/right whitespace while we're at it
            cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
            // alert (cookie_name);

            // if the extracted name matches passed check_name
            if ( cookie_name.indexOf(check_name) > -1 )
            {
                b_cookie_found = true;
                // we need to handle case where cookie has no value but exists (no = sign, that is):
                if ( a_temp_cookie.length > 1 )
                {
                    cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, '') );
                    document.cookie = cookie_name + "=" + cookie_value +
                    ";path=/" +
                    ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
                    // alert("cookie deleted " + cookie_name);
                }
            }
            a_temp_cookie = null;
            cookie_name = '';
        }
        return true;
    }
    // DESTROY
    delete_cookie("JSESSIONID");

</SCRIPT>

Give another look to this answer. With JavaScript, JSESSIONID can be read, modified, have it's session lost or hijacked.

[PART 3] : KEEPING A SESSION AFTER CLOSING YOUR BROWSER

After closed and re-opened the browser and their accounts are still signed in. But some websites, cannot do like that. I'm confused that it's considered session or cookie??

It's cookie.

We saw that when the JSESSIONID session cookie has been deleted by the web browser, the session object on server-side is lost. There is no way to access it again without the right ID.

If I want my website to be signed in like that, do I have to set session.setMaxInactiveInterval() or cookie.setMaxAge()?

We also saw that session.setMaxInactiveInterval() was to prevent from running a lost session indefinitely. JSESSIONID cookie cookie.setMaxAge() won't get us anywhere either.

Use a persistent cookie with the session Id :

I came to this solution after reading the following topics :

The main idea is to register the user's session in a Map, put into the servlet context. Each time a session is created, it is added to the Map with the JSESSIONID value for key; A persistent cookie is also created to memorize the JSESSIONID value, in order to find the session after the JSESSIONID cookie has been destroyed.

When you close the web browser, JSESSIONID is destroyed. But all the HttpSession objects adress have been kept into a Map on server-side, and you can access the right session with the value saved into the persistent cookie.

First, add two listeners in your web.xml deployment descriptor.

<listener>
    <listener-class>
        fr.hbonjour.strutsapp.listeners.CustomServletContextListener
    </listener-class>
</listener>

<listener>
    <listener-class>
        fr.hbonjour.strutsapp.listeners.CustomHttpSessionListener
    </listener-class>
</listener>

The CustomServletContextListener creates a map at context initialization. This map will register all the sessions created by the user on this application.

/**
 * Instanciates a HashMap for holding references to session objects, and
 * binds it to context scope.
 * Also instanciates the mock database (UserDB) and binds it to 
 * context scope.
 * @author Ben Souther; ben@souther.us
 * @since Sun May  8 18:57:10 EDT 2005
 */
public class CustomServletContextListener implements ServletContextListener{

    public void contextInitialized(ServletContextEvent event){
        ServletContext context = event.getServletContext();

        //
        // instanciate a map to store references to all the active
        // sessions and bind it to context scope.
        //
        HashMap activeUsers = new HashMap();
        context.setAttribute("activeUsers", activeUsers);
    }

    /**
     * Needed for the ServletContextListener interface.
     */
    public void contextDestroyed(ServletContextEvent event){
        // To overcome the problem with losing the session references
        // during server restarts, put code here to serialize the
        // activeUsers HashMap.  Then put code in the contextInitialized
        // method that reads and reloads it if it exists...
    }
}

The CustomHttpSessionListener will put the session into the activeUsers map when it is created.

/**
 * Listens for session events and adds or removes references to 
 * to the context scoped HashMap accordingly.
 * @author Ben Souther; ben@souther.us
 * @since Sun May  8 18:57:10 EDT 2005
 */
public class CustomHttpSessionListener implements HttpSessionListener{

    public void init(ServletConfig config){
    }

    /**
     * Adds sessions to the context scoped HashMap when they begin.
     */
    public void sessionCreated(HttpSessionEvent event){
        HttpSession    session = event.getSession();
        ServletContext context = session.getServletContext();
        HashMap<String, HttpSession> activeUsers =  (HashMap<String, HttpSession>) context.getAttribute("activeUsers");

        activeUsers.put(session.getId(), session);
        context.setAttribute("activeUsers", activeUsers);
    }

    /**
     * Removes sessions from the context scoped HashMap when they expire
     * or are invalidated.
     */
    public void sessionDestroyed(HttpSessionEvent event){
        HttpSession    session = event.getSession();
        ServletContext context = session.getServletContext();
        HashMap<String, HttpSession> activeUsers = (HashMap<String, HttpSession>)context.getAttribute("activeUsers");
        activeUsers.remove(session.getId());
    }

}

Use a basic form to test a user authentification by name/password. This login.jsp form is meant for test only.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title><bean:message key="formulaire1Title" /></title>
    </head>
    <body>
        <form action="login.go" method="get">
            <input type="text" name="username" />
            <input type="password" name="password" />
            <input type="submit" />
        </form>
    </body>
</html>

There we go. This java servlet is forwarding to a login page when the user is not in session, and to another page when he is. It is only meant for testing the persistent session!

public class Servlet2 extends AbstractServlet {

    @Override
    protected void doGet(HttpServletRequest pRequest,
            HttpServletResponse pResponse) throws IOException, ServletException {
        String username = (String) pRequest.getParameter("username");
        String password = (String) pRequest.getParameter("password");
        // Session Object
        HttpSession l_session = null;

        String l_sessionCookieId = getCookieValue(pRequest, "JSESSIONID");
        String l_persistentCookieId = getCookieValue(pRequest, "MY_SESSION_COOKIE");

        // If a session cookie has been created
        if (l_sessionCookieId != null)
        {
            // If there isn't already a persistent session cookie
            if (l_persistentCookieId == null)
            {
                addCookie(pResponse, "MY_SESSION_COOKIE", l_sessionCookieId, 1800);
            }
        }
        // If a persistent session cookie has been created
        if (l_persistentCookieId != null)
        {
            HashMap<String, HttpSession> l_activeUsers = (HashMap<String, HttpSession>) pRequest.getServletContext().getAttribute("activeUsers");
            // Get the existing session
            l_session = l_activeUsers.get(l_persistentCookieId);
        }
        // Otherwise a session has not been created
        if (l_session == null)
        {
                    // Create a new session
            l_session = pRequest.getSession();
        }

            //If the user info is in session, move forward to another page
        String forward = "/pages/displayUserInfo.jsp";

        //Get the user
        User user = (User) l_session.getAttribute("user");

        //If there's no user
        if (user == null)
        {
                    // Put the user in session
            if (username != null && password != null)
            {
                l_session.setAttribute("user", new User(username, password));
            }
                    // Ask again for proper login
            else
            {
                forward = "/pages/login.jsp";
            }
        }
        //Forward
        this.getServletContext().getRequestDispatcher(forward).forward( pRequest, pResponse );

    }

The MY_SESSION_COOKIE cookie will save the value of the JSESSIONID cookie. When the JSESSIONID cookie is destroyed, the MY_SESSION_COOKIE is still there with the session ID.

JSESSIONID is gone with the web browser session, but we chose to use a persistent and simple cookie, along with a map of all active sessions put into the application context. The persistent cookie allow us to find the right session in the map.

Don't forget these useful methods made by BalusC to add/get/remove cookies :

/**
 * 
 * @author BalusC
 */
public static String getCookieValue(HttpServletRequest request, String name) {
    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
        for (Cookie cookie : cookies) {
            if (name.equals(cookie.getName())) {
                return cookie.getValue();
            }
        }
    }
    return null;
}

/**
 * 
 * @author BalusC
 */
public static void addCookie(HttpServletResponse response, String name, String value, int maxAge) {
    Cookie cookie = new Cookie(name, value);
    cookie.setPath("/");
    cookie.setMaxAge(maxAge);
    response.addCookie(cookie);
}

/**
 * 
 * @author BalusC
 */
public static void removeCookie(HttpServletResponse response, String name) {
    addCookie(response, name, null, 0);
}

}

The last solution was tested with glassfish on localhost, with chrome for webbrowser, on windows. It only depends on a single cookie, and you don't need a database. But actually, I don't know what are the limits of such a mechanism. I only spent the night coming to this solution, without knowing if it will be a good or a bad one.

THANKS

I'm still learning, please tell me if there's any error in my answer. Thanks, @+

这篇关于会话或Cookie混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆