title: Preventing Numerous Devices Concurrently signed into a Single User Account
body: <p>I have a functioning authentication, ACL and session management system for my online software application. As this is a paid service on a per-user account basis, I need to ensure that a user account cannot be shared between employees in the same fashion that  PayPal manages business accounts. </p>
  
  <p>My struggle is finding a way to do achieve such functionality that a competent, technical user couldn't circumvent via modifying Javascript or using a client side proxy. </p>
  
  <p>Currently, each company account has a database on my server with a "session" table that consists of <code>session_id (PK), session_user, session_data, client_ip, timestamp_created</code> and <code>timestamp_updated</code> columns. Whenever a user logs in, the <code>session_user</code> column is updated with their login name. Should another person log into that account on a different machine, the previously accessed account will have the session_user column set to <code>NULL</code>. The result is that no two rows should have the same value for <code>session_user</code>. Possibly worth noting is that customers do not have administrative access to their database.</p>
  
  <p>The client-side application runs a Javascript function on a timer every 5 seconds which performs an AJAX call to a Zend Controller. This controller checks the <code>session_user</code> column for the active session via a DB query using <code>Zend_Session::getId();</code>. This method <code>echo</code>'s a JSON encoded response with <code>success</code> set to <code>TRUE</code> if the <code>session_id</code> has an associated <code>session_user</code> in the database, or <code>FALSE</code> if there is no value in the <code>session_user</code> column. In the event that the method returns <code>FALSE</code>, the Javascript function proceeds to alert the user that another machine has logged into their account, and then redirects them to the login page. </p>
  
  <p>The problem with this approach is that anyone with experience in Chrome's inspector or Mozilla's FireBug can remove the Javascript that performs the AJAX call and proceed to use the application on numerous machines. Worse yet, this easy method is only the beginning of vulnerabilities. </p>
  
  <p>I have a feeling that I will need to look into Zend's plugin architecture, perhaps implementing a check during <code>preDispatch()</code> to ensure that the current <code>session_id</code> has value set in the corresponding <code>session_user</code> table. This check would be complimentary to my current structure, as I feel that the majority of my users will not be well versed in basic "hacking" per se, and will do just find to prevent account sharing. If this server-side check fails, as it occurs when a resource is requested, an error could be thrown and the requested data would not be pushed to the front end (e.g. the data for viewing products).</p>
  
  <p>Does this approach seem like it will work, or is there a better way of achieving such functionality? I've read a bunch of SO posts that derail into arguments regarding whether or not it is a good idea to be so cumbersome on the end-user. We have already decided that since revenue is largely based around company accounts purchasing additional user accounts that there is a significant need to prevent any sort of account sharing. Preventing the user from logging into an account with an existing session is something I want to avoid. Believe it or not, I would rather have users be annoyed by being booted out of their active session by another device logging in, as I feel this will encourage additional user licenses to be purchased.</p>
  
  <p>Please feel free to ask if you would like any additional information, or require clarification about anything I described in my post. </p>