Session data not being stored

145 views
Skip to first unread message

Juan Aguilar

unread,
Nov 4, 2015, 4:16:20 PM11/4/15
to Lucee
Anybody have any idea for reasons why session data would not be saved across requests (like, the very definition of session data)?!

I get to a certain page in my process and my home-grown CSRF validation stops working. With each page request I check to see if a token for that page is stored in the session scope. If not, I create the token, store it in the session scope, submit the token through a hidden form field, then check the hidden form field against the token stored in the session scope. Standard stuff.

if (!isDefined("session.tokens.employee.contributions.token")){
 
"session.tokens.employee.contributions" = {
 
"token": LCase(Hash("#CreateUUID()#employee.contributions#RandRange(10000,99999)#", "SHA-256")),
 
"expires": dateAdd("h", 2, Now())
 
}
}

<input type="hidden" id="csrftoken" name="csrftoken" value="#session.tokens.employee.contributions.token#"/>

if (session.tokens.employee.contributions.token != form.csrftoken){
 variables
.isValidToken = false;
}

What is happening is that, when I submit the form, the page does not find a token for that page in the session scope so it creates a new token. Since the new token doesn't match the form token, then isValidToken is false. But it's only happening once I get to this stage in my process, never earlier.

So I decided to try using CSRFGenerateToken and CSRFVerifyToken instead but I am finding the same result. Even when CSRFGenerateToken has forceNew set to false, a new token is being generated for the key on that page.

My sessions have nested structs in them and I briefly considered that the name "session.tokens.employee.contributions" was somehow reserved. I'm also using cfml sessions, a datasource for session storage, and sessionCluster = true. This is happening in multiple environments (dev, uat, demo) which are all similarly configured but run on different hardware.

Any ideas? On dev I'm running:

Version Lucee 4.5.2.017 final
OS Mac OS X (10.11.2) 64bit
Servlet Container Apache Tomcat/8.0.15
Java 1.7.0_65 (Oracle Corporation) 64bit

I can see that the session data is not being stored to the database. Any reason why this should be the case?

Thanks!

Juan Aguilar

unread,
Nov 4, 2015, 5:38:47 PM11/4/15
to Lucee
Looking at this a little closer, before checking the session token, there's a case where I'm logging an error to my BugLogHQ server. Since it's an http request, I run that in a thread:

thread name="errorReport" {
     application
.bugLogService.notifyService(message="The default date for the account is invalid.", extraInfo=form, severityCode="INFO");
}

It appears that, if I start a new thread, the current page session is not written to the database. Or, maybe it's a race condition and both the main thread and the errorReport thread both cause the session scope to be written to the database with the errorReport thread winning out.

Will test and update.

Juan Aguilar

unread,
Nov 5, 2015, 10:52:24 AM11/5/15
to Lucee
OK. Now I'm pretty sure that the issue is that a cfthread call overwrites the session scope.

The attach code outputs the session scope via cflog. If there is no delay in the thread, then there is no issue. You can hit submit to your hearts content. But if I introduce a delay (in this case via url.sleepTimer), then a running thread eventually overwrites the session scope with the version that it had when it was run. In the code that revealed this problem, the delay was introduced by an http call within the thread.

I'm honestly not sure if this is expected behavior or a bug. Should a thread be able to write to a shared scope after the requesting page finishes processing?

Note that this problem only occurs when this.sessionCluster=true.
20151104.cfm

Jon Clausen

unread,
Nov 5, 2015, 11:29:09 AM11/5/15
to lu...@googlegroups.com

If you want the thread to use the existing session scope, then you need to pass it in as a parameter:

        SESSION.someSetting= true;
        SESSION.someOtherSetting = 'Yes';

        //note that we are explicitly passing in the shared scope to use
        thread action="run" name="TestSharedScope" session=SESSION {
            SESSION.someOtherSetting = "NO";
        }

        thread name="TestSharedScope" action="join";
         
        //Now the session will reflect the change to our shared scope
        writeDump(var=SESSION,top=1);
        abort;

By design, a thread cannot use any object unless it is explicitly passed in to the thread. Since the SESSION scope is a global of the server, if the scope is not passed in for use, the server creates a new one.

--
Love Lucee? Become a supporter and be part of the Lucee project today! - http://lucee.org/supporters/become-a-supporter.html
---
You received this message because you are subscribed to the Google Groups "Lucee" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lucee+un...@googlegroups.com.
To post to this group, send email to lu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lucee/81eb85df-f378-4496-9c0a-c3400f325ecf%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jon Clausen

unread,
Nov 5, 2015, 11:37:55 AM11/5/15
to lu...@googlegroups.com
Oh, and for the record, I find this thread behavior extremely problematic (which is why I’ve advocated in the past for some sort to asyc Promise functionality that has access to existing variables and scopes), but the current behavior with shared scopes has been the status quo since the initial implementation of <cfthread>.

Juan Aguilar

unread,
Nov 5, 2015, 1:53:52 PM11/5/15
to Lucee
Thanks for your reply, Jon. I don't want to access the session scope in the thread. I want the longer running thread to not overwrite the session scope. What I'm seeing is the following:
  1. First, "Request 1" creates session.page1 and runs "Thread 1" which makes no changes to the session scope.
  2. Next, "Request 2" creates session.page2. (Now the session scope contains session.page1 and session.page2.)
  3. "Thread 1" finishes running and causes the session scope to be saved to the datasource. This only contains session.page1.
  4. Finally, "Request 3" does not find session.page2 since "Thread 1" overwrote the scope in Step 3 above.
This only happens when this.sessionCluster=true, probably because the lag in writing to the database is so much greater than writing to memory.

So, as a workaround, I'm ditching the threads, but I'm still wondering if threads should modify shared scopes.

 

Jon Clausen

unread,
Nov 5, 2015, 2:18:25 PM11/5/15
to lu...@googlegroups.com

I see. In an async situation, of course, your session keys will be out of sync. That said, if you explicitly pass in the session scope, you should see the reference maintained according to the sequence in which those are modified:

structClear(session);
SESSION.otherValue= true;
SESSION.somevalue = 'Yes';
SESSION.page1='/page1';

thread action="run" name="TestSharedScope" session=SESSION {
    SESSION.somevalue = "NO";
}

thread name="TestSharedScope" action="join";

thread action="run" name="TestSharedScope2" session=SESSION {
    thread name="TestSharedScope2" action="sleep" duration=4000;
    SESSION.someOthervalue = "Here is my new value";
}
//We won't see SESSION.someOtherValue yet because of the sleep
writeDump(var=session,top=1);



SESSION.page2='/page2';

thread name="TestSharedScope2" action="join";

//Now the session will reflect all the changes made to our shared scope
writeDump(var=SESSION,top=1);
abort;

That said, modifying anything in the scope that involves out-of-sequence database writes is probably a recipe for failure. If you need access to the existing session scope, in the the thread, I would suggest passing it in as a new variable via duplicate(session) so that any setting of keys to the actual scope is done outside of the thread.

--

Love Lucee? Become a supporter and be part of the Lucee project today! - http://lucee.org/supporters/become-a-supporter.html
---
You received this message because you are subscribed to the Google Groups "Lucee" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lucee+un...@googlegroups.com.
To post to this group, send email to lu...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages