Reverse hash lookup query - mysql

i have an web service and one of the parameter our clients needs to use is a custom key. this key is a hash of sha1
eg:
bce700635afccfd8690836f37e4b4e9cf46d9c08
then when the client call our web service i have to check few things:
is client active
is client can submit via webservice and service
now my problem is this:
i have a query:
$sql = "SELECT permission, is_active FROM clients WHERE sha1(concat(id,key)) = '" . mysql_real_escape_string($key) . "'";
Am i doing the right thing? or there's a better way?
thanks

This approach is expensive, since, every time you run this query, MySQL will have to examine every single record in clients and compute the SHA-1 hash of its id and key. (I'm assuming here that clients has more than a few rows, or at least, that you'd like to use an approach that supports the case where clients has more than a few rows.)
Why don't you add a new field called (say) id_key_sha1? You can use a trigger to keep the field populated, and add an index on it. This approach should perform much better.
Edited to add: You mention that the client, in addition to passing in this SHA-1 hash, also has to submit a username and password? I don't know what your table structure looks like, but I'm guessing that it would make more sense to find the client record based on the username first, and then comparing the SHA-1 hash for that specific record, rather than trying to find the record by the SHA-1 hash.

You should not applying function into your LHS column where doing filtering in mysql,
this make not possible for mysql to make use of index for comparison.
An example will allow make use on index :-
where key = SHA1(CONCAT(id, :key))
// where the :key = user submitted api key
// and in this case mysql able to fetch the matched rows via index

Related

Securing MySQL id numbers so they are not sequential

I am working on a little package using PHP and MySQL to handle entries for events. After completing an entry form the user will see all his details on a page called something like website.com/entrycomplete.php?entry_id=15 where the entry_id is a sequential number. Obviously it will be laughably easy for a nosey person to change the entry_id number and look at other people's entries.
Is there a simple way of camouflaging the entry_id? Obviously I'm not looking to secure the Bank of England so something simple and easy will do the job. I thought of using MD5 but that produces quite a long string so perhaps there is something better.
Security through obscurity is no security at all.
Even if the id's are random, that doesn't prevent a user from requesting a few thousand random id's until they find one that matches an entry that exists in your database.
Instead, you need to secure the access privileges of users, and disallow them from viewing data they shouldn't be allowed to view.
Then it won't matter if the id's are sequential.
If the users do have some form of authentication/login, use that to determine if they are allowed to see a particular entry id.
If not, instead of using a url parameter for the id, store it in and read it from a cookie. And be aware that this is still not secure. An additional step you could take (short of requiring user authentication) is to cryptographically sign the cookie.
A better way to implement this is to show only the records that belong to that user. Say the id is the unique identifier for each user. Now store both entry_id and id in your table (say table name is entries).
Now when the user requests for record, add another condition in the mysql query like this
select * from entries where entry_id=5 and id=30;
So if entry_id 5 does not belong to this user, it will not have any result at all.
Coming towards restricting the user to not change his own id, you can implement jwt tokens. You can give a token on login and add it to every call. You can then decrypt the token in the back end and get the user's actual id out of it.

Using MD5() in SELECT Query does not return results

I have this query in my Laravel PHP application, however, I found out that this problem primarily relates to MySQL rather than Laravel or PHP. This is the query:
SELECT id FROM users WHERE MD5('email')='9e1af6d8046e217984ea76bf489a64eb' AND password_md5='f3617237ac21562663a40608a85ea38d';
I'm only given the email's md5 hash as well as the password (also md5-hashed) and need to retrieve the user's id from the MySQL database. email in the database is not hashed, that's why I found that I need to MD5() it during the statement. However, the above query does not return any results when it should have returned one. Yes, I made sure that the hashes are properly input.
What I found when trying to tackle this problem was that SELECT MD5('users.email') does not return the same MD5 hash as the actual email address. I wonder whether I'm misusing the MD5() function or if MySQL adds anything to it so the hash is different from the one also calculated my PHP.
Remove the quotes around email if it is a column identifier. You only need to use quotes for string literals.
SELECT id FROM users WHERE MD5(email)='9e1af6d8046e217984ea76bf489a64eb' AND password_md5='f3617237ac21562663a40608a85ea38d';

Encryption of Database Id

I was working on developing a RESTful service where the Id of a particular table in the database needs to be returned to the client for future access to the particular entry in the database. I was advised against using auto increment and returning the id directly and hence I went for encrypting and sending the Id in the following manner instead -
SET #secretKey1 = "some key";
SET #secretKey2 = CONCAT("some other key", AccountNo);
SET #encryptedAccountNo = TO_BASE64(AES_ENCRYPT(AccountNo, #secretKey1));
SET #encryptedId = TO_BASE64(AES_ENCRYPT(Id, #secretKey));
RETURN CONCAT(#encryptedAccountNo, #encryptedId);
(Note: The Account Number is a sufficiently random field not exposed to the client)
Would using UUID as the primary key be more appropriate? If so, is using the UUID enough or should that be encrypted too?
Or would you use some other design entirely?
Also, do you have any tips for improving the security or performance aspects of the existing design?
I think you may have misunderstood that advice....
When you say "I was advised against using auto increment and returning the id directly".
You should certainly always CHECK the Id is correct to use server side, before using it;
(i.e. check that the document with that Id belongs to the user who is trying to edit it),
but encrypting the ID itself really serves no useful purpose as your API will have to deal with the encrypted one (unless you are encrypt/decrypt client side, which does nothing for security), so the (malicious) client can just send the encrypted version and have the exact same result...
We cannot comment of the security of your code from looking at a (small) piece of your database logic. If you want proper review you will have to post the code that actually does the interaction...

How to generate a SEF alias for a DB String Value

I have a DB table named games which lets just say for simplification contains the columns "id" and "gametitle" and has roughly 7,000 rows already populated.
What I would like to do is have a piece of SQL that would generate a SEF alias for the gametitle that I can use in the URL (I have URL Rewriting successfully running on the site).
The new field would be entered into a new column named "gamealias".
So for instance, if I had a gametitle of "Halo: Combat Evolved" it would drop any special characters and produce something similar to "halo-combat-evolved". All the aliases in the table would have to be unique as they are going to be used in the games url... e.g. http://thegamesdb.net/game/halo-combat-evolved/
Also, it would be nice if upon insertion of a new row, the alias could be generated automatically from SQL without having to handle it in PHP (maybe using the sql fields default value somehow), although I don't mind having to do this in PHP if it's not possible magically in SQL.
I think this could be done in MySQL using a trigger and a regex-replace UDF, but it would probably be a simpler route just using PHP. You could easily guarantee gamealias uniqueness if you integrated the title's primary key in with the string. For example, consider something that would output "halo-combat-evolved-321".

Case Sensitivity and Indices in MYSQL

I am creating a system where is use e-mail address as unique identifier. There are times I need to look for a user by the e-mail address. If the user enters the e-mail address in all lower case, but the database has it stored as mixed case, is it a full scan, or will the database still use the index?
This really is a problem because I attempt to validate that the e-mail address is valid when adding the user to the system.
I am using grails with MYSQL on the back end for the database.
I am currently doing this to find the user
def c = User.createCriteria()
def currentUser = c.get() { ilike('emailAddress',message.sender.address) }
I know I can force the case at the UI, but I would also like to force it at the model level
Thanks, and sorry for the long question
MySQL specifies collation for every character column, which may be case-sensitive or case-insensitive.
Index is built using whatever collation is specified on the column, so:
Alter your table to specify case-insensitive collation on email column (like ascii-general-ci, for example).
Rebuild your index.
Enjoy.
Keep in mind that all queries against email will now be case-insensitive.
Unfortunately MySQL does not support function based indexes like Postgres and Oracle. (Source)
A possible workaround in MySQL is to add another column for lower case e-mail addresses, and a trigger that populates it with lower case e-mails on all updates and inserts. Then simply index that column, and use that for your lookups.
With a function based index, you would have been able to do the following:
CREATE INDEX
ix_users
ON
table_users
USING
lower(email_address);
With Grails you have a few options to validate the model:
You can write a setter for the emailAddress that converts it to a consistent case:
public void setEmailAddress(email){
emailAddress = email
}
A more involved but correct answer would be to create a custom editor (PropertySupportEditor) that will handle the normalization for you automatically.
You will also would want to write a custom validator to ensure that Grails' validation fails if the emailAddress is not correctly normalized. If you wanted to make it really elegant you could make the validator into a reusable constrtaint using the constraints plugin which could result in something like this:
static constraints = {
emailAddress(normalizedEmail:true)
}