会话变量 - 文档请求

时间:2016-05-18 13:18:03

标签: http session variables

会话变量

在所有网络应用中,您可以获取/设置会话变量

  

PHP:

$foo = $_SESSION['myVar'];
     

.NET (MVC,在Controller中):

using System.Web.Mvc;
// ...
var foo = Session["myVar"];

我正在寻找关于会话变量的一些详细信息:

  • 他们最初的目的(他们打算解决什么问题?)
  • 常见用例

存储

  • 在哪里存储在系统上?

硬盘,内存,......

  • 谁在存储

客户端/服务器

  • 我猜这是服务器端,所以管理什么

Web服务器(Apache,IIS,...)/ Web App

  • 会话变量的生命周期是什么?

会议,对。所以当会话开始时,它何时结束以及系统如何知道它何时可以摆脱这些变量(GC机制)?

安全

  • 已知的安全漏洞?

PS:我想让这里的人们建立一个关于这个概念的好文档。如果您认为应该添加或编辑某些问题,请随时编辑问题。

3 个答案:

答案 0 :(得分:3)

<强>目的

创建会话变量主要是为了处理HTTP协议的无状态行为。由于每个页面请求几乎完全与其他页面请求分开处理,因此开发人员希望将各种请求串联在一起。这个规范示例是一个登录页面,用于对用户进行身份验证,然后在登录后更改请求页面的行为。

为了解决这个问题,许多语言和/或框架都提供了一个会话变量的概念,它允许开发人员存储与特定浏览器相关联的数据,并且可以在来自同一浏览器的单独请求中保留。

因此,以登录为例,在新浏览器的第一个请求中,会话变量将为空。然后,用户将填写认证信息并假设它是正确的,在服务器端,代码将为该浏览器设置会话变量以包含某种标识符,以表明他的浏览器已经过认证。然后在后续请求期间,代码可以检查会话变量中的标识符,以执行一些需要登录的特定代码。

另一个常见用例是&#34;向导&#34;流程。您可能希望用户通过多个单独的请求填写多页表单。当用户填写表单时,您可以将值添加到会话中,直到用户到达表单的末尾,此时您可以将其保存在更永久的存储中。

存储和管理

存储会话变量的方法有很多种。任何类型的持久存储都可以在请求中保持不变。可能最基本的方法是为每个会话创建一个单独的文件。 PHP通过获取它在浏览器中存储为cookie的会话ID,然后查找具有从会话ID派生的命名的文件来完成此操作。

您还可以将会话变量存储在数据库,共享内存中,甚至存储在cookie本身中。 Ruby on Rails通过加密数据然后将cookie设置为加密数据来存储会话变量。因此会话存储在用户的浏览器本身中。

最常见的是,会话变量与以某种方式存储在Web浏览器中的cookie相关联。此cookie通常由编写Web服务器应用程序的语言或框架自动管理。语言或框架检测新会话并创建新的会话变量,它通过某种API提供给Web服务器应用程序。然后,Web服务器应用程序可以使用API​​在会话变量中存储信息,删除它,创建新的等等...通常框架在会话的生命周期中有一些默认值,但通常可以通过API。我认为最典型的默认生命周期是浏览器进程的生命周期,通过cookie与用户的浏览器进程相关联。

安全

会话变量存在很多安全问题,因为它们通常用于管理Web应用程序中的授权和身份验证。

例如,许多应用程序仅使用与cookie关联的生命周期来设置会话生命周期。许多登录系统希望强制用户在指定时间后重新登录,但是当您告知cookie时,您无法信任浏览器使cookie过期。浏览器可能是错误的,可能由恶意的人编写,或由用户自己操纵以调整cookie的生命周期。因此,如果您使用的会话变量API依赖于cookie生存期,您可能需要具有强制会话变量过期的辅助机制,即使cookie没有。

其他一些安全问题涉及存储。如果您将会话ID存储在cookie中,然后使用该会话ID作为文件名来存储会话变量,则恶意浏览器可以将cookie中的会话ID更改为另一个ID,然后来自该浏览器的请求将开始使用某些ID其他浏览器的会话文件。

另一个问题是被盗的会话信息。通过XSS或数据包检查,会话信息可以从用户浏览器会话中被窃取,然后被恶意用户用来访问其他用户的帐户。通常使用SSL来保护传输中的会话,从而减轻此类问题。

This page解释了使用PHP实现的Session Variables时的许多安全问题。 Ruby on Rails的a similar page概述了该平台的Session Variables的安全问题。

答案 1 :(得分:2)

所以,我将在两个考虑因素的基础上提出这个问题:  1.我正在根据PHP指南回答。  2.我假设使用了共享托管服务。

<强>存储 通过使用共享主机,php.ini文件保留了这个答案。该文件是通过php.ini文件中的“session.save_path”行在您指定的路径上物理创建的。

来源:php.net Manual

谁存储会话 会话由SERVER技术上存储,但显然是由客户端请求。那么,回答:SERVER。 资料来源:session_start

由谁管理 如果您的session.save_path设置为在共享主机服务器上的某个位置,那么它们将控制销毁它的GC或忽略它直到稍后。实际上,我发生了一些实例,其中共享主机服务器中的其他客户端的session_gc.maxlifetime的数量比我的数量少,因此会导致我的会话文件在其设置的时间内被破坏(其他共享用户) 。要解决此问题,请在您的OWN文件树中编辑“session.save_path”。

<强>寿命 如前所述,“session.gc_maxlifetime”控制此文件的“到期”。与此同时,应考虑“session.gc_probability”和“session.gc_divisor”,并分别设置为“1”和“100”。谷歌搜索这个以获得进一步的解释。

来源:session.gc_maxlifetime

安全 我要让php.net处理这个,但这是链接!

来源:Security

答案 2 :(得分:2)

我以ASP.NET应用程序场景为例。

在ASP.NET / MVC中HttpContext.Current.Session提供对由服务器(WebServer / AppServer,IIS)管理的RAM的访问。在Internet Information Server的情况下,使用的RAM位于所谓的应用程序池内,并由在Web- / AppServer内运行的一个或多个应用程序使用。从程序员的角度来看,结构是一个字典,意思是通过C#进行访问,你可以使用this []操作符来写入和读取Session对象。

// write access
var CurrentArticle = 123456;
Session["CurrentArticle"] = CurrentArticle;

//...

// read access
var CurrentArticle = 0;
CurrentArticle = (int)Session[nameof(CurrentArticle)];

.NET提供的Session对象将在方法Session_Start中创建,并在Session_End中删除。但是,您不必使用系统的默认会话存储,并且可以实现自己的会话存储,例如:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Web;
// using MyOtherStuff;

namespace MyStuff.Server.Context
{
    public class HttpSessionState : HttpSessionStateBase
    {
        Dictionary<string, object> _sessionStorage = new System.Collections.Generic.Dictionary<string, object>();
        public override object this[string name]
        {
            get 
            { 
                if (HttpContext.Current == null || HttpContext.Current.Session == null) 
                    if (!_sessionStorage.ContainsKey(name))
                        return null;
                    else return _sessionStorage[name];
                return HttpContext.Current.Session[name]; 
            }
            set 
            {
                if (HttpContext.Current == null || HttpContext.Current.Session == null)
                    _sessionStorage[name] = value;
                else HttpContext.Current.Session[name] = value; 
            }
        }
    }
    public class Current
    {
        /// <summary>
        /// Objects stored in Cache expire after some time; compare Application 
        /// </summary>
        public static ExpiringCache Cache = new ExpiringCache();
        /// <summary>
        /// Objects stored in Application don't expire
        /// </summary>
        public static Application Application = new Application();
        public static HttpSessionState Session = new HttpSessionState();
        private static System.Web.HttpServerUtility server;
        public static System.Web.HttpServerUtility Server
        {
            get
            {
                if (System.Web.HttpContext.Current != null)
                    return Context.Current.Server;
                if (server != null)
                    return server;
                server = new System.Web.HttpApplication().Server;
                if (server != null)
                    return server;
                throw new NotSupportedException("HDitem.ApplicationServices.Current was not initialized (server)");
            }
            set { server = value; }
        }
    }
    //..
}

连接到服务器的每个新浏览器都会创建一个新会话。如果您不关心同一用户的最近会话数据(如果您的应用程序有用户),那么您可能不会在此处完成。

如果您想将新会话重新连接到一个或多个以前的会话,即通过您可以获得的有关此用户的某些数据组合(例如通过请求,cookie或类似)或以最简单的形式识别用户身份验证比您可能希望在Session_End中存储会话数据而不是删除它并在Session_start中或之后的任何时间恢复(一旦您有足够的关于此会话的用户的数据来识别她。)如果您需要任何形式的会话持久性(大概可以归结为硬盘或SSD来引用您的问题),在这种情况下可以采用任何形式的基于每个用户的存储,有时存储在用户配置文件中数据库或任何文件格式,如基于XML或JSON的。

换句话说:我不想在这里概括太多,但会话存储理想情况下是非常快的内存存储,如果实现会话持久性,可能会保存到任何外部存储。

上面提到的会话存储位于服务器端。现代浏览器有一个内置的本地存储,可以通过JavaScript访问。此本地存储还可用于创建会话内存,该会话内存可以与服务器端会话不同地使用,但当然可以以显式请求或附件(cookie)的形式进行同步。