More Than Just Web Design | INTERNET ENGINEERING | APPLICATION | DESIGN
JeRo And The Beanstalk
Amazon's Elastic Beanstalk - The Magic Vanishing PHP Session Fairy Story
We've been working on an online booking system for a client and it became apparent that due to the time sensitive high demand nature of the application, a scalable server was needed. This seemed like a job for Amazon's AWS, specifically their Elastic Beanstalk.
We built the application using Concrete5, our preferred CMS, and everything was good. Until we moved it to Beanstalk. We noted that after a couple of minutes of inactivity, the PHP session would be lost. Reading through the documentation indicated some potential issues:
- Using "sticky" load balancing to tie a session to a machine instance might be necessary
- Specific instances can terminate, which looses the session files.
Storing sessions in DynamoDB ought to resolve these issues, since it will serve the session data across many instances, a bit like the RDS MySQL database we were using.
Fortunately another project had already necessitated the use of Amazon's DynamoDB to hold session data, so we plugged that in. But still sessions were lost. The data was visible in Dynamo, but it wasn't getting used. The browser was sending the session cookie, but Concrete5 was sending a new session cookie back. Something was spitting the cookie out rather than chewing on it.
After a bit of investigation into the way Concrete5 handles sessions, we found some code in concrete/startup/session.php to prevent session fixation. Among other things this checks that the IP address of the request matches with the one stored in the session, and if it doesn't, it regenerates the session ID and clears the session data.
And that's when the penny dropped - all the IP addresses we see presented to the machine instance and DynamoDB are internal load balancer IP addresses staring 172.x.x.x and they tend to vary. The load balancer is a sort of reverse proxy so you never see the real world IP. The solution was to comment out the session fixation check, and that sorted the problem.
Thinking this through a bit more, the load balancer sets the typical proxy headers such as HTTP_X_FORWARDED_FOR which mean that it ought to be possible to update the code to look for $_SERVER['HTTP_X_FORWARDED_FOR'] instead of $_SERVER['REMOTE_HOST'] and thus restore the session fixation check.
My only concern is that HTTP_X_FORWARDED_FOR may not always be an IP address - as this post points out.