Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cookie blocked/not saved in IFRAME in Internet Explorer

I got it to work, but the solution is a bit complex, so bear with me.

What's happening

As it is, Internet Explorer gives lower level of trust to IFRAME pages (IE calls this "third-party" content). If the page inside the IFRAME doesn't have a Privacy Policy, its cookies are blocked (which is indicated by the eye icon in status bar, when you click on it, it shows you a list of blocked URLs).

the evil eye
(source: piskvor.org)

In this case, when cookies are blocked, session identifier is not sent, and the target script throws a 'session not found' error.

(I've tried setting the session identifier into the form and loading it from POST variables. This would have worked, but for political reasons I couldn't do that.)

It is possible to make the page inside the IFRAME more trusted: if the inner page sends a P3P header with a privacy policy that is acceptable to IE, the cookies will be accepted.

How to solve it

Create a p3p policy

A good starting point is the W3C tutorial. I've gone through it, downloaded the IBM Privacy Policy Editor and there I created a representation of the privacy policy and gave it a name to reference it by (here it was policy1).

NOTE: at this point, you actually need to find out if your site has a privacy policy, and if not, create it - whether it collects user data, what kind of data, what it does with it, who has access to it, etc. You need to find this information and think about it. Just slapping together a few tags will not cut it. This step cannot be done purely in software, and may be highly political (e.g. "should we sell our click statistics?").

(e.g. "the site is operated by ACME Ltd., it uses anonymous per-session identifiers for its operation, collects user data only if explicitly permitted and only for the following purposes, the data is stored only as long as necessary, only our company has access to it, etc. etc.").

(When editing with this tool, it's possible to view errors/omissions in the policy. Also very useful is the tab "HTML Policy": at the bottom, it has a "Policy Evaluation" - a quick check if the policy will be blocked by IE's default settings)

The Editor exports to a .p3p file, which is an XML representation of the above policy. Also, it can export a "compact version" of this policy.

Link to the policy

Then a Policy Reference file (http://example.com/w3c/p3p.xml) was needed (an index of privacy policies the site uses):

<META>
  <POLICY-REFERENCES>
    <POLICY-REF about="/w3c/example-com.p3p#policy1">
      <INCLUDE>/</INCLUDE>
      <COOKIE-INCLUDE/>
    </POLICY-REF>
  </POLICY-REFERENCES>
</META>

The <INCLUDE> shows all URIs that will use this policy (in my case, the whole site). The policy file I've exported from the Editor was uploaded to http://example.com/w3c/example-com.p3p

Send the compact header with responses

I've set the webserver at example.com to send the compact header with responses, like this:

HTTP/1.1 200 OK 
P3P: policyref="/w3c/p3p.xml", CP="IDC DSP COR IVAi IVDi OUR TST"
// ... other headers and content

policyref is a relative URI to the Policy Reference file (which in turn references the privacy policies), CP is the compact policy representation. Note that the combination of P3P headers in the example may not be applicable on your specific website; your P3P headers MUST truthfully represent your own privacy policy!

Profit!

In this configuration, the Evil Eye does not appear, the cookies are saved even in the IFRAME, and the application works.

Edit: What NOT to do, unless you like defending from lawsuits

Several people have suggested "just slap some tags into your P3P header, until the Evil Eye gives up".

The tags are not only a bunch of bits, they have real world meanings, and their use gives you real world responsibilities!

For example, pretending that you never collect user data might make the browser happy, but if you actually collect user data, the P3P is conflicting with reality. Plain and simple, you are purposefully lying to your users, and that might be criminal behavior in some countries. As in, "go to jail, do not collect $200".

A few examples (see p3pwriter for the full set of tags):

  • NOI : "Web Site does not collected identified data." (as soon as there's any customization, a login, or any data collection (***** Analytics, anyone?), you must acknowledge it in your P3P)
  • STP: Information is retained to meet the stated purpose. This requires information to be discarded at the earliest time possible. Sites MUST have a retention policy that establishes a destruction time table. The retention policy MUST be included in or linked from the site's human-readable privacy policy." (so if you send STP but don't have a retention policy, you may be committing fraud. How cool is that? Not at all.)

I'm not a lawyer, but I'm not willing to go to court to see if the P3P header is really legally binding or if you can promise your users anything without actually willing to honor your promises.


I've spend a large part of my day looking into this P3P thing and I feel the need to share what I've found out.

I've noticed that the P3P concept is very outdated and seems only to be really used/enforced by Internet Explorer (IE).

The simplest explanation is: IE wants you to define a P3P header if you are using cookies.

This is a nice idea, and luckily most of the time not providing this header won't cause any issues (read browser warnings). Unless your website/web application is loaded into an other website using an (i)Frame. This is where IE becomes a massive pain in the ***. It will not allow you to set a cookie unless the P3P header is set.

Knowing this I wanted to find an answer to the following two questions:

  1. Who cares? In other words, can I be sued if I put the word "Potato" in the header?
  2. What do other companies do?

My findings are:

  1. No one cares. I'm unable to find a single document that suggests this technology has any legal weight. During my research I didn't find a single country around the world that has adopted a law that prevents you from putting the word "Potato" in the P3P header
  2. Both Google and Facebook put a link in their P3P header field referring to a page describing why they don't have a P3P header.

The concept was born in 2002 and it baffles me that this outdated and legally unimplemented concept is still forced upon developers within IE. If this header doesn't have have any legal ramifications this header should be ignored (or alternatively, generate a warning or notification in the console). Not enforced! I'm now forced to put a line in my code (and send a header to the client) that does absolutely nothing.

In short - to keep IE happy - add the following line to your PHP code (Other languages should look similar)

header('P3P: CP="Potato"');

Problem solved, and IE is happy with this potato.


I was able to make the evil eye go away by simply adding this small header to the site in the IFrame (PHP solution):

header('P3P: CP="NOI ADM DEV COM NAV OUR STP"');

Remember to press ctrl+F5 to reload your site or Explorer may still show the evil eye, despite the fact that it's working fine. This is probably the main reason why I had so many problems getting it to work.

No policy file was neccesary at all.

Edit: I found a nice blog entry that explains the problem with cookies in IFrames. It also has a quick fix in C# code: Frames, ASPX Pages and Rejected Cookies


This is buried in the comments of other answers, but I almost missed it, so it seems like it deserves its own answer.

To review: in order for IE to accept 3rd party cookies, you need serve your files with an http header called p3p in the format:

CP="my compact p3p policy"

BUT, p3p is pretty much dead as a standard at this point and you can easily get IE to work without investing the time and legal resources in creating a real p3p policy. This is because if your compact p3p policy header is invalid, IE actually treats it as a good policy and accepts 3rd party cookies. So you can use a p3p header such as this

CP="This site does not have a p3p policy."

You can optionally include a link to a page that explains why you don't have a p3p policy, as Google and Facebook do (they point here: https://support.google.com/accounts/answer/151657 and here: https://www.facebook.com/help/327993273962160/).

Finally, it's important to note that all files served from the 3rd party site need to have the p3p header, not just the one that sets the cookie, so you may not be able to just do this in your PHP, asp.net, etc code. You are probably better off setting in up on the web server level (i.e. in IIS or Apache).


I had this issue as well, thought I'd post the code that I used in my MVC2 project. Be careful when in the page life cycle you add in the header or you'll get an HttpException "Server cannot append header after HTTP headers have been sent." I used a custom ActionFilterAttribute on the OnActionExecuting method (called before the action is executed).

/// <summary>
/// Privacy Preferences Project (P3P) serve a compact policy (a "p3p" HTTP header) for all requests
/// P3P provides a standard way for Web sites to communicate about their practices around the collection, 
/// use, and distribution of personal information. It's a machine-readable privacy policy that can be 
/// automatically fetched and viewed by users, and it can be tailored to fit your company's specific policies.
/// </summary>
/// <remarks>
/// More info http://www.oreillynet.com/lpt/a/1554
/// </remarks>
public class P3PAttribute : ActionFilterAttribute
{
    /// <summary>
    /// On Action Executing add a compact policy "p3p" HTTP header
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpContext.Current.Response.AddHeader("p3p","CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"");

        base.OnActionExecuting(filterContext);
    }
}

Example use:

[P3P]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewData["Message"] = "Welcome!";

        return View();
    }

    public ActionResult About()
    {
        return View();
    }
}