Home > Apex, force.com Sites, Visualforce > Serious Force.com Cookie Security Issue

Serious Force.com Cookie Security Issue

June 25th, 2010

UPDATE:
Before you read the update I would encourage you to read the original article below first.

This is not a bug but an expected issue with the way force.com sites pages are cached. For some reason in my crazy head I thought the only items cached on pages where the html structure, images, css, etc. I thought that even on cached pages the controller would execute on every load of the page. This is not true. The controller will only execute once when a page is not cached. Any subsequent visits while the page is cached will not cause the controller to execute. So if you are populating dynamic data on the page with Apex it will stay there for the next 10 minutes.

This becomes a major issue with pages that depend on cookies and customizing the site content per visit.

I’ve recommended that salesforce.com update their documentation with two big red bold updates:
1) Cached pages will not execute the controller on load
2) Pages that use cookies to display dynamic data should never be cached

I hope this is helpful to someone out there as I definitely learned something today.

Additional info can be found here: dev board post.

-Jason


Original Post:

I have discovered a major bug with the new cookie feature released in the Summer 10 edition of salesforce.com. Let’s get straight to the point. Cookie data is being passed across different browsers, different computers, and different users. Yes, you heard this right. Sounds unbelievable so I created a video that shows this happening. Clearly this is a major issue if you are storing session or personal information in cookies.

Before anyone rips into me for blogging about what could be a very significant security issue I have already notified salesforce.com and it is a high priority issue. I also believe it is best to get this information out to other force.com developers before they build something that depends on this functionality and this issue causes major problems for them.

At this point I highly recommend not using the new cooking feature until more information about this issue or a fix is released.

Page:

<apex:page controller="CookieBug" expires="60">
    <apex:form >
        <apex:inputText value="{!input}"/>
        <apex:commandButton value="Update Cookie" action="{!updateCookie}"/>
    </apex:form>
</apex:page>

Controller:

public class CookieBug{
 
    public String input {get; set;}
 
    public CookieBug(){
        //Autofill input based on cookie value
        Map<String,Cookie> cookies = ApexPages.currentPage().getCookies();
        if(cookies.size() > 0){
            if(cookies.get('myCookie') != null){
                input = cookies.get('myCookie').getValue();
            }
        }
    }
 
    public void updateCookie(){
        List<Cookie> cookies = new List<Cookie>();
        Cookies.add(new Cookie('myCookie',input,null,15552000,false));
        ApexPages.currentPage().setCookies(cookies);
    }
}
  1. Richard Vanhook
    June 25th, 2010 at 08:02 | #1

    Wow that’s bad. Always better to shed light on issues like this as opposed to not. Thanks for posting.

  2. Bulent Cinarkaya
    June 25th, 2010 at 09:19 | #2

    Jason,

    Thank you for the post. We are testing this use case. We’ll take the necessary actions.

  3. Mom
    June 25th, 2010 at 09:30 | #3

    Jason, I am not sure what I am more impressed with – the bug you found or watching the video with the little curser moving all over by itself. You know I always thought that remote thing was pretty cool. Yep, I am easily entertained! Hope my posts get a smile out of you! Mom

  4. Richard Tuttle
    June 25th, 2010 at 09:53 | #4

    Ouch. Nice catch Jason. Guess I won’t be using cookies anytime soon.

  5. Bulent Cinarkaya
    June 25th, 2010 at 10:19 | #5

    Jason,

    Sites in production orgs are out of the box integrated with a Content Delivery Network to provide global caching and traffic shaping. All unauthenticated pages via HTTP access are cached for 10 minutes if you don’t specify otherwise. Caching is controlled via the apex page cache and expires attributes. There is no caching in place if any of the following is true:

    1- if you authenticate site visitors (via portal integration)
    2- if your request is a HTTPS request
    3- if you set cache=”false” for your page

    In your example your page is cached for 10 minutes. So, it’s the Page that’s cached, not the cookie.

    Your code is reflecting the cookie value back in the page, and the content of that page gets cached.

    We do not think this is a bug. You can disable the caching for your page for your use case.

    - Bulent

  6. June 25th, 2010 at 10:29 | #6

    Interesting. I’d recommend installing Fiddler2 and observing the raw HTTP headers.
    http://www.fiddler2.com/fiddler2/

    I suspect a browser config anomaly.

  7. June 25th, 2010 at 11:11 | #7

    Wow. Very interesting. I fully agree that they need to update the documentation re caching.

    Excellent work!

    Mike

  8. June 25th, 2010 at 11:18 | #8

    Omitting the cache attribute in a DE org results in no caching. However, a missing cache attribute in Production defaults to 10 minutes. I’ve found this to be the source of many panicky moments :-)

  9. Paul
    December 18th, 2010 at 20:04 | #9

    i had a question on this logic. i understand that the page caches the controller state, and that it looked like cookie values being cached. does this same logic hold true for pages that depend on a URL parameter to determine dynamic content to be rendered? example, a renderer for a knowledge article. you pass article ID to the page via URL param. will the CDN cache the first article to be viewed and return that for every request to the page (basically, omitting the logic based on URL param), or is it only caching by full URL, including params?

  10. December 22nd, 2010 at 08:49 | #10

    Hey Paul,

    I am pretty sure that if the page is dynamic in anyway per view it should not be cached. The HTML structure of the page is what is cached and nothing in controller is executed. So if your rendered logic is in the controller it will not work correctly. Even if you are doing something like this: rendered={!$CurrentPage.parameters.theater == 1} , I think it will only work on the first uncached visit and then subsequent requests for the page will returned the cached html page. I am not positive on this but it would be easy enough to test.

    Let me know if that does or does not answer your question.

    -Jason

  11. Paul
    December 22nd, 2010 at 10:03 | #11

    Thanks Jason, that does make sense. We launched the site this morning, and it looks like the stuff I’m caching, and not caching, is working the way I’d expect. Regarding the controller-fed dynamic rendering stuff, I have to imagine that isn’t true. If it is, it’d severely devalue the usefulness of the platform. Any cheap VPS host can deliver CDN-powered static HTML. The whole point of Sites is to do that, but to also be rich in design, functionality, and data integration. If it isn’t, Salesforce has a big lemon on their hands. Ya know?

  12. December 22nd, 2010 at 16:36 | #12

    Oh it is true. On initial load of the page nothing in the controller executes if the page is cached. This can be confirmed by monitoring debug logs. Page will load but constructor will never execute and get methods will not be called.

    Keep in mind this is on initial load only. If after load you have some sort of ajax rerender/rendered logic this will work ok.

  13. Paul
    December 22nd, 2010 at 16:41 | #13

    Lame. Well, I set cache to false pretty much always, so I should be ok. sites is basically worthless I regards to the CDN for that reason though, because you still go through it, which make noncached page that much slower. Sounds like I need to have a chat with them on how a real company does scalable websites…