Internet Explorer Cannot Download https://something
Earlier today, I was asked to troubleshoot a secure site where file downloads were always failing. Having seen this problem many times often over the years, I immediately suspected that the web developer wasn’t aware that
if a user tries to download * a file over a HTTPS connection, any response headers that prevent caching will cause the file download process to fail.
* Note that this applies to “downloaded” files that open in programs other than IE. It does not apply to resources that render inside IE’s HTML rendering engine, like images/script/css/etc.
When Internet Explorer encounters a HTTPS download that will not be cached, the download is aborted with the following dialog box:
The Fiddler web debugger allows you to easily check to see whether a download contains headers that prevent caching.
Cache-preventing headers include:
- A Cache-Control header with the tokens no-cache, no-store
- A Vary header that specifies almost anything
- A Pragma header that specifies exactly no-cache
Without changing the site’s code, you can easily confirm that the problem is caused by cache-prevention headers using Fiddler’s Filters tab:
Fiddler allowed me to determine that today’s instance was caused by cache-preventing headers. After the web developer updates these headers to allow local caching (e.g. Cache-Control: private, max-age=15) the file download process will work correctly.
-Eric
PS: In the unlikely event that the user has checked the Do not save encrypted pages to disk option inside Tools / Internet Options > Advanced, this error dialog may be shown for any file downloads from secure sites, regardless of caching headers. I recommend that folks avoid enabling this option, and use the Delete Browser History on Exit feature instead.
Update Oct. 2010: I've conducted some further investigation of this issue, and found that (surprisingly) you CAN specify Cache-Control: no-store, no-cache and the download will work, but if you specify these directives in the opposite order, it will fail. Additionally, if you include a Pragma: no-cache header, the secure response will not be cached regardless of other headers. As a comment notes below, the behavior is slightly different for direct navigation (e.g. URL in the address bar) vs. a hyperlink navigation (e.g. user clicks on a link).
Update Feb. 2011: I've modified the file download logic for IE9. IE9 should be able to successfully download a file regardless of HTTPS or Cache-Control headers unless you have the "Do not save encrypted pages to disk" option set.
Comments
Anonymous
October 03, 2009
Can you clarify "downloaded files" a bit more? Does only apply to files with "Content-Disposition" response headers? Or is it simply any response with a Content-Type which IE does not handle natively?Anonymous
October 03, 2009
@Billy: "this applies to “downloaded” files that open in programs other than IE" means "any response with a Content-Type which IE does not handle natively."Anonymous
October 03, 2009
This behavior seems kind of silly. Is there a particular threat we're protecting against? Is copy/paste blocked too? Blocking these downloads seems like it will just discourage people from using HTTPS.Anonymous
October 03, 2009
If a secure (SSL) web app builds content to the filesystem and points the browser at those files for download, it also must modify the IIS settings for that file, or it will fail for IE‽ > "this applies to “downloaded” files that open in programs other than IE" means "any response with a Content-Type which IE does not handle natively." Content-Type based on the header, or content type detected by sampling the data?Anonymous
October 03, 2009
> "This behavior seems kind of silly." :-) I've used a variety of words to describe it, most of which are a bit harsher than "silly." I should have noted that this behavior has existed since (at least) IE6. It's something that major customers (especially banks) had asked for, without really understanding what it would mean for the user-experience. Obviously (considering the confusing UI) this wasn't a scenario where a major investment was made. > "it also must modify the IIS settings for that file, or it will fail for IE‽" No, unless IIS configuration had already been modified to send a "no-cache" header. By default, IIS wouldn't send this header, and hence this problem would not be encountered. > "Content-Type based on the header, or content type detected by sampling the data?" The distinction is irrelevant in this case.Anonymous
October 04, 2009
> It's something that major customers (especially banks) had asked for,[…] Wait, so this is not a bug but a feature? I still don't get what the security gain could be. AFAIK, https traffic shouldn't be cached anyway. And on top of that, if that's a 'security feature' why this misleading error message?! Apropos banks requesting security features, what about "X-Force-TLS"?Anonymous
October 04, 2009
<< AFAIK, https traffic shouldn't be cached anyway.>> That's an incorrect assumption. << what about "X-Force-TLS"? >> A number of folks are interested in the Strict Transport Security spec.Anonymous
October 04, 2009
« That's an incorrect assumption. » Maybe, for when some evil villain is able to read your cache (the one on the disk) all is lost anyway. The equivalent of "Do not save encrypted pages to disk" is in Firefox the the about:config entry "browser.cache.disk_cache_ssl" which is set to "false" by default. So – unlike IE – Firefox isn't caching content coming through HTTPS par default. I guess Mozilla had their reasons for deciding on this default behaviour, particularly as it means a sacrifice of performance on HTTPS pages. BTW/OT: I wish I will also find my life's calling where I would be so dedicated that I would reply to blog post comments on Sundays. :)Anonymous
October 04, 2009
"Firefox isn't caching content coming through HTTPS par default" Last time I looked, in current Firefox versions, if a Cache-Control: public header is present, Firefox will cache the HTTPS-delivered content.Anonymous
October 05, 2009
The setting makes complete sense on shared machines. If someone decides to access their inbox on a public computer with auto-login, other people shouldn't be able to dig up what they were looking at over SSL. Perhaps I'm too paranoid but I always make sure that setting is checked. Thanks for the heads-up about Firefox, Eric.Anonymous
October 05, 2009
@WillH: Generally speaking, it's never safe to browse private sites on an untrusted PC, because the PC may contain keyloggers or other spy software. Rather than tweaking the setting (which doesn't really work like you hope it does), you should use the "Delete Browser History" command or IE8's InPrivate Browsing feature.Anonymous
October 05, 2009
@WillH: The problem with disabling caching for all HTTPS traffic is that it makes HTTPS slower and more expensive for web site operators. That means fewer of them will deploy HTTPS and everyone's security suffers to mitigate this marginal threat. If you don't want something cached, send a cache header with that instruction!Anonymous
October 14, 2009
The comment has been removedAnonymous
October 14, 2009
@Ryan: You shouldn't be sending a Pragma header at all. But yes, if you send a Pragma that forbids caching, you'll see behavior as described in this post.Anonymous
February 15, 2010
I'm running into this on my site but we're using straight HTTP, not HTTPS. We have caching disabled (Cache-control: no-cache) for our download area due to a customer request. Strangely, the problem only happens if I type in the URL to the file directly: http://www.aesc-inc.com/download/SPC/2010/SPC2010Install.exe">http://www.aesc-inc.com/download/SPC/2010/SPC2010Install.exe . If I go to our download page (http://www.aesc-inc.com/download/SPC/ ) and click the link, it works just fine. Any ideas?Anonymous
September 21, 2010
Like Don, I get this error using HTTP and not HTTPS and only if the user follows a link within an email or types the URL in IE directly. Strangely it only happens to users within our corporate network. External visitors can access the files fine either via links or by entering the address directly into the browser. Enabling caching is not an option as we then get an alternative error "myfile.xls is locked for editing by 'me' Open 'Read-Only', or click 'Notify' to open read-only..." Is there any resolution to this?Anonymous
October 05, 2010
I developed a activex. and signed it, and make cab file, and also signed it. It worked fine when download from http://something in WinXP and windows7 (IE7)client. but when download from https://something in WinXP and windows7 (IE7)client. it doesn't work. (can't download anything) in Win XP, I checked [Do not save encrypted pages to disk] option, so download activex OK from https://something. but windows7 still can't work. Is there any resolution to this? Any advice please.Anonymous
October 06, 2010
@DonPratt, @SimonJ, @Schin: Please send me (via email) the exact headers on the response. You can capture these via the Fiddler Web Debugger (www.fiddler2.com); for HTTPS sites, you'll need to enable HTTPS decryption in the Fiddler options.Anonymous
October 06, 2010
I solved my problem now. The cause is we used tomcat as our web server. the tomcat add Cache-Control header when the server site is https. thank you very much.Anonymous
October 27, 2010
Hi Eric; right now I'm having this issue at the QA server, but there's a little problem, I wasn't using any kind of cache control. In my localhost it works just fine, but at QA displays that error, so i added the control cache that you used as example and it keeps going fine in my local and keeps sending the error message at the QA server, could you please give me some advice? This is the code (well, the part that is making me get hairless); I forgot, is Classic ASP and the QA server is not HTTPS Response.Buffer = TRUE Response.Clear() Response.ContentType = "application/vnd.ms-excel" Response.AddHeader "Cache-Control: private, max-age=15","attachment; filename=Reporte_Detallado.xls" Thanks in advanceAnonymous
October 27, 2010
The comment has been removedAnonymous
November 17, 2010
The comment has been removedAnonymous
November 17, 2010
@Drew: The article itself talks about workarounds, which leads me to believe that you're having some other problem entirely. If you email me a network trace (www.fiddler2.com), I'm happy to have a look at it.Anonymous
January 06, 2011
Great post, though I'm still having problems. I've tried amending my .net code, as suggested above, by adding: Response.AddHeader "Cache-Control", "private, max-age=15" but that hasn't solved it. After that change, I've used Fiddler to delete the Cache-Control header as directed, but I was still getting an Expires: -1 so also had to delete the pragma header (by entering "pragma; cache-control" in the Fiddler 'Delete response header' textbox). This then allowed the download of an Excel file from a page served over https My question is, what else do I need to do in my code ? Perhaps this : HttpContext.Current.Response.Cache().SetExpires(DateTime.Now.AddMinutes(15)) Thanks in advance. Iain.Anonymous
January 06, 2011
@Iain: Pragma: no-cache will prevent caching. If your page is sending that, you need to reconfigure it not to. If you don't know how to suppress that header, you'll need to ask in an ASP.NET forum.Anonymous
January 06, 2011
Thanks Eric. I've got it working now. In case it helps others, here's my code: HttpContext.Current.Response.Clear() HttpContext.Current.Response.ClearHeaders() HttpContext.Current.Response.AddHeader("content-disposition", String.Format("attachment; filename={0}", fileName)) HttpContext.Current.Response.AddHeader("Cache-Control", "private, max-age=15") HttpContext.Current.Response.ContentType = "application/vnd.ms-excel" HttpContext.Current.Response.Cache().SetExpires(DateTime.Now.AddMinutes(15)) I imagine it's the ClearHeaders() statement that has removed the pragma header.Anonymous
January 11, 2011
Thanks a lot Eric for the article. It saved me from a tough debugging session. Your tip on the header "Cache-Control: no-store, no-cache" was a great hint. I got my file working over SSL now. Thank you once again, have a good day!Anonymous
February 17, 2011
Thanks, you just saved my sanity. Beer is on me!Anonymous
April 19, 2011
Thanks. This worked for JSP , Tomcat, HTTPS. Set the Header follows on HttpServletResponse:
response.setHeader(CACHE_CONTROL, "private, max-age=15");
response.setHeader(PRAGMA,"");Anonymous
November 02, 2011
Coming very late to this conversation, but to those who say that no HTTPS content should ever be written to disk, what if you have a paystub site that gives you your paystub as a PDF? How do you get that PDF to open in your PDF reader if you don't have it on disk? What if you want to print something? The print spooler operates on files. As Eric says, if someone can access your Temporary Internet Files folder, they have lots of other ways to control your user account; e.g., capture the HTML or other data after it has been downloaded by your browser and decrypted. HTTPS provides point to point encryption, but at the endpoints it's in the clear.Anonymous
January 23, 2012
IE changes the extension on almost all file downloads, forcing me to save as change the extension and then open. This happens with Groupon when I try to print a voucher for instance. Furthermore, when I download an executbale (.exe) it changes the extension. It is like there is a remapping of the period to an underscore for anything but .htm or .html. [EricLaw]: This is a configuration problem somewhere on your machine. Please contact me using the link at the top-right to let us investigate.Anonymous
February 27, 2012
Very cool - thanks for the help. Was able to get it working via: string attachment = "attachment; filename=" + rptName + ".xls" + ""; HttpContext.Current.Response.Clear(); HttpContext.Current.Response.ClearHeaders(); HttpContext.Current.Response.AddHeader("content-disposition", attachment); HttpContext.Current.Response.AddHeader("Cache-Control", "private, max-age=1"); HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"; HttpContext.Current.Response.Charset = ""; HttpContext.Current.Response.Buffer = true; HttpContext.Current.Response.Cache.SetExpires(DateTime.Now.AddMinutes(1));Anonymous
April 04, 2012
We had the exact same issue. In our case the problem was caused by McAfee HBSS/IDSAnonymous
June 25, 2012
This is for the one other person in the world that will run in to this: I have some old code that uses the Tabular Data Control (msdn.microsoft.com/.../ms531356%28v=vs.85%29.aspx). I ran in to this issue when I had a script that generates a CSV file. In the headers I had a Pragma: no-cache. This file was then being consumed by the TDC over https. In IE8, it would not display the content over https, but would over http. In IE9 it worked fine. I spent some time looking for the bug and found the problem with the header by trial and error. Then after finding it, I did a search for Pragma: no cache over https and found this site. Thanks for helping me to see what was causing the error.Anonymous
June 25, 2012
The comment has been removedAnonymous
September 20, 2012
When I download any file over HTTPS, the resulting file is corrupt. Using the same code over HTTP is fine. I've tried various combinations of: Response.AddHeader "Cache-Control", "private, max-age=15" Response.AddHeader "Pragma", "no-cache" Response.AddHeader "cache-control", "no-store, must-revalidate, private" Response.AddHeader "Cache-Control", "no-store, no-cache" at different code locations. Do these lines need added at a certain location, e.g. before adding other headers?Anonymous
September 21, 2012
@Tito: Can you explain what specifically is "corrupt" in the cases you're referring to? What browser are you using, and what are the final set of headers?Anonymous
November 08, 2012
i've seen the same issue when trying to "view source" of an xml file. If my web-server tells the browser "do not cache", then Internet Explorer does as it's told, and saves no copy of the file. The logic of the (original) situation seems "reasoanble" when you explain it that way. How can an external program (like Excel or Notepad) open a file off the hard-drive, when Internet Explorer has been told not to save a copy. One reason for specifying "no-cache" is so that the browser will always get a "fresh" copy of the server. Another reason can be that the information is somewhat sensitive, and we'd rather you didn't keep a copy on the hard-drive if at all possible.Anonymous
November 11, 2012
Having much the same problem: Using IE9-x64 on Windows 7 Ultimate. NOT using "do not save encrypted pages". HAVE set BypassSSLNoCacheCheck=1. STILL cannot save downloads from banks to disk using IE9. Can do this with Mozilla. What's going on?Anonymous
January 07, 2013
We've experienced this problem with IE8 and Pentaho. Unable to download reports generated by the system using IE8 but could using IE9 and other browsers when using SSL. In the end we fronted it with an Apache server doing SSL termination, and configured Apache with "mod_headers" to remove the offending headers. This didn't work on it's own, we also had to disable the "Do not store encrypted pages to disk" setting.Anonymous
October 23, 2013
I've changed Cache-Control: and Pragma: and downloads in IE8 through SSL now work but only if you type the URL into the address bar. If you click on the link in an email it still gives the error. Fiddler shows that in both cases the headers are identical. What gives? EricLaw: And what, exactly, are the headers in question?Anonymous
October 24, 2013
Thank you for a very interesting and hopefully useful blog. I have the opposite problem. Getting IE (10) to stop caching my page. I have an .aspx that draws (bars using System.Drawing and the bitmap i then saved as a physical but temporary .png and rendered whit an htmlImage scr=...png. There is a dropdown (time) causing postbacks but the images are never regenerated due to caching. Chrome and FireFox works fine but IE just don't quitAnonymous
October 24, 2013
@Tomas: What are the exact headers on the HTTP response? One very rare issue I've seen with ASP.NET partial-page updates is that images with unchanged URLs can be reused out of Trident's per-page image cache, so request doesn't even go to the network stack where cache headers would be evaluated. But this is very rarely the issue, the most common problem is failure to set proper headers on the response.Anonymous
October 25, 2013
@EricLaw: Thanks for the response. In both cases the headers are identical and as follows: HTTP/1.1 200 OK
Date: Thu, 24 Oct 2013 02:46:03 GMT
Server: Apache/2.2.16 (Debian)
Vary: Host
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache
Pragma: private
Content-Disposition: attachment; filename="19062351.doc"
Content-Length: 4905
Connection: close
Content-Type: text/rtf Again, pasting or typing the URL into the address bar works but clicking on it in an email does not. Interestingly, sometimes the first time you paste it into the address bar you get the same error but clicking go or hitting enter a second time works. This is IE8 on WinXP. Prior to setting Cache-Control: no-store, no-cache and Pragma: private the links were never working in IE8, now they are working just not when clicked on in an email. I've also tried the other variations for Cache-Control: listed on this page and the behavior stays the same. Thanks Eric I really appreciate your feedback, I can't find any solution for this online, everything just mentions the Cache-Control: and Pragma: headers that I think I already have set correctly. [EricLaw] Remove the meaningless Pragma header. Remove the Vary header. Change the Cache-Control header to be Cache-Control: private, max-age=10. DevinAnonymous
October 26, 2013
Thank you so much Eric, for the response. The Pragma: and Vary: headers were being set if I didn't specify them so I looked into explicitly removing them. You were right, that and changing Cache-Control to 'private, max-age=10' did the trick. Its working now with these headers: HTTP/1.1 200 OK Date: Sat, 26 Oct 2013 20:02:32 GMT Server: Apache/2.2.16 (Debian) Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: private, max-age=10 Content-Disposition: attachment; filename="19062351.doc" Content-Length: 4905 Connection: close Content-Type: text/rtf For those who are interested, I'm using PHP and this is the code I used to get it working: // check for IE only headers if (isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false)) { header('Cache-Control: private, max-age=10'); header_remove('Pragma'); header_remove('Vary'); } Thanks again Eric, I really appreciate your help on this.