How to secure an authentication cookie without SSL
authentication, cookies, php
Solution
Introduction
Why do you want to authenticate cookie when that is exactly what sessions are going ? If you want to change the `ID` you can easily achieve that with `session_regenerate_id` as @MarcB has pointed.
My Assumptions
I want to assume i did not understand the question clearly and probably this is what you want to achieve
- Store Values to Cookie
- Know if such values have been modified
You solved it already
I could resort to a salt, random key then use hash_hmac to sha512 the salt+key and save that as the cookie...
That is exactly the the solution but you need to note that
- Session Can Sill be hijacked
- PHP has better ways of generating random strings
- Imagine the overhead having to updated your mysql table every time for something sessions can easily do for you
- using `hash_hmac 512` would generate `126` in hex format you need to understand that there is Browser Cookie Limits so i suggest you reduce it to `256`
Your Solution Modified
If we are going to use your solution we need some little modification
session_start();
// Strong private key stored Securly stored
// Used SESSION For demo
$privateKey = isset($_SESSION['key']) ? $_SESSION['key'] : mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
$my = new SignedCookie($privateKey);
$my->setCookie("test", "hello world", time() + 3600);
echo $my->getCookie("test");
Output
hello world
But the Data was stored like this :
This just uses `hash_hmac` to sign and verify your values and also uses a random variable to make sure the bad guys are not able to build table of possible values because really they don't have to break the hash .. the can just study it can also use a valid one previously used eg.
10 Cookies = AAAA
1 Cookie = BBBB
He can login with valid session and changed cookies from `BBBB` to `AAAA` so even if you re not storing to database always include a random argument
You can also still remove the cookies like this :
$my->setCookie("test", null, time() - 3600);
Simple Class Used
class SignedCookie {
private $prifix = '$x$';
private $privateKey;
function __construct($privateKey) {
$this->privateKey = $privateKey;
}
function setCookie($name, $value, $expire, $path = null, $domain = null, $secure = null, $httponly = null) {
$value = $value === null ? $value : $this->hash($value, mcrypt_create_iv(2, MCRYPT_DEV_URANDOM));
return setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
}
function getCookie($name, $ignore = false) {
if (! isset($_COOKIE[$name]) || empty($_COOKIE[$name]))
return null; // does not exist
if ($ignore === false) {
if (substr($_COOKIE[$name], 0, 3) !== $this->prifix)
return - 1; // modified
$data = pack("H*", substr($_COOKIE[$name], 3)); // Unpack hex
$value = substr($data, 32, - 2); // Get Value
$rand = substr($data, - 2, 2); // Get Random prifix
if ($this->hash($value, $rand) !== $_COOKIE[$name])
return - 1; // modified
return $value;
}
return $_COOKIE[$name];
}
function hash($value, $suffix) {
// Added random suffix to help the hash keep changing
return $this->prifix . bin2hex(hash_hmac('sha256', $value . $suffix, $this->privateKey, true) . $value . $suffix);
}
}
Conclusion
You are not a security expert Just Use so just use SSL (SSL also has its issues but far better) or Look for an existing secure authentication service. @ircmaxell reminded me of Schneier's Law recently :
@Baba: "surprise" is the enemy of security. The ONLY thing that should be secret is the private key. Remember Schneier's Law: Anyone can invent an encryption scheme that they themselves can't break. My answer is based on tried and true cryptographic principles.
well i think you should take to that advice too.
Problem
I am in the process of creating a login system which uses both sessions (for those who disallow the use of cookies (to agree with the cookie law.. I am using the site http://www.cookielaw.org/the-cookie-law.aspx as a reference) Now, I have this system for my cookie authentication ``` function GenerateString(){ $length = mt_rand(0,25); $characters = '0123456789abcdefghijklmnopqrstuvwxyz'; $string = ''; for ($p = 0; $p < $length; $p++) { $string .= $characters[mt_rand(5, strlen($characters) -1)]; } return $string; } $RandomString = GenerateString(); $CookieAuth = $DB->prepare("INSERT INTO cookieauth (Username,RandomString) VALUES (?,?)"); $CookieAuth->bind_param('ss',$_POST['Username'],$RandomString); $CookieAuth->execute(); // Insert the Authentication Methods into the database $CookieAuth->close(); // Allow another query/statement $GetInsertID = $DB->prepare("SELECT ID FROM CookieAuth WHERE RandomString=?"); $GetInsertID->bind_param('s',$Randomstring); $GetInsertID->execute(); $GetInsertID->bind_result($RowID); $GetInsertID->fetch(); $GetInsertID->close(); setcookie("Auth[ID]",$RowID); setcookie("Auth[UName],$_POST['Username']); setcookie("Auth[RandomString]",$RandomString); ``` Then to process the cookie: ``` if(isset($_COOKIE['Auth'])){ $Authenticate = $DB->prepare("SELECT Username,RandomString FROM cookieauth WHERE ID=?"); $Authenticate->bind_param('i',$_COOKIE['Auth']['ID']); $Authenticate->execute(); $Authenticate->bind_result($RowUsername,$RowString); $Authenticate->fetch(); $Authenticate->close(); if ($_Cookie['Auth']['UName'] == $RowUsername){ if ($_COOKIE['Auth']['RandomString'] == $RowString){ header("Location: LoggedIn.php"); }else{ die("Possible Cookie Manipulation, Autologin Cannot Continue"); } }else{ die("Possible Cookie Manupulation, Autologin Cannot Continue!"); } ``` My overall objective is to provide an auto login feature by using cookies. As people should know they are essentially stored on the hard drive as plain text.. So If i include a randomly generated string which will be changed on further processing each time (then updating the cookie to match the database) is this a reasonably secure way to achieve the task? I mean, I understand that this is not 100% secure due to some users might attempt to manipulate the random string, so I could resort to a salt, random key then use `hash_hmac` to sha512 the salt+key and save that as the cookie... My overall question, is the chunks I have provided a semi-secure method to process automatic logins via cookies and can minimize the possibility of some bad guys manipulating the keys to achieve the required data?