asp:feature
LANGUAGE: C# | VBScript
ASP.NET VERSIONS: 1.0 | 1.1
Share Session State Between ASP and ASP.NET Apps
Learn how - and how not - to share Session variables
between your old and new apps.
By Dennis Hurst
As you migrate your Web apps from classic ASP to ASP.NET,
you may not have the luxury of completely rewriting the entire application
before going to production. Instead, you may need to migrate portions of the application from ASP to
ASP.NET, while leaving others as-is. If you need to make this type of
migration, you will inevitably encounter the issue of how to integrate session
state from your ASP application into your ASP.NET app.
Unfortunately, the session management services for each
technology are completely separate, and there is no standard mechanism for
sharing information between an ASP and an ASP.NET session. This article,
however, shows a secure and simple method of sharing Session variables between
ASP and ASP.NET pages. Along the way, you'll also learn about several
alternative methods that are not
secure.
Must-Haves and
Must-Nots
Any solution to the ASP/ASPX session sharing issue needs
to address certain issues. First, it must be secure. Given that highly
sensitive information is typically kept in session variables, security must be
considered. A breach in a session sharing mechanism could result in a major
system breach.
Next, it should be elegant. A complex solution or one that
is difficult to maintain would be counterproductive. After all, this solution
is most likely a temporary solution until all of an application can be migrated
to ASP.NET pages.
Finally, it should require minimal server-based components
beyond ASP.NET and ASP-based pages (or better yet, none at all). Many sites are
hosted on remote servers; getting a vendor to run your DLL or other system file
can be challenging.
Typically, information stored in a Session variable is for
internal application use only and should be considered to be highly secure.
Things that are often stored in the Session object include login state, user
information, system information, and many potentially other secure items that
an end user should never see.
Given the secure nature of information that is stored in a Session object,
security must be the paramount concern. With that in mind, some of the obvious
solutions to the Session sharing issue must be avoided because they are
extremely insecure. You should never
put sensitive information in a cookie, a hidden parameter, or a URL; and you
should avoid returning secure or
system information to a browser, unless it's absolutely necessary.
The Big Question
HTTP is a stateless protocol. A request is sent by the
client to the server and a response is returned to the client. The connection
is then completed. The nature of this sessionless protocol has led vendors
(like Microsoft) to come up with alternative means of maintaining session state
outside the base HTTP protocol. In general, session state is maintained by ASP
via the use of a cookie that is sent from the server to the client. If you look
at the HTTP response, you'll see something like this:
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0 Date:
Mon,07 Apr 2003 12:52:26GMT
Content-Length: 10225
Content-Type: text/html
Cache-control: private
Set-Cookie: ASPSESSIONIDCSCRRCBS=GODPKFJDPJNMHGGJDOEIDDMK;
Note that the Web server (IIS) set a cookie with a name
that starts with ASPSESSION and has some seemingly random value. This is the
ASP Session cookie. All subsequent requests sent from the client to the server
will include the ASP Session cookie along with the request. This cookie allows
IIS to associate the request with a specific session object that is stored on
the server.
ASP.NET uses the same technique to maintain session state,
except that a different cookie name is used. In the case where an ASP session
and an ASP.NET session have been established with the same server, the browser
will send both the ASP and ASP.NET cookies with each request. The request will
look something like this:
GET /MixedSessions/ASPSession.aspx
HTTP/1.0
...headers removed to simplify example...
Cookie: ASPSESSIONIDAAR=NGHNLJKBBJG;
ASP.NET_SessionId=q5ydd3t45....
From this we know that if you have ASP and ASP.NET
applications running in the same folder (specifically if you put the ASP and
ASP.NET files in the same folder or virtual directory), the user will have a
Session object in both the ASP and ASP.NET environments. The question now
becomes how you can share information in the ASP environment with the ASP.NET
environment.
All Together Now
The goal of this solution is to allow an ASP.NET app to
retrieve variables from an ASP Session object. Figure 1 illustrates the flow of
the process that occurs:
- A user's browser will send a request from the client to the
server. This request will contain the ASP and ASPX Session tokens (cookies).
- An ASPX Web page that needs information from an ASP Session
object will create an HTTP request and send it to an ASP page that is
specifically designed to return ASP Session object variables securely.
- The ASP page will authenticate that the request is from a
local ASP.NET page only. Then it will
look up the requested Session variable and return it in the HTTP response.
- The ASP.NET page will do whatever processing is needed and
generate the response.
- The response is returned to the user.
Figure 1. By using a .NET class that
creates a request containing the ASP Session cookie and sends it to an ASP page
to retrieve the ASP Session variable and an ASP page that authenticates the
request and returns the Session variable, you can share Session state between
ASP.NET and ASP apps.
In Step 2 above, the ASP.NET page will craft a request
that contains the ASP Session cookie that was passed to it. This will allow the
ASP page to associate the request that comes from the ASPX page with the proper
user's session.
Two components will be needed to make this system work.
The first is a .NET class that will create a request that contains the ASP
Session cookie and sends it to an ASP page to retrieve the ASP Session
variable. The second will be the ASP page that authenticates the request and
then returns the Session variable.
The .NET code consists of two main functions and a
constructor. The two functions work together to request Session information
from an ASP page and the constructor decides to which ASP page the necessary
request will be sent.
The constructor for this class takes a reference to the
HttpContext and derives the URL it will need to send its requests to, as shown
in Figure 2.
public ASPSessionVar(HttpContext oInContext)
{
oContext = oInContext;
ASPSessionVarASP =
"SessionVar.asp";
/* We now build a
System.Uri object to derive the correct
URL to send the HTTP
request to. oContext.Request.Url
will contain a
System.Uri object that represents
this ASPXs URL.
*/
System.Uri oURL =
oContext.Request.Url;
ASPSessionVarASP =
oURL.Scheme + "://"
+ oURL.Host +
":" + oURL.Port.ToString()
+ ASPSessionVarASP;
}
Figure 2. The ASPX
page is going to make an HTTP request to an ASP page contained in the same
folder as this ASPX page. This section of code derives the proper URL to send
the request to.
The primary function for this example is called
GetSessionVar, which is shown in Figure 3. It does the majority of the work
done by this application as outlined in Step 2 of Figure 1. This includes
creating a WebRequest, sending it off to the ASP page, and returning the
response.
public string GetSessionVar(string ASPSessionVar)
{
// First get the Session
Cookie
string ASPCookieName =
"";
string ASPCookieValue =
"";
if (!GetSessionCookie
(out ASPCookieName,out
ASPCookieValue))
{
return "";
}
// Initialize the
WebRequest.
HttpWebRequest myRequest
=
(HttpWebRequest)
WebRequest.Create
(ASPSessionVarASP +
"?SessionVar=" + ASPSessionVar);
myRequest.Headers.Add
("Cookie: "
+ ASPCookieName + "=" + ASPCookieValue);
// Send the request and
get a response
HttpWebResponse
myResponse =
(HttpWebResponse)
myRequest.GetResponse();
Stream receiveStream = myResponse.GetResponseStream();
System.Text.Encoding encode =
System.Text.Encoding.GetEncoding("utf-8");
StreamReader readStream =
new
StreamReader(receiveStream, encode);
string sResponse =
readStream.ReadToEnd();
// Do a bit of cleanup
myResponse.Close();
readStream.Close();
return sResponse;
}
Figure 3. GetSessionVar is the primary function
in this example. It handles the process of creating, sending, and parsing the
HTTP request that is used to retrieve the ASP session variable.
One utility function that is used is GetSessionCookie,
shown in Figure 4. This function simply takes the Request that was passed by
the client and extracts the ASP Session cookie from it. This function is called
by the GetSessionVar function to retrieve the ASPSession cookie. Since this
ASP/ASPX-based application is on the same server the Web browser will send both
the ASP and ASPX cookies with each request that is made to the Web server. This
function iterates through the cookies that are contained in the Cookies collection
and finds and returns the ASPSession cookie.
private bool GetSessionCookie
(out string
ASPCookieName, out string ASPCookieValue)
{
int loop1;
HttpCookie
myCookie; // Cookie variable
ASPCookieName =
"";
ASPCookieValue =
"";
// Capture all cookie
names into a string array.
String[] CookieArray =
oContext.Request.Cookies.AllKeys;
// Grab individual
cookie objects by cookie name.
for (loop1 = 0; loop1
< CookieArray.Length; loop1++)
{
myCookie =
oContext.Request.Cookies[CookieArray[loop1]];
if
(myCookie.Name.StartsWith("ASPSESSION"))
{
ASPCookieName =
myCookie.Name;
ASPCookieValue =
myCookie.Value;
return true;
}
}
return false;
}
Figure 4. The GetSessionCookie function will
find and return the ASPSession cookie that was sent by the browser in the HTTP
request and return it to the GetSessionVar function.
Serve the Session Variable
The ASP code for this example was placed in an ASP file
called SessionVar.asp. It performs two simple tasks. First, it ensures that the
request is coming from the server that the ASP page is running on. This ensures
that the request is valid and coming ONLY from the Web server's IP address. The
ASP page then returns the session variable it was asked to provide:
<%
dim sT
if Request.ServerVariables("REMOTE_ADDR") =
Request.ServerVariables("LOCAL_ADDR") then
sT =
Request("SessionVar")
if trim(sT) <>
"" then
Response.Write
Session(sT)
end if
end if
%>
It is critically important that the IP address check not
be removed for any reason. Removing this would allow a hacker to access
potentially critical information.
The following code shows how this class can be used by an
ASPX-based Web page that needs to retrieve Session from an ASP-based
application. The ASPX page will instantiate an ASPSessionVar object, passing in
the current Context to the constructor. The GetSessionVar function is then
called, passing in the name of the ASP Session variable that is to be
retrieved. No other setup is required to call the method:
//Create an ASPSessionVar object,
//passing in the current context
SPI.WebUtilities.ASP.ASPSessionVar oASPSessionVar
= new
SPI.WebUtilities.ASP.ASPSessionVar(Context);
string sTemp = oASPSessionVar.GetSessionVar("FirstName");
After executing a call to the GetSessionVar function the
sTemp variable will contain the contents of the FirstName session variable from
the ASP-based application.
The sample code in this
article is available for download.
Dennis
Hurst is a senior
consulting engineer for SPI Dynamics and
is a member of its SPI Labs team of Internet security
experts. He is responsible for working with customers and for
developing marketing resources that educate them on the need for Web
application security and practical ways to protect Web sites by using
WebInspect, the company's flagship product line of Web application security
assessment solutions. Dennis is an MSCD in Visual Basic and SQL Server. You can
reach Dennis at mailto:dhurst@spidynamics.com.