Hi I'm Integrating memcache in my codeigniter application,
My query change on the user selected values. some thing like this
$sql='select * from user where user_name="'.$name.'" and location='".$location."'";
$result = $this->memcached_library->get(md5($sql));
if(!$result ){
/* execute query and get $result */
$this->memcached_library->add(md5($sql), $result );
}else{
return $result;
}
This is my approach to handle the keys for each different query. But I have heard some where that md5() is not always unique.?
1> Is md5() always unique?
2> if md5() is not unique than what shoud be the other option....
3> what about crc32() is that unique??
Thanks....
A. Your SQL is wrong it should be
$sql = "select * from user where user_name = '{$name}' and location = '{$location}'";
B. You code might have errors since MD5 is case sensitive
See
var_dump(md5("A"),md5("a"));
Output
string '7fc56270e7a70fa81a5935b72eacbe29' (length=32)
string '0cc175b9c0f1b6a831c399e269772661' (length=32)
Better Approach us using strtolower
$result = $this->memcached_library->get(md5(strtolower($sql)));
C, Is MD5 unique
MD5 cannot guarantee total uniqueness, however there are approximately 3.402823669209387e+38 different values in a 32 digit hex value (16^32). That means that, assuming the math behind the algorithm gives a good distribution, your odds are phenomenally small that there will be a duplicate.
D. Better option is using sha1
$betterKey = "user" . sha1(strtolower($sql));
^- identify request for each table
MD5 is unique enough in your case.
But:
I used this technic for a while before dropping it. Why?
md5 is considered to be too fast for password hashing. But it is still a hashing function and when called each time you have to make a DB query, it might slow down your code. I've seen in the past that hashing the SQL query to generate a key was responsible 20% of the PHP execution time, which was huge.
If you need to delete or update a specific key, for example in your case if a user want to change his location and you want this change to be reflected as soon as possible, you'll have to rebuild the same DB query, hash it, to retrieve your key.
The solution I prefer:
Create simple, short, useful keys instead. Typically, use the method name from your model. If the method in your example is User::getUser($name, $location), make your key:
$key = "User::getUser($name, $location)"
You won't need hashing at all, it will be clearer, and easier to manage keys.
You are refering to the Collision vulnerabilities of MD5. For practical, simple use you can forget about those. So MD5( uniqid() ) is unique. See http://php.net/manual/en/function.uniqid.php
For generating hashes in use like SessionID, MD5() is fine.
Related
I have the following function which seems to run forever. Its creating a random string then checking if its in the database. If it is it should run again and again until it has one that is new. It should then return the value to me
public function checkPromo(){
$continue = true;
while ($continue){
$promo = $this->getRandString(6);
$query = sprintf("SELECT * FROM table WHERE field=%s",
$this->db->cleanCode($promo, "text"));
$result = $this->db->query($query);
if($this->db->num_rows($result) >= 1){
$continue = false;
}
}
return $promo;
}
Your specific problem is that your check is backwards. You're looping until you find a duplicate, which will likely take quite a while or forever.
Even if you fixed it, it's a bad algorithm. It will take exponentially longer to generate a new unique code the more codes you have in your database, since the chance of duplicates increases. Especially if your codes are only 6 characters long the chance for duplication increases a lot.
Note that you're also prone to race conditions with your code (think it through from that perspective).
There are two approaches to generating unique ids:
use an incrementing counter, which means you're using a central generator which keeps track of existing ids
use a decentralised approach where you're not keeping track of your ids, but you're using an algorithm that is random enough and has a large enough space that collisions are so unlikely as to be irrelevant in practice
You're combining the worst of both worlds: you're using a central system to keep track of your ids, but you're using random id generation with it. Use one or the other, not both.
If you're going to use a database anyway, just use a standard auto_increment id. If you want it to look a bit random, hash it with MD5 or such.
Alternatively, simple pre-generate all possible codes (just 6 characters isn't a lot), and pick one at random using a method which is not prone to race conditions. Something along the lines of this:
UPDATE codes
SET claimed_user_id = %d
WHERE claimed_user_id IS NULL
ORDER BY RAND()
LIMIT 1
Otherwise, if you want decentralised random ids, use an appropriate algorithm, which is pretty much UUID.
while (true) is a dangerous thing. As you noted, its defaulted to run again and again creating an infinite loop.
You'd be better offer utilizing an auto-incremented value(link assumes MySQL) or generate a pseudo unique id with PHP (such as uniqid()).
You could expand on these values further by prefixing or suffixing a common word, say promo, or padding or hashing them to create a standard length.
Assuming you simply want to generate a promocode that was not recorded in the database and taking into account the context, I advise you change the attitude a little bit:
public function generatePromo(){
$promo = $this->getRandString(6);
$query = sprintf("SELECT * FROM table WHERE field=%s", $this->db->cleanCode($promo, "text"));
$result = $this->db->query($query);
if($this->db->num_rows($result) > 0){ # in case a record with this "text" already exists, run this method again
$this->generatePromo();
} else {
return $this->promo = $promo; # otherwise return the value/store it in the object
}}
If you expect your table to contain only unique values, then I suggest you make it UNIQUE. That will significantly reduce query time.
user id or username which is better to save in session and also in mysql which is the best way.
--> "select * from usertable where loginname=" . $_SESSION['username']; or
--> "select * from usertable where id=" . $_SESSION['id'];
whether integer comparison or string comparison which is the best comparison in SQL.
You should usually save the ID, because if you are running a fully normalised database this is the value that is most useful to you when performing other lookups.
What you are thinking doesnt really make much sense to me, really!
Integer comparison or String comparison -- Why do you think one will be faster that the other? Of course, if you go instruction by instruction Integer comparison will be faster, but why do you want that?
My answer: Stick to what ever you want. Choose the one that will be guaranteed to be unique. Plus, choosing username, isnt something great. Generate a unique ID for every user that is logged on. And store that ID into the $_SESSION[..]. Obviously, you would need to have some mechanism to validate the ID, and associate it with the username.
Integers comparison is always more accurate than strings, also you would like to consider the fact, the id is unique for each user, and there maybe an several user with the same username, that depends on your system.
I believe id comparison is the best way to go
A few years I asked here on stackoverflow about how to make PHP password storage safe.
The main answer suggests using the following hashing algorithm:
function hash_password($password, $nonce) {
global $site_key;
return hash_hmac('sha512', $password . $nonce, $site_key);
}
The answer suggests using a random nonce. Is there any advantage in having a random nonce over simple unique nonces?
For instance, each user can have its own ID which does not change. However, let's assume user IDs are sequential(built with MySQL's auto increment feature) and therefore not random. Would the user ID be a good nonce or is randomness important?
Now, each user can pick an username. Each user has its own username which does not change, and two different users can't have the same username.
Usernames are still not random, but they aren't sequential either. Would usernames be good enough as a nonce? Would it be better than using the user ID?
THIS IS ALL ON THE ASSUMPTION THAT A NONCE IS A SALT...
If by nonce you mean a salt then yes that requires more rainbow tables to be made. Usually once salt over 20 characters suffices, but for extreme security conditions you would want a new random salt for each password.
Also good choice in a slow hash http://www.php.net/manual/en/function.hash.php#89574, no sarcasm. But I like ripemd.
Didnt see the bottom half of your response. To elaborate: Nonces are used to prevent the use of rainbow tables. Whether the ID's would work depends merely on the length of the IDs. Randomness is not technically important, but just makes more rainbow tables required. An example would be, lets say you used a character "a" as a nonce and the password were 2 characters long, a rainbow table of a-aa, a-ab a-ac and so on would have to be created. If you use a random one each time maybe all the permutations of 'a' would have to be done + all the permuatations of the other random characters.
But in general making rainbow tables take quite a long time. So if you come up with a salt thats long its likely the rainbow table for it doesnt exists.
I found that there was a fairly nice tutorial written online about this topic. I don't quite remember where on google I found it but let me see if I can break the function down well enough myself as it is right in front of me...
First the function, it can create a key length of any size. I took the liberty of commenting it fairly heavily...
function pbkdf2($password,$salt,$iter_count = 1500,$key_length = 32,$algorithm = 'sha512')
{
/*
#param string password -- password to be encrypted
#param string salt -- salt to encrypt with
#param int iter_count -- number of times to iterate blocks
#param key_length -- length of key to return
#param $algorithm -- algorithm to use in hashing
#return string key
*/
//determine the length of the hahs
$hash_length = strlen(hash($algorithm,NULL,TRUE));
//determine the number of key blocks to compute
$key_blocks = ceil($key_length/$hash_length);
//initialize key
$key = '';
//create the key itself
//create blocks
for($block_count = 1;$block_count <= $key_blocks;$block_count++)
{
//initalize hash for this block
$iterated_block = $block = hash_hmac($algorithm,$salt.pack('N',$block_count),$password,TRUE);
//iterate blocks
for($iterate = 1;$iterate <= $iter_count;$iterate++)
{
//xor each iterate
$iterated_block ^= ($block = hash_hmac($algorithm,$block,$password,TRUE));
}
//append iterated block
$key .= $iterated_block;
}
//return the key
return substr($key,0,$key_length);
}
First thing it does is figure out the length of the hash.
Next it determines how many key blocks are required for the key length specified
Then it initializes the hash (key) to return
sets up the for loop that will create each block
takes the initial hash of the block with the block counter in binary appended to the salt
begins the loop to iterate the block $iter_count times (create a hash of itself)
XOR each iterate and append it to $iterated_block (xor previous hash to current)
XOR loop finishes
append $iterated_block to $key for each block
block loop finishes
return the key
I feel this is probably the best way to do this. Maybe I am too paranoid?
For storing password enough to use:
sha512(salt + password)
salt should be random and unique for each user. Random salt will make precalculated hash tables attack impossible: each user will require his own calculated hash tables. If you'll use not random salt, then chance that precalculated table exists will be higher.
Position salt before password will help to hide hash patterns in case some users have same password.
Nonce is not needed, because it is for prevention a reply attack. This protection is not possible in your architecture.
Using HMAC to prevent collisions is useless, because a) we use hash not for MAC, b) to make probability of collision 50% for SHA-512 you need to calculate about 2^256 values. And 2^256 is truly astronomical number.
I don't know how to ask this so I'll start with what I have already:
mysql_query("UPDATE `questions` SET `votes` = `votes` + 1
WHERE `questionID`='".md5($_GET['q'])."'");
What I want to do is update the row where the md5 hashed version of questionID = some string. Can I do this using MySQL's md5 function?
Edit:
Would it be something like this then:
"WHERE MD5(`questionID`)='".md5($_GET['q'])."'"
Of course. MySQL's MD5 behavior is identical to PHP's MD5.
'WHERE MD5(field)="'.md5($field).'"'
Your method of passing "q" via $_GET isn't secure though. Makes no sense hashing it when the fact that ?q= is visible to users on the browser's address bar. You may want to preprocess "q" thru a Javascript MD5 function first before form submission:
http://pajhome.org.uk/crypt/md5/
If you really want to use an MD5 hash in this way I would suggest precomputing the hashed value of questionID and storing it in a column of the questions table. Index this column. If you used an indexed column in your WHERE clause MySQL merely looks at the index to find the matching rows.
If the column is not indexed, or you use a function such as MD5(), MySQL has to look at every single row in that database table to return the information you are looking for. You will see a major performance boost with the indexed column, especially on larger datasets.
You may also wish to use a salt so that your MD5 hashes are not easily converted to their original value. See this URL for more information:
http://skfox.com/2007/12/18/md5-hashes-and-salt/
You could, but in that code you're using PHP's md5.
EDIT: If you want to search for a row where the hash of the questionID column equals the hash of $_GET['q'], the second looks right. It's not clear what you're using MD5 for, though. Maybe you should give some background.
EDIT 2: Since q is already hashed, it should be (with escaping):
"WHERE MD5(`questionID`)='" . mysql_real_escape_string($_GET['q']) . "'"
I'm having a dilemma. I have a field hashedX that is a hashed/salted value and the salt is saved in the same row in the mysql database as is common practice.
hashedX saltX
------ ------
hashed1 ssai3
hashed2 woddp
hashed3 92ofu
When I receive inputX, I need to know if it matches any of the values in hashedX such as hashed1 hashed2 or hashed3. So typically I would take my input, hash/salt it, and compare it to the values of hashedX. Pseudo code:
$hashed_input = hash ($input with $salt );
select * from tablename where $hashed_input is hashedX
The problem is I don't know which saltX I need to even get to the $hashed_input before I can do any select.
I could go through the database rows, one by one, try that salt on my input, then check if the input as hashed/salted with this salt matches hashedX of that same row. If I have a 100,000 records, my guess is that this would be painfully slow. I have no idea how slow since I'm not that great at databases.
Is there a better way to do this, than selecting all rows, looping through them, using that row's salt to hash input, then comparing again to the hashed value in the db?
If it is possible (depends on your hash formula) define a MySQL User Defined Function database side for the hash formula (see CREATE FUNCTION). This way you will be able to get your results in one simple request:
SELECT hashedX, saltX FROM tablename WHERE UDFhash(input, saltX) = hashedX ;
You don't specify which hash algorithm you're using in PHP. MySQL supports MD5 and SHA1 hash algorithms as builtin functions:
SELECT ...
FROM tablename
WHERE SHA1(CONCAT(?, saltX)) = hashedX;
SHA2 algorithms are supported in MySQL 5.5, but this is only available in pre-beta release at this time. See http://dev.mysql.com/doc/refman/5.5/en/news-5-5-x.html for releases.
Is there a better way to do this, than selecting all rows, looping
through them, using that row's salt to
hash input, then comparing again to
the hashed value in the db?
Yes. A much better way.
Typically a salt is only used to prevent exactly what you are trying to do. So either you don't want to use a salt, or you don't want to do this kind of lookup.
If you are checking an entered password against a given user account or object, you should reference the object on the same line that you have the salt and hashed salt+password. Require the account name / object to be referenced when the password is given, then look up the row corresponding to that account name and object and compare the password against that salt + hash.
If you are keeping a record of items that you've seen before, then you should just go with a hash, (or a bloom filter) and forget the salt, because it doesn't buy you anything.
If you're doing something new / creative, please describe what it is.