December 7, 201015 yr I posted this on my Facebook for my CompSci friends to see, figured it'd be helpful outside of those 50 or so people. "Sidejacking" is when a hacker uses a packet-sniffer to detect the login auth cookie and uses that cookie data himself to pretend to be authorised on a website. This is possible because mostly what we do to say that a user is authorised is create a unique hash (using sha1 or similar) and store it in both the database and the cookie: salt = sha1( username + password + time() ) cookie['login'] = salt database.write( login = salt ) Then to check that the user is authorised, we do if( database.get_where( login = cookie['login'] ) ) ... Sidejacking works because the cookie can be used from any location. How to stop this? Add some user-specific data (IP and user agent) based encryption and store two different hashes like so: salt = sha1( username + password + time() ) cookie['login'] = salt database.write( login = sha1( salt + IP + UA ) ) if( database.get_where( login = sha1( cookie['login'] + IP + UA ) ) ... Now a sidejacking attempt can't work because the IP and UA is required to transmute from the cookie salt to the DB salt. Simples Note that this won't stop all attacks - the UA is not unique to each user and sidejacking often occurs within the same network (so the IP is shared beyond the router), but it will stop most of the rudimentary attempts when you can't get SSL running throughout the site. (The easiest and most complete method of stopping sidejacking is using SSL (https) encryption for all authorised pages so that cookies/sessions can't be grabbed by a packet sniffer. However, that's not always a possibility due to server or cost restraints.)
December 7, 201015 yr I posted this on my Facebook for my CompSci friends to see, figured it'd be helpful outside of those 50 or so people. "Sidejacking" is when a hacker uses a packet-sniffer to detect the login auth cookie and uses that cookie data himself to pretend to be authorised on a website. This is possible because mostly what we do to say that a user is authorised is create a unique hash (using sha1 or similar) and store it in both the database and the cookie: salt = sha1( username + password + time() ) cookie['login'] = salt database.write( login = salt ) Then to check that the user is authorised, we do if( database.get_where( login = cookie['login'] ) ) ... Sidejacking works because the cookie can be used from any location. How to stop this? Add some user-specific data (IP and user agent) based encryption and store two different hashes like so: salt = sha1( username + password + time() ) cookie['login'] = salt database.write( login = sha1( salt + IP + UA ) ) if( database.get_where( login = sha1( cookie['login'] + IP + UA ) ) ... Now a sidejacking attempt can't work because the IP and UA is required to transmute from the cookie salt to the DB salt. Simples Note that this won't stop all attacks - the UA is not unique to each user and sidejacking often occurs within the same network (so the IP is shared beyond the router), but it will stop most of the rudimentary attempts when you can't get SSL running throughout the site. (The easiest and most complete method of stopping sidejacking is using SSL (https) encryption for all authorised pages so that cookies/sessions can't be grabbed by a packet sniffer. However, that's not always a possibility due to server or cost restraints.) This is a very good topic, I hashed the session key that is stored into the cookie or session, then check against it in the database, but your right saying use the users unique data as a backup plan.
December 7, 201015 yr Very Interesting Yh although they will only stop most attacks, I think its worth saying that SSL is only the secure way.
December 7, 201015 yr Indeed it is worth saying, and said it was in the original post. Yh thanks for posting this, Im working on a login system now and just when i think its fool proof its actualy not.
December 7, 201015 yr Yh thanks for posting this, Im working on a login system now and just when i think its fool proof its actualy not. What do you use to test if your code is secure?
December 7, 201015 yr What do you use to test if your code is secure? I use Acunetix Web Security Scanner, Its good but only spots the most ovious mistakes.
December 7, 201015 yr Author Common sense and experience are my tools - relying on the knowledge of others (either in pure form, or tool form) is also a good route. My latest login code (which I make no claims as to it's perfection) is as follows (in form of a CodeIgniter model, the best framework ever): function login( $username = false, $password = false ) { // get from object if not passed if( ! $username ) $username = $this->username; if( ! $password ) $password = $this->password; // create salt $salt = sha1( $username.$password.time() ); // update database based on username & password $this->db->where( "username", $username ); $this->db->where( "password", sha1( $password ) ); $this->db->set( "salt", sha1( $salt . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) ); $this->db->update( "users" ); // the "it didnae work" bit if( ! $this->db->affected_rows() )return false; // if it did work, get the user from the db $this->db->where( "username", $username ); $this->db->where( "password", sha1( $password ) ); $user = $this->db->get( "users" )->row(); // backup "no database" failure bit if( $user->salt != sha1( $salt . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) ) return false; // copy data to object foreach( $user as $i=>$v ) $this->$i = $v; $this->parse_settings(); // set cookie set_cookie( "natrium", $salt, 86400 * 30 ); return true; } function get() { // if user is already set, return self (true) if( $this->username && $this->id ) return $this; // unset all variables as backup foreach( array( "id", "username", "email", "password", "salt", "name" ) as $k ) $this->$k = false; $this->salt = get_cookie( "natrium" ); // get user from db where salt matches rehash $this->db->where( "salt", sha1( $this->salt . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) ); $q = $this->db->get( "users" ); if( ! $q->num_rows ) return false; foreach( $q->row() as $k=>$v ) $this->$k = $v; $this->parse_settings(); return $this; } btw: natrium is the Latin for sodium, one half of table salt (sodium chloride) and most other salts...
December 7, 201015 yr Common sense and experience are my tools - relying on the knowledge of others (either in pure form, or tool form) is also a good route. My latest login code (which I make no claims as to it's perfection) is as follows (in form of a CodeIgniter model, the best framework ever): function login( $username = false, $password = false ) { // get from object if not passed if( ! $username ) $username = $this->username; if( ! $password ) $password = $this->password; // create salt $salt = sha1( $username.$password.time() ); // update database based on username & password $this->db->where( "username", $username ); $this->db->where( "password", sha1( $password ) ); $this->db->set( "salt", sha1( $salt . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) ); $this->db->update( "users" ); // the "it didnae work" bit if( ! $this->db->affected_rows() )return false; // if it did work, get the user from the db $this->db->where( "username", $username ); $this->db->where( "password", sha1( $password ) ); $user = $this->db->get( "users" )->row(); // backup "no database" failure bit if( $user->salt != sha1( $salt . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) ) return false; // copy data to object foreach( $user as $i=>$v ) $this->$i = $v; $this->parse_settings(); // set cookie set_cookie( "natrium", $salt, 86400 * 30 ); return true; } function get() { // if user is already set, return self (true) if( $this->username && $this->id ) return $this; // unset all variables as backup foreach( array( "id", "username", "email", "password", "salt", "name" ) as $k ) $this->$k = false; $this->salt = get_cookie( "natrium" ); // get user from db where salt matches rehash $this->db->where( "salt", sha1( $this->salt . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] ) ); $q = $this->db->get( "users" ); if( ! $q->num_rows ) return false; foreach( $q->row() as $k=>$v ) $this->$k = $v; $this->parse_settings(); return $this; } btw: natrium is the Latin for sodium, one half of table salt (sodium chloride) and most other salts... wow this is impressive code!
December 7, 201015 yr Author wow this is impressive code! I'm a 3rd year Computer Science student, and have been using PHP since for about 6 years (since I was 15). I've been using CodeIgniter for around 2 years and have created plenty of commercial systems with it... so plenty of experience.
December 7, 201015 yr I'm a 3rd year Computer Science student, and have been using PHP since for about 6 years (since I was 15). I've been using CodeIgniter for around 2 years and have created plenty of commercial systems with it... so plenty of experience. CodeIgniter? Ive never used any addons, Ive always written apps from groupup? I could google, but whats it for and how good is it?
December 7, 201015 yr Author CodeIgniter is a free OS OOP HMVC framework (wooo acronyms) that prides itself on being: - lightweight (about 1.3mb memory footprint usually, which is good for it's capabilities), - extensible (true, but requires decent code skills), and - allowing minimal code to get things done (again true, again requiring good knowledge to truly exploit) It doesn't force a new microlanguage or meme on you like most frameworks, beyond gently nudging you towards following the MVC pattern. I strongly recommend you try it out for a few weeks - it's cut my code time (creation AND maintenance) dramatically whilst increasing program performance.
December 7, 201015 yr CodeIgniter is a free OS OOP HMVC framework (wooo acronyms) that prides itself on being: - lightweight (about 1.3mb memory footprint usually, which is good for it's capabilities), - extensible (true, but requires decent code skills), and - allowing minimal code to get things done (again true, again requiring good knowledge to truly exploit) It doesn't force a new microlanguage or meme on you like most frameworks, beyond gently nudging you towards following the MVC pattern. I strongly recommend you try it out for a few weeks - it's cut my code time (creation AND maintenance) dramatically whilst increasing program performance. Im setting up a blog tonight so i may have a look your coding has realy impressed me, its almost asif i carnt read it.
Create an account or sign in to comment