精华内容
下载资源
问答
  • cookie和session

    2018-05-03 16:30:24
    cookie和session

    cookie

    cookie:客户端浏览器上的一个文件(键值对方式存储,类似于python中的字典),一般用于记录用户状态、和用户信息的,绝大多数的网站自动登录功能都是基于cookie实现的,下面使用Django实现一个用户登陆作为例子展示。

    首先是最简单的登录页面 login:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="/login/" method="post">
        <input type="text" name="username" placeholder="用户名">
        <input type="password" name="password" placeholder="密码">
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    login请求处理函数
    user_infp ={
        "fml":{"password":"123"}
    }
    
    def login(request):
        if request.method == "GET":
            return  render(request,"login.html")
        if request.method == "POST":
            u = request.POST.get("username")
            p = request.POST.get("password")
            dic = user_infp.get(u)
            if not dic:
                return render(request,"login.html")
            if dic["password"] == p:
                res = redirect('/index')
                res.set_cookie("username",u)
                return res
            else:
                return render(request,"login.html")
    当请求为get方式的时候返回登录页面,为post方式的时候验证表单,这里只使用字典来简化从数据库验证的操作。当验证通过的时候跳转到index页面,并且设置一个cookie,内容为{"username":username},否则任然返回当前页面。

    index页面:仅仅用来显示登录的用户名

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>欢迎{{ user }}</h1>
    </body>
    </html>

    index处理函数:

    def index(request):
        user = request.COOKIES.get("username")
        if not user:
            return redirect('/login')
        else:
            return render(request,'index.html',{"user":user})
    如果上面我们如果登录成功浏览器会存储一个cookie,当我们再次请求index页面的时候,同时发送过去的还有本地的cookie,所以可以从request中的cookie中获取我们已经存储的用户名,如果不存在则跳转到login页面,如果有登录信息则显示登录页面

    以上是最简单的cookie使用,其实cookie还有很多其他的用法

    rep = HttpResponse(...) 或 rep = render(request, ...)
     
    rep.set_cookie(key,value,...)
    rep.set_signed_cookie(key,value,salt='加密盐',...)
        参数:
            key,              键
            value='',         值
            max_age=None,     超时时间
            expires=None,     超时时间(IE requires expires, so set it if hasn't been already.)
            path='/',         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
            domain=None,      Cookie生效的域名
            secure=False,     https传输
            httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)



    下面再来详细说一说各个参数的作用。
    首先是获取cookie,salt:这个参数的具体作用目前我还是不太清除,猜测是cookie加密操作,等我弄懂了再回来修改。

    接下来是设置cookie,key和value不用再说了,
    max_age:设置超时时间以秒为单位,很多网站上登录页面都有多长时间免登录的功能一般都是通过这个来设置的,当超过了一段时间这个cookie就会失效
    expires: 同样是设置超时时间的,但是和上面的不太一样,这里的单位不是秒,而是datetime,所以就有两种超时时间的设置方法

    #max_age方法
    res.set_cookie("username",u,max_age=10)
    #expires方法
    import datetime
    current_time = datetime.datetime.utcnow()
    end_time = current_time + datetime.timedelta(seconds=10)
    res.set_cookie("username",u,expires=end_time)
    path:是指定cookie生效的路径,参数默认为 ' / ' 可被当前网站任意URL页面访问,下面我们重新写一个页面index1,内容和index相同
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>这里是index1欢迎{{ user }}</h1>
    </body>
    </html>
    index1 的处理函数
    def index1(request):
        user = request.COOKIES.get("username")
        if not user:
            return HttpResponse("没有获取到cookie")
        else:
            return render(request,"index1.html",{"user":user})


    这里我们将login函数里面的cookie设置为
    res.set_cookie("username",u,path='/index')
    然后重新运行登录,这里就能看出在index可以正常获取到cookie,而index1获取不到,path设置成功。

    domain:设置生效域名,这里只能设置当前域名的子域名,无法给其他域名设置

    session

    和cookie不同的是session是保存在服务器端的键值对,session基于cookie来使用的,一般情况下本地的cookie会存储session中的key名,然后通过cookie中的key去获取服务器上存储的信息。
    下面依然以用户登录作为最简单的示例:
    模板还是上面的那两个,这里只重写对应的处理函数
    user_infp ={
        "fml":{"password":"123"}
    }
    
    def login(request):
        if request.method == "GET":
            return  render(request,"login.html")
        if request.method == "POST":
            u = request.POST.get("username")
            p = request.POST.get("password")
            dic = user_infp.get(u)
            if not dic:
                return render(request,"login.html")
            if dic["password"] == p:
                res = redirect('/index')
                request.session['username'] = u
                request.session["is_login"] = True
                return res
            else:
                return render(request,"login.html")
    
    def index(request):
        print(request.session["is_login"])
        if request.session["is_login"]:
            return render(request, 'index.html', {"user": request.session["username"]})
        else:
            return redirect('/login')
    乍一看和cookie的操作类似,其实这是因为django为我们在后台做了很多工作,例如
    request.session['username'] = u
    request.session["is_login"] = True
    这两句就很简单的完成了session的创建,实际上django首先生成了一串随机字符串用来作为key并将这个随机字符串保存到本地的cookie中,然后在将后面的两个内容以字典的形式存到服务器端,django中默认session存储在数据库中。

    request.session["is_login"]:
    这一步首先从cookie中回去对应的key,然后再从数据库中获取对应的value进行判断
    同样的session和cookie一样也有一些高级功能,例如设置超时时间
    request.session.set_expiry(value)
                * 如果value是个整数,session会在些秒数后失效。
                * 如果value是个datatime或timedelta,session就会在这个时间后失效。
                * 如果value是0,用户关闭浏览器session就会失效。
                * 如果value是None,session会依赖全局session失效策略。

    除了超时时间设置还有一下功能:

            # 获取、设置、删除Session中数据
            request.session['k1']
            request.session.get('k1',None)
            request.session['k1'] = 123
            request.session.setdefault('k1',123) # 存在则不设置
            del request.session['k1']
     
            # 所有 键、值、键值对
            request.session.keys()
            request.session.values()
            request.session.items()
            request.session.iterkeys()
            request.session.itervalues()
            request.session.iteritems()
     
     
            # 用户session的随机字符串
            request.session.session_key
     
            # 将所有Session失效日期小于当前日期的数据删除
            request.session.clear_expired()
     
            # 检查 用户session的随机字符串 在数据库中是否
            request.session.exists("session_key")
     
            # 删除当前用户的所有Session数据
            request.session.delete("session_key")

    在django中session共有5种方式来存储:数据库、缓存、文件、缓存加数据库、加密cookie,但是都需要我们在settings里面设置,下面就是每种的配置方式

    #数据库配置
    
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'  # 引擎(默认)
    
    SESSION_COOKIE_NAME = "sessionid"  # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/"  # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None  # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False  # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True  # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600  # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否关闭浏览器使得Session过期(默认)
    SESSION_SAVE_EVERY_REQUEST = False  # 是否每次请求都保存Session,默认修改之后才保存(默认)
    
    #缓存配置
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    SESSION_CACHE_ALIAS = 'default'  # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
    
    SESSION_COOKIE_NAME = "sessionid"  # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    SESSION_COOKIE_PATH = "/"  # Session的cookie保存的路径
    SESSION_COOKIE_DOMAIN = None  # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False  # 是否Https传输cookie
    SESSION_COOKIE_HTTPONLY = True  # 是否Session的cookie只支持http传输
    SESSION_COOKIE_AGE = 1209600  # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否关闭浏览器使得Session过期
    SESSION_SAVE_EVERY_REQUEST = False  # 是否每次请求都保存Session,默认修改之后才保存
    
    #文件配置
    SESSION_ENGINE = 'django.contrib.sessions.backends.file'  # 引擎
    SESSION_FILE_PATH = None  # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()                                                            # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
    
    SESSION_COOKIE_NAME = "sessionid"  # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    SESSION_COOKIE_PATH = "/"  # Session的cookie保存的路径
    SESSION_COOKIE_DOMAIN = None  # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False  # 是否Https传输cookie
    SESSION_COOKIE_HTTPONLY = True  # 是否Session的cookie只支持http传输
    SESSION_COOKIE_AGE = 1209600  # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否关闭浏览器使得Session过期
    SESSION_SAVE_EVERY_REQUEST = False  # 是否每次请求都保存Session,默认修改之后才保存
    
    #缓存加数据库(数据库实现持久化,缓存提高效率)
    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎
    
    #加密Cookie
    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎








    展开全文
  • Cookie和Session

    2019-06-02 20:21:50
    Cookie和Session的区别: Cookie和Session都是会话技术,Cookie是运行在客户端,Session是运行在服务器端。 Cookie有大小限制以及浏览器在存cookie的个数也有限制,Session是没有大小限制和服务器的内存大小有关...

    Cookie和Session的区别:

    1. Cookie和Session都是会话技术,Cookie是运行在客户端,Session是运行在服务器端。

    2. Cookie有大小限制以及浏览器在存cookie的个数也有限制,Session是没有大小限制和服务器的内存大小有关。

    3. Cookie有安全隐患,通过拦截或本地文件找得到你的cookie后可以进行攻击。

    4. Session是保存在服务器端上会存在一段时间才会消失,如果session过多会增加服务器的压力。

    Cookie和Session的使用:

    // 初始化session,使用前必须写
    
    session_start();
    
    //销毁删除
    
    unset($_SESSION['username']);
    
    //删除数组中的所有内容,session文件中的内容清空了
    
    $_SESSION = array();
    $_SESSION = [];
    
    //session文件删除
    
    session_destroy();
    
    //删除客户端的cookie
    
    if (isset($_COOKIE[session_name()])){
        setcookie(session_name(),'',time()-1,'/');
    }
    
    //存储
    
    $_SESSION['username']='username';
    
    // 获取
    
    echo $_SESSION['username'];
    
    print_r($_SESSION['loves']);
    
    echo $_SESSION['lianxi']['phone'];
    
    
    
    展开全文
  • Cookie Session

    千次阅读 2021-01-13 11:17:52
    Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。 Cookie最早是网景公司的前雇员Lou Montulli在1993年3月的发明。Cookie是由...

    一、Cookie

    Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。


    Cookie最早是网景公司的前雇员Lou Montulli在1993年3月的发明。Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie名称和值可以由服务器端开发自己定义,这样服务器可以知道该用户是否是合法用户以及是否需要重新登录等。服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cookies最典型记住用户名。
    Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用。

    Cookie的特点

    • Cookie以键值对Key-Value形势进行信息的存储。
    • Cookie基于域名安全,不同域名的Cookie是不能互相访问的

    1 设置Cookie

    可以通过HttpResponse对象中的set_cookie方法来设置cookie。

    HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)
    
    • max_age 单位为秒,默认为None。如果是临时cookie,可将max_age设置为None。

    2 读取Cookie

    可以通过HttpRequest对象的COOKIES属性来读取本次请求携带的cookie值。request.COOKIES为字典类型

    二、Session

    Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session
    对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session
    对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web
    服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。Session
    对象最常见的一个用法就是存储用户的首选项。

    1. Session 的作用

    Session 的作用就是它在 Web服务器上保持用户的状态信息供在任何时间从任何设备上的页面进行访问。因为浏览器不需要存储任何这种信息,所以可以使用任何浏览器,即使是像 Pad 或手机这样的浏览器设备。

    保持会话状态!

    2. Session的特点

    • 依赖cookies
    • 存储敏感、重要的信息
    • 支持更多字节
    • Session共享问题

    3. Session配置和存储

    3.1 启用Session

    Django项目默认启用Session

    可以在settings.py文件中查看,如图所示
    在这里插入图片描述

    如需禁用session,将上图中的session中间件注释掉即可。

    3.2 存储方式

    在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等。

    3.2.1 数据库

    存储在数据库中,如下设置可以写,也可以不写,这是默认存储方式

    SESSION_ENGINE='django.contrib.sessions.backends.db'
    

    如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用。
    在这里插入图片描述

    数据库中的表如图所示

    session数据库

    表结构如下

    session表结构

    由表结构可知,操作Session包括三个数据:键,值,过期时间。

    3.2.2 本地缓存

    存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。

    SESSION_ENGINE='django.contrib.sessions.backends.cache'
    

    3.2.3 混合存储

    优先从本机内存中存取,如果没有则从数据库中存取。

    SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
    

    3.2.4 Redis

    在redis中保存session,需要引入第三方扩展,我们可以使用django-redis来解决。

    1) 安装扩展

    pip install django-redis
    

    2)配置

    在settings.py文件中做如下设置

    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379/1",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
            }
        }
    }
    SESSION_ENGINE = "django.contrib.sessions.backends.cache"
    SESSION_CACHE_ALIAS = "default"
    

    注意
    如果redis的ip地址不是本地回环127.0.0.1,而是其他地址,访问Django时,可能出现Redis连接错误,如下:

    redis连接错误

    解决方法:

    修改redis的配置文件,添加特定ip地址。

    打开redis的配置文件

    sudo vim /etc/redis/redis.conf
    

    在如下配置项进行修改(如要添加10.211.55.5地址)

    修改redis配置文件

    重新启动redis服务

    sudo service redis-server restart
    

    4、Session操作

    通过HttpRequest对象的session属性进行会话的读写操作。

    1) 以键值对的格式写session。

    request.session['键']=

    2)根据键读取值。

    request.session.get('键',默认值)
    

    3)清除所有session,在存储中删除值部分。

    request.session.clear()
    

    4)清除session数据,在存储中删除session的整条数据。

    request.session.flush()
    

    5)删除session中的指定键及值,在存储中只删除某个键及对应的值。

    del request.session['键']
    

    6)设置session的有效期

    request.session.set_expiry(value)
    
    • 如果value是一个整数,session将在value秒没有活动后过期。
    • 如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。
    • 如果value为None,那么session有效期将采用系统默认值,默认为两周,可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。
    展开全文
  • cookie session

    2015-01-30 16:49:07
    cookie session 众所周知,HTTP 是一个无状态协议,所以客户端每次发出请求时,下一次请求无法得知上一次请求所包含的状态数据,如何能把一个用户的状态数据关联起来呢? 比如在淘宝的某个页面中,你进行...

    转载来源于:https://github.com/alsotang/node-lessons/tree/master/lesson16


    cookie 和 session

    众所周知,HTTP 是一个无状态协议,所以客户端每次发出请求时,下一次请求无法得知上一次请求所包含的状态数据,如何能把一个用户的状态数据关联起来呢?

    比如在淘宝的某个页面中,你进行了登陆操作。当你跳转到商品页时,服务端如何知道你是已经登陆的状态?

    cookie

    首先产生了 cookie 这门技术来解决这个问题,cookie 是 http 协议的一部分,它的处理分为如下几步:

    • 服务器向客户端发送 cookie。
      • 通常使用 HTTP 协议规定的 set-cookie 头操作。
      • 规范规定 cookie 的格式为 name = value 格式,且必须包含这部分。
    • 浏览器将 cookie 保存。
    • 每次请求浏览器都会将 cookie 发向服务器。

    其他可选的 cookie 参数会影响将 cookie 发送给服务器端的过程,主要有以下几种:

    • path:表示 cookie 影响到的路径,匹配该路径才发送这个 cookie。
    • expires 和 maxAge:告诉浏览器这个 cookie 什么时候过期,expires 是 UTC 格式时间,maxAge 是 cookie 多久后过期的相对时间。当不设置这两个选项时,会产生 session cookie,session cookie 是 transient 的,当用户关闭浏览器时,就被清除。一般用来保存 session 的 session_id。
    • secure:当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效。
    • httpOnly:浏览器不允许脚本操作 document.cookie 去更改 cookie。一般情况下都应该设置这个为 true,这样可以避免被 xss 攻击拿到 cookie。

    express 中的 cookie

    express 在 4.x 版本之后,session管理和cookies等许多模块都不再直接包含在express中,而是需要单独添加相应模块。

    express4 中操作 cookie 使用 cookie-parser 模块(https://github.com/expressjs/cookie-parser )。

    var express = require('express');
    // 首先引入 cookie-parser 这个模块
    var cookieParser = require('cookie-parser');
    
    var app = express();
    app.listen(3000);
    
    // 使用 cookieParser 中间件,cookieParser(secret, options)
    // 其中 secret 用来加密 cookie 字符串(下面会提到 signedCookies)
    // options 传入上面介绍的 cookie 可选参数
    app.use(cookieParser());
    
    app.get('/', function (req, res) {
      // 如果请求中的 cookie 存在 isVisit, 则输出 cookie
      // 否则,设置 cookie 字段 isVisit, 并设置过期时间为1分钟
      if (req.cookies.isVisit) {
        console.log(req.cookies);
        res.send("再次欢迎访问");
      } else {
        res.cookie('isVisit', 1, {maxAge: 60 * 1000});
        res.send("欢迎第一次访问");
      }
    });

    session

    cookie 虽然很方便,但是使用 cookie 有一个很大的弊端,cookie 中的所有数据在客户端就可以被修改,数据非常容易被伪造,那么一些重要的数据就不能存放在 cookie 中了,而且如果 cookie 中数据字段太多会影响传输效率。为了解决这些问题,就产生了 session,session 中的数据是保留在服务器端的。

    session 的运作通过一个 session_id 来进行。session_id 通常是存放在客户端的 cookie 中,比如在 express 中,默认是connect.sid 这个字段,当请求到来时,服务端检查 cookie 中保存的 session_id 并通过这个 session_id 与服务器端的 session data 关联起来,进行数据的保存和修改。

    这意思就是说,当你浏览一个网页时,服务端随机产生一个 1024 比特长的字符串,然后存在你 cookie 中的 connect.sid字段中。当你下次访问时,cookie 会带有这个字符串,然后浏览器就知道你是上次访问过的某某某,然后从服务器的存储中取出上次记录在你身上的数据。由于字符串是随机产生的,而且位数足够多,所以也不担心有人能够伪造。伪造成功的概率比坐在家里编程时被邻居家的狗突然闯入并咬死的几率还低。

    session 可以存放在 1)内存、2)cookie本身、3)redis 或 memcached 等缓存中,或者4)数据库中。线上来说,缓存的方案比较常见,存数据库的话,查询效率相比前三者都太低,不推荐;cookie session 有安全性问题,下面会提到。

    express 中操作 session 要用到 express-session (https://github.com/expressjs/session ) 这个模块,主要的方法就是session(options),其中 options 中包含可选参数,主要有:

    • name: 设置 cookie 中,保存 session 的字段名称,默认为 connect.sid 。
    • store: session 的存储方式,默认存放在内存中,也可以使用 redis,mongodb 等。express 生态中都有相应模块的支持。
    • secret: 通过设置的 secret 字符串,来计算 hash 值并放在 cookie 中,使产生的 signedCookie 防篡改。
    • cookie: 设置存放 session id 的 cookie 的相关选项,默认为
      • (default: { path: '/', httpOnly: true, secure: false, maxAge: null })
    • genid: 产生一个新的 session_id 时,所使用的函数, 默认使用 uid2 这个 npm 包。
    • rolling: 每个请求都重新设置一个 cookie,默认为 false。
    • resave: 即使 session 没有被修改,也保存 session 值,默认为 true。

    1) 在内存中存储 session

    express-session 默认使用内存来存 session,对于开发调试来说很方便。

    var express = require('express');
    // 首先引入 express-session 这个模块
    var session = require('express-session');
    
    var app = express();
    app.listen(5000);
    
    // 按照上面的解释,设置 session 的可选参数
    app.use(session({
      secret: 'recommand 128 bytes random string', // 建议使用 128 个字符的随机字符串
      cookie: { maxAge: 60 * 1000 }
    }));
    
    app.get('/', function (req, res) {
    
      // 检查 session 中的 isVisit 字段
      // 如果存在则增加一次,否则为 session 设置 isVisit 字段,并初始化为 1。
      if(req.session.isVisit) {
        req.session.isVisit++;
        res.send('<p>第 ' + req.session.isVisit + '次来此页面</p>');
      } else {
        req.session.isVisit = 1;
        res.send("欢迎第一次来这里");
        console.log(req.session);
      }
    });

    2) 在 redis 中存储 session

    session 存放在内存中不方便进程间共享,因此可以使用 redis 等缓存来存储 session。

    假设你的机器是 4 核的,你使用了 4 个进程在跑同一个 node web 服务,当用户访问进程1时,他被设置了一些数据当做 session 存在内存中。而下一次访问时,他被负载均衡到了进程2,则此时进程2的内存中没有他的信息,认为他是个新用户。这就会导致用户在我们服务中的状态不一致。

    使用 redis 作为缓存,可以使用 connect-redis 模块(https://github.com/tj/connect-redis )来得到 redis 连接实例,然后在 session 中设置存储方式为该实例。

    var express = require('express');
    var session = require('express-session');
    var redisStore = require('connect-redis')(session);
    
    var app = express();
    app.listen(5000);
    
    app.use(session({
      // 假如你不想使用 redis 而想要使用 memcached 的话,代码改动也不会超过 5 行。
      // 这些 store 都遵循着统一的接口,凡是实现了那些接口的库,都可以作为 session 的 store 使用,比如都需要实现 .get(keyString) 和 .set(keyString, value) 方法。
      // 编写自己的 store 也很简单
      store: new redisStore(),
      secret: 'somesecrettoken'
    }));
    
    app.get('/', function (req, res) {
      if(req.session.isVisit) {
        req.session.isVisit++;
        res.send('<p>第 ' + req.session.isVisit + '次来到此页面</p>');
      } else {
        req.session.isVisit = 1;
        res.send('欢迎第一次来这里');
      }
    });

    我们可以运行 redis-cli 查看结果,如图可以看到 redis 中缓存结果。

    各种存储的利弊

    上面我们说到,session 的 store 有四个常用选项:1)内存 2)cookie 3)缓存 4)数据库

    其中,开发环境存内存就好了。一般的小程序为了省事,如果不涉及状态共享的问题,用内存 session 也没问题。但内存 session 除了省事之外,没有别的好处。

    cookie session 我们下面会提到,现在说说利弊。用 cookie session 的话,是不用担心状态共享问题的,因为 session 的 data 不是由服务器来保存,而是保存在用户浏览器端,每次用户访问时,都会主动带上他自己的信息。当然在这里,安全性之类的,只要遵照最佳实践来,也是有保证的。它的弊端是增大了数据量传输,利端是方便。

    缓存方式是最常用的方式了,即快,又能共享状态。相比 cookie session 来说,当 session data 比较大的时候,可以节省网络传输。推荐使用。

    数据库 session。除非你很熟悉这一块,知道自己要什么,否则还是老老实实用缓存吧。

    signedCookie

    上面都是讲基础,现在讲一些专业点的。

    上面有提到

    cookie 虽然很方便,但是使用 cookie 有一个很大的弊端,cookie 中的所有数据在客户端就可以被修改,数据非常容易被伪造

    其实不是这样的,那只是为了方便理解才那么写。要知道,计算机领域有个名词叫 签名,专业点说,叫 信息摘要算法

    比如我们现在面临着一个菜鸟开发的网站,他用 cookie 来记录登陆的用户凭证。相应的 cookie 长这样:dotcom_user=alsotang,它说明现在的用户是 alsotang 这个用户。如果我在浏览器中装个插件,把它改成dotcom_user=ricardo,服务器一读取,就会误认为我是 ricardo。然后我就可以进行 ricardo 才能进行的操作了。之前 web 开发不成熟的时候,用这招甚至可以黑个网站下来,把 cookie 改成 dotcom_user=admin 就行了,唉,那是个玩黑客的黄金年代啊。

    OK,现在我有一些数据,不想存在 session 中,想存在 cookie 中,怎么保证不被篡改呢?答案很简单,签个名。

    假设我的服务器有个秘密字符串,是 this_is_my_secret_and_fuck_you_all,我为用户 cookie 的 dotcom_user 字段设置了个值 alsotang。cookie 本应是

    {dotcom_user: 'alsotang'}

    这样的。

    而如果我们签个名,比如把 dotcom_user 的值跟我的 secret_string 做个 sha1

    sha1('this_is_my_secret_and_fuck_you_all' + 'alsotang') === '4850a42e3bc0d39c978770392cbd8dc2923e3d1d'

    然后把 cookie 变成这样

    {
      dotcom_user: 'alsotang',
      'dotcom_user.sig': '4850a42e3bc0d39c978770392cbd8dc2923e3d1d',
    }

    这样一来,用户就没法伪造信息了。一旦它更改了 cookie 中的信息,则服务器会发现 hash 校验的不一致。

    毕竟他不懂我们的 secret_string 是什么,而暴力破解哈希值的成本太高。

    cookie-session

    上面一直提到 session 可以存在 cookie 中,现在来讲讲具体的思路。这里所涉及的专业名词叫做 对称加密。 假设我们想在用户的 cookie 中存 session data,使用一个名为 `session_data` 的字段。 存 ```js var sessionData = {username: 'alsotang', age: 22, company: 'alibaba', location: 'hangzhou'} ``` 这段信息的话,可以将 `sessionData` 与我们的 `secret_string` 一起做个对称加密,存到 cookie 的 `session_data` 字段中,只要你的 `secret_string` 足够长,那么攻击者也是无法获取实际 session 内容的。对称加密之后的内容对于攻击者来说相当于一段乱码。 而当用户下次访问时,我们就可以用 `secret_string` 来解密 `sessionData`,得到我们需要的 session data。 signedCookies 跟 cookie-session 还是有区别的: 1)是前者信息可见不可篡改,后者不可见也不可篡改 2)是前者一般是长期保存,而后者是 session cookie

    cookie-session 的实现跟 signedCookies 差不多。

    不过 cookie-session 我个人建议不要使用,有受到回放攻击的危险。

    回放攻击指的是,比如一个用户,它现在有 100 积分,积分存在 session 中,session 保存在 cookie 中。他先复制下现在的这段 cookie,然后去发个帖子,扣掉了 20 积分,于是他就只有 80 积分了。而他现在可以将之前复制下的那段 cookie 再粘贴回去浏览器中,于是服务器在一些场景下会认为他又有了 100 积分。

    如果避免这种攻击呢?这就需要引入一个第三方的手段来验证 cookie session,而验证所需的信息,一定不能存在 cookie 中。这么一来,避免了这种攻击后,使用 cookie session 的好处就荡然无存了。如果为了避免攻击而引入了缓存使用的话,那不如把 cookie session 也一起放进缓存中。

    session cookie

    初学者容易犯的一个错误是,忘记了 session_id 在 cookie 中的存储方式是 session cookie。即,当用户一关闭浏览器,浏览器 cookie 中的 session_id 字段就会消失。

    常见的场景就是在开发用户登陆状态保持时。

    假如用户在之前登陆了你的网站,你在他对应的 session 中存了信息,当他关闭浏览器再次访问时,你还是不懂他是谁。所以我们要在 cookie 中,也保存一份关于用户身份的信息。

    比如有这样一个用户

    {username: 'alsotang', age: 22, company: 'alibaba', location: 'hangzhou'}

    我们可以考虑把这四个字段的信息都存在 session 中,而在 cookie,我们用 signedCookies 来存个 username。

    登陆的检验过程伪代码如下:

    if (req.session.user) {
      // 获取 user 并进行下一步
      next()
    } else if (req.signedCookies['username']) {
      // 如果存在则从数据库中获取这个 username 的信息,并保存到 session 中
      getuser(function (err, user) {
        req.session.user = user;
        next();
      });
    } else {
      // 当做为登陆用户处理
      next();
    }

    展开全文
  • COOKIE SESSION

    2009-12-11 22:24:00
    COOKIE SESSION 首先要明白以下几个基本知识: 1,浏览网页使用的是HTTP协议 2,HTTP协议是无状态的 3,整个过程是用户发出请求,服务器接受请求,作出响应,断开连接(无状态,不记录该连接记录) 4,HTTP协议...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 22,316
精华内容 8,926
关键字:

cookie和session