Can I use mysql's md5 function in an update? - php

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']) . "'"

Related

Obfuscating database ID to customer facing number

I'm using mysql database auto-increment as an order ID. When I display the order ID to the user, I want to somehow mask/obfuscate it.
Why?
So at first glance, it is obvious to admin users what the number
refers to (orders start with 10, customers start with 20 etc)
To hide, at first glance, that this is only my 4th order.
Based on this this answer, I want the masked/obfuscated order id to:
Be only numbers
Consistent length (if possible)
Not cause collisions
Be reversible so I can decode it and get the original ID
How would I acheive this in PHP? It doesn't have to be very complex, just so at first glance it's not obvious.
I think you can use XOR operator to hide "at first glance" for example (MySQL example):
(id*121) ^ 2342323
Where 2342323 and 121 are "magic" numbers - templates for the order number.
To reverse:
(OrderNum ^ 2342323)/121
Additional advantage in this case - you can validate OrderNumber (to avoid spam or something like this in online form) if (OrderNum ^ 2342323) is divided by 121 with no remainder.
SQLFiddle demo
A little bit late, but Optimus (https://github.com/jenssegers/optimus) does exactly what is here asked for.
$encoded = $optimus->encode(20); // 1535832388
$original = $optimus->decode(1535832388); // 20
Only the initial setup is a bit weird (generate primenumbers)
Probably the simplest way is to just generate a long random string and use it instead of the auto-increment ID. Or maybe use it alongside the auto-increment ID. If the string is long enough and random enough, it will be unique for every record (think of GUIDs). Then you can display these to the user and not worry about anything.
Can it help?
echo hexdec(uniqid());
Off course you should store this value at db, at the same row with order id.
Just converting a ID into something like HEX might not give you the result what you like. Moreover its still easy 'guessable'
I would a a extra ID column (i.e. order_id). Set a unqi. index. Then on_creation use one of the following mysql functions:
SHA1(contcat('ORDER', id))
MD5(contcat('ORDER', id))
SHA1(contcat('ORDER', id, customer_id))
MD5(contcat('ORDER', id, customer_id))
UUID()
// try this in your mysql console
SELECT UUID(), SHA(CONCAT('ORDER',10)), SHA1(1);
You could (as in the example), add a simple text prefix like 'order'. Or even combine them. However i think UUID() would be easiest.
Implementation depends a bit on what you prefer you could use a stored procedure) or incorporate it in your model.

php memcache key management

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.

PHP search feature, where comparing an encrypted value

I am making a search feature where the search value should be compared with two columns in a db table. One column is just a name and the other column is en encrypted value in format "xxxxxx-xxxx" (only numbers). The user should be able to just search for part of the total string in the table.
For the name comparison I use where name LIKE %search_value%, but for the encrypted value I can't use that way of doing it.
Any ideas to how a good way of doing the comparison would be?
You couldn't use a wildcard search for crypted values, because the crypting of 'a' is ENTIRELY and UTTERLY different than the crypting of 'bac'. There's no practical method of doing sub-string matching within a crypted field. However, a simple direct equality test is doable. If you're a DB-side function like mysql's aes_encrypt(), then you could do
... WHERE
(name LIKE '%search%') OR
(cryptedfield = AES_ENCRYPT('search', 'key'))
For substring matching, you'd have to decrypt the field first:
... WHERE
(name LIKE '%search%') OR
(AES_DECRYPT(cryptedfield, 'key') LIKE '%search%')
basically, if it needs to be encrypted, no part of the system should be able to search it. if it should be searchable, then it probably doesn't need to be encrypted.
otherwise you are kind of defeating the purpose of encryption.
If you're looking for full-text search capability of encrypted data (without the database server being able to decrypt the messages), you're in academic research territory.
However, if you only need a limited subset of searching capabilities on encrypted data, you can use blind indexes constructed from the plaintext which can be used in SELECT queries.
So instead of:
SELECT *
FROM humans
WHERE name LIKE '%search_value%';
You could do this:
SELECT h.*
FROM humans h
JOIN humans_blind_indexes hb ON hb.human_id = h.id
WHERE hb.first_initial_last_name = $1 OR hb.first_name = $2 OR hb.last_name = $3
And then pass it three truncated hash function outputs, and you'll get your database records with matching ciphertexts.
This isn't just a theoretical remark, you can actually do this today with this open source library.

Which is the best way ?? to save the username in session or id of the user in session?

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

Dilemma, searching a hashed field when no other information is known

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.

Categories