1. Flash Player has a cookie bug. No cookies (or IE's cookies) are sent by Flash Player uploads in FireFox, Opera, and Safari on Windows (and maybe on other systems).
2. Overriding the session in PHP is easy. Overriding the session is ASP.Net is not so easy (at least not as obvious).
I randomly came across a solution for ASP.Net Session overriding. I did a simple test with the ASP.Net Application Demo and it seems to work.
By including a Global.asax file and the following code you can override the missing Session ID cookie
void Application_BeginRequest(object sender, EventArgs e)
{
/* Fix for the Flash Player Cookie bug in Non-IE browsers.
* Since Flash Player always sends the IE cookies even in FireFox
* we have to bypass the cookies by sending the values as part of the POST or GET
* and overwrite the cookies with the passed in values.
*
* The theory is that at this point (BeginRequest) the cookies have not been ready by
* the Session and Authentication logic and if we update the cookies here we'll get our
* Session and Authentication restored correctly
*/
try
{
string session_param_name = "ASPSESSID";
string session_cookie_name = "ASP.NET_SESSIONID";
if (HttpContext.Current.Request.Form[session_param_name] != null)
{
UpdateCookie(session_cookie_name, HttpContext.Current.Request.Form[session_param_name]);
}
else if (HttpContext.Current.Request.QueryString[session_param_name] != null)
{
UpdateCookie(session_cookie_name, HttpContext.Current.Request.QueryString[session_param_name]);
}
}
catch (Exception)
{
}
try
{
string auth_param_name = "AUTHID";
string auth_cookie_name = FormsAuthentication.FormsCookieName;
if (HttpContext.Current.Request.Form[auth_param_name] != null)
{
UpdateCookie(auth_cookie_name, HttpContext.Current.Request.Form[auth_param_name]);
}
else if (HttpContext.Current.Request.QueryString[auth_param_name] != null)
{
UpdateCookie(auth_cookie_name, HttpContext.Current.Request.QueryString[auth_param_name]);
}
}
catch (Exception)
{
}
}
void UpdateCookie(string cookie_name, string cookie_value)
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookie_name);
cookie.Value = cookie_value;
HttpContext.Current.Request.Cookies.Set(cookie);
}
Explaination: This code checks your POST (form) and GET (querystring) for a Session ID. If it finds one then it overrides the session cookie with the value from your POST/GET. Then later when the session is restored the overridden session is what you get (instead of IE's session or a brand new session which was what the bug was causing to happen).
The same sort of thing is done for the Forms Auth cookie, but I didn't actually go back and look at Forms Auth to see how it works to make sure this would work. And I didn't set the Forms Auth bit so it might not even work.
You just need to include a post_param in your SWFUpload page that passes in the session id. Something like:
var swfu = new SWFUpload({
/* lots of settings */
post_params : {
/* other post params */
"ASPSESSID" : "<%=Session.SessionID %>"
}
/* lots more settings */
});
Note: The overriding of the Forms Authentication cookie has not been tested but I think it should still work. Someone will have to let me know.
P.S. & Security Warning: Don't just copy and paste this code in to your ASP.Net application without knowing what you are doing. It introduces security issues and possibilities of Cross-site Scripting.
February 29, 2008 - 1:18pm
I have seen similar solution to this firefox/flashplayer bug. But it doesn't solve the problem. I have seen that many people faced this and many got this solution on the web, but didn't found anybody who says it really worked for them.
It doesn't work for all of them who are doing authentication on upload page which seems to be a general real requirement.
Any help?
March 3, 2008 - 12:40pm
If you need to fix authentication you also have to pass over the authentication cookie in the post_params.
post_params : {
"ASPSESSID" : "<%=Session.SessionID %>",
"AUTHID" : "<% /* Code to output the contents of the auth cookie */ %>"
}
I finally got around to testing all this and it seems to work fine. The latest version of the code (with some bug fixes) is now part of the SWFUpload package.
C# and VB.Net samples will be included in the v2.1.0 release.
January 7, 2009 - 10:07am
As of version v2.2.0 Beta4, the ASP Net C# example does not work. It works only for Forms Authentication with anonymous user access allowed - a bit absurd. This wouldn't be such a problem, except that the forum and code samples imply it should work. The web.config is set up for Forms Authentication, and the global.asax file has code that seems to pull the Forms Authentication cookie from the post in order to override the wrong (IE) one. However, the constructor for the SWF component doesn't add it to the post parameters:
You need (beware of line wraps):
post_params : {
"ASPSESSID" : "<% =Session.SessionID %>",
"AUTHID" : "<% = Request.Cookies[FormsAuthentication.FormsCookieName]==null ?
"" : Request.Cookies[FormsAuthentication.FormsCookieName].Value %>"}
Great work here on the SWFUpload component, but it would be even greater if developers for non-IE didn't have to tear their hair out on this issue.
January 7, 2009 - 10:21am
The C# demo does not demonstrate restoring the Auth cookie, just the session. The VB version does both.
That's how they've always been.
March 5, 2009 - 3:22pm
just changed updatecokie function:
void UpdateCookie(string cookie_name, string cookie_value)
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookie_name);
if (cookie == null)
{
HttpCookie cookie1 = new HttpCookie(cookie_name, cookie_value);
Response.Cookies.Add(cookie1);
}
else
{
cookie.Value = cookie_value;
HttpContext.Current.Request.Cookies.Set(cookie);
}
}
March 15, 2009 - 2:03am
I just wanted to share my experience getting this to work on my AJAX based web app, where logins take place dynamically on the page without the page ever refreshing.
post_params : {
"ASPSESSID" : "<% =Session.SessionID %>",
"AUTHID" : "<% = Request.Cookies[FormsAuthentication.FormsCookieName]==null ?
"" : Request.Cookies[FormsAuthentication.FormsCookieName].Value %>"}
That being said, the code above would require another trip to the server, so I needed something more real-time. The problem is that the ASP.NET session and authentication cookies are flagged as HttpOnly, and cannot be read by javascript. The workaround:
void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
HttpCookieCollection cookies = HttpContext.Current.Response.Cookies;
if (cookies != null && cookies.Count>0)
{
for (int i = 0; i < cookies.Count; i++)
{
if (cookies[i].Name == FormsAuthentication.FormsCookieName || cookies[i].Name.ToUpper() == "ASP.NET_SESSIONID")
{
if (cookies[i].HttpOnly == true)
{
cookies[i].HttpOnly = false;
}
}
}
}
}
This event removes the HttpOnly flag on the Forms Authentication cookie and the Session cookie. WARNING: The HttpOnly flag was developed to prevent XSS attacks, and removing the flag opens a new security hole. You have been warned.
At this point, the cookies are readable by Javascript, and we can now use something like:
function fileQueuedHandler(file) {
this.setPostParams({"ASPSESSID":Cookie.get("ASP.NET_SessionId"),"AUTHID": Cookie.get(".ASPXAUTH") });
}
This way, the post params are updated at every file queue, in case of a new user, and therefore new authentication cookie.
Conclusion: So this way works, but it removes a security prevention mechanism at the same time. What are your thoughts on removing the HttpOnly flag? Reasonable idea or stupid? Anyway, just thought I'd share how I got it working, since I think it's kinda cool...
April 12, 2009 - 2:30pm
giuice's code change fixed the issue for me as well. The key being that when the cookie is null you want to update the *response* cookie collection, not the *request* cookie collection. I don't actually understand why that is, since I thought we were trying to simulate a request from the user's browser, but it did the trick.
Also, if you want to tighten up some of the other code, it's not hard to shorten it and reduce some of the repeated logic:
HttpRequest request = HttpContext.Current.Request;
try
{
string session_param_name = "ASPSESSID";
string session_cookie_name = "ASP.NET_SESSIONID";
string session_value = request.Form[session_param_name] ?? request.QueryString[session_param_name];
if (session_value != null) { UpdateCookie(session_cookie_name, session_value); }
}
catch (Exception){ }
try
{
string auth_param_name = "AUTHID";
string auth_cookie_name = FormsAuthentication.FormsCookieName;
string auth_value = request.Form[auth_param_name] ?? request.QueryString[auth_param_name];
if (auth_value != null) { UpdateCookie(auth_cookie_name, auth_value); }
}
catch (Exception) {}
April 25, 2009 - 5:05am
If you are using this with an ashx handler don't forget to add a marker interface like IReadOnlySessionState to your handler definition.
I want my four hours back.