One of the useful benefits of IIS 7.0 and the ASP.NET Integrated mode is the ability to protect all content using ASP.NET Forms Authentication.
In the past, people would often protect the application pages themselves, and leave images and media content open for public access. It wasn’t easy to extend the same internet-based authentication scheme to static content unless the static content was served through custom handlers. Even this wasn’t a perfect solution as you’d often lose performance and static content features such as static compression and ranged request support.
With IIS 7.0, you can configure Forms Authentication and Url Authorization rules once for the entire site, and rest easy knowing that your ASPX pages, PHP scripts, HTML files and media content is protected from unauthorized access.
Unfortunately, if you are serving web video using embedded video players, you may see that your embedded player becomes broken when using forms authentication. E.g. an embedded Windows Media Player may yeild this:
Why does this happen?
Here is why. When you log in to your site using Forms Authentication, you are typically issued a cookie that contains your authentication ticket. On subsequent requests, the browser sends this cookie and the server automatically authenticates you.
When the embedded media player makes a request to retrieve the media content, it automatically forwards the browser cookies for that domain. This should ensure that the server can authenticate the media player’s request and return the media file.
Unfortunately, this does not happen for Forms Authentication.
This is because when we developed ASP.NET 2.0, we made a decision to mark the Forms Authentication cookie with the HttpOnly attribute. This attribute prevents script from being able to access the cookie – thereby blocking potential Cross-Site Scripting (XSS) attacks aimed at stealing the authentication cookie.
Because of this security measure, the embedded media player does not have access to the Forms Authentication cookie, and is unable to retrieve the media content if it is protected by Forms Authentication.
To workaround, we can remove the HttpOnly attribute from Forms Authentication cookies when they are issued.
WARNING: This may make your authentication ticket more vulnerable to stealing, if someone can successfully carry out a cookie-stealing XSS attack.
1) Place this code in global.asax in the application root:
<script runat="server" language="c#">
void Application_PreSendRequestHeaders(Object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpCookieCollection cookies = app.Context.Response.Cookies;
if (cookies != null)
{
foreach(string name in cookies)
{
HttpCookie cookie = cookies[name];
if (cookie.Name.Equals(FormsAuthentication.FormsCookieName, StringComparison.OrdinalIgnoreCase))
{
 
; cookie.HttpOnly = false;
break;
}
}
}
}
</script>
2) Make sure to set <modules runAllManagedModulesForAllRequests="true" /> in the application web.config to allow this code to run for media content.
Other alternatives:
1) Make your media content publically available
2) Use cookie-less Forms Authentication in the application, and use relative media urls with the media player or insert the cookieless ticket in the embedded media player urls.
Using cookie-less forms authentication is also not a great option, as it may make the entire application more vulnerable to the url-based ticket threats. For more, see “Client Ticket Security” in http://msdn.microsoft.com/en-us/magazine/cc163702.aspx.
Hopefully this helps demystify this issue. Happy (media) serving!
Mike
Anonymous
One of the useful benefits of IIS 7.0 and the ASP.NET Integrated mode is the ability to protect all content
Anonymous
Mike,
I also get the exact same error message in the following circumstance:
– Cookieless forms authentication
– Left-clicking a webpage link to a protected .wmv file. Firstly you are directed to the login page and following successful login, this launches media player on the client and produces the error message. This happens even if the user was previously authenticated.
Given this is for cookieless authentication and the fact it’s not an embedded player, do you have any idea why this would be happening and are there any work-arounds for this precise situation? The only thing I can tell from the IIS log is the media player appears to be requesting authentication again (login form entries are shown in the log but not seen visibly during execution).
Many thanks,
Mark
Mike Volodarsky
Hi Mark,
My guess is that the media url for the player is not relative, or does not explicitly contain the cookieless token.
Check the server logs – do you see the player providing the cookieless tokens in the url when it requests the media content? Additionally, the content typically must be in the same application for the authentication token to work.
Thanks,
Mike
Anonymous
You know what, my mouse happened to be exactly on Close button, and I clicked about five times and then noticed it was a picture.
aspmark
Hi Mike,
Yes you’re right, my apologies. I was being silly and thought I had cookieless authentication in operation when it was session state all along. So I was in fact using cookie based authentication which is why it wasn’t working, as you’ve already recognised.
Switching to cookieless does indeed work, as does your code for cookie based authentication. It works a treat so thank you for the solution. I searched high and low for the answer and this blog was the only place I could find it so thanks very much Mike for helping with this.
Regards,
Mark
Mike Volodarsky
You are welcome, glad to help!
Mike
Anonymous
thank you so very much i have been looking for this !
Anonymous
Really short but useful howto.
Thanks.
johnny
Anonymous
Mike,
I was just wondering whether you knew if there were any plans to ensure later versions of windows media player would read httponly cookies by default? This problem doesn’t seem to manifest itself with other players so it doesn’t seem to be a general client/player issue but something specific to the windows player.
Many thanks,
Mark
Anonymous
Mike, do these changes effect cross application support in IIS 7 for forms authentication also? I’m using the IIS 6 syntax of setting identical Forms and machineKey elements in both applications, but when I switch from Application 1 to Application 2 i get redirected to my login page. It does prove that Application 2 is at least understanding the loginUrl because it’s sending me to the correct page, but it’s not passing authentication.
thanks,
Jay
Anonymous
Thanks for the information, Mike, it definitely resolved the issue in Internet Explorer. However, I’m still unable to get WMVs to play in other browsers (chrome, opera, firefox, safari). What happens is that after clicking on the link to the WMV file, the embedded windows media player appears, reports “opening media”, then “connecting”, then “ready”, but the video never starts. Clicking on the play button flashes “opening media” then “ready”, but does not play the video.
This problem only happens with WMV files placed in a directory with a .net application using forms authentication. If I copy the WMV into a directory outside of the application (or temporarily rename web.config), it will play the WMV fine. In addition, the problem only appears to happen with WMV files – MP4 files play fine within the application (using an embedded quicktime player).
Any ideas?
Anonymous
Thank you for submitting this cool story – Trackback from NewsPeeps
Anonymous
That is what I need, thank you very much!
Anonymous
Thanks, for the script. I needed that
Anonymous
Mike,
What I have observed in one of the web application, we have custom login form and the authentication mode is set to windows. And instead of media player we have appletviewer which display images from server similar issue has occured and your solution has fixed the issue.
My query is – Is this not fixed at IIS level though as I am using IIS7.5 on windows R2 and I see a setting on IIS for webapp httponly cookie set to false but still it doesn’t work any idea why setting fails and I have to write the code in global.asax.
Anonymous
First time around, I forgot to edit web.config, but after I fixed that, it worked like a charm. Thanks Mike, great blog!
Tony
Thank you. I just ran into this issue. You saved me a lot of time