is this possible?
For a model with EncryptedCharField named "first_name" i notice that the field does not decrypt when I search on it. In all other uses it is fine. This does not work:
if form.is_valid():
cd = form.cleaned_data
search_results = MyTable.objects.filter(first_name__icontains=cd['search_term'])
is this by design or am i doing something wrong?
thanks for you help...
Encrypting the search term first, even if the exact decrypted value, would not work as the cipher is not going to be the same as the one stored in the db. So this would not work:
crypter = Crypter.Read(settings.ENCRYPTED_FIELD_KEYS_DIR)
if form.is_valid():
cd = form.cleaned_data
cipher = crypter.Encrypt(cd['search_term'])
search_results = MyTable.objects.filter(first_name__icontains=cipher)
When something is encrypted (or at least, when it is done properly), it is impossible to gain the value that has been encrypted, without knowing the value. This means that while you can check the value of say a password very quickly, as the user has given you the value of the password, it is very hard to find out the value of the password from the encrypted string. This is part of the P=NP topic.
When you search say via MyTable.objects.filter(first_name=cipher), you are just comparing encrypted strings, which is fine. However, when you try MyTable.objects.filter(first_name_icontains=cipher), you are asking django to unencrypt all of the values, compare them, then return what matches. However, django cannot do that, as no one knows what the value of the decrypted first_name field is. This is by design, as it means that even if the database is compromised, the data is safe (It is also why you should beware any website or organisation that will show you your password, as it means they have not encrypted the value in their database). Overall, not being able to see a users password is a good thing, and even if you do not agree, it is a small price to pay for good security.
You could simply store the HMAC hash of the value in another field, then search for that.
Related
I'm making a food order project in Django, and I want to set unique order numbers for quick verification of the user when they come to pick the food up after the order.
If I create a random combination of numbers and letters, there can be an issue of two orders having the same order number. Is it possible to make the order number unique to each session?
Just use normal incremental order numbers and One Time Passwords(OTP)
User pyotp to generate random OTP for order.
When user orders, create a secret string. Then Generate an OTP for user and send it to them.
When they arrive to pick up, they show the OTP. You can check it using pyotp and the secret string to verify.
Use counter based OTP.
Store the secret key in the order model.
Simple and effective.
Are you storing this on the request.session or is it a model in the database? If it's the model in the database that's a lot simpler. Just set the unique=True kwarg in the field. Though you still have to generate the unique fields.
Look at this guy's _createHash function in his question. Combined with the accepted answer you can create unique order ID's this way. If it's just attached the the request.session object, it'll be more difficult(if not impossible) to be 100% sure that the string has not been repeated, because there's no way to query all the existing Sessions for a custom added attribute. I don't think session is the word you're looking for, though.
I'm new to password_hash and password_verify, and they appear to be the most efficient way of storing passwords securely!
I noticed that password_hash produces different hash for the same plain-text value every time!
This means that if a user tried to create an account with the password (thisIsMyPassword) it will generate a hash like this $2y$10$VCNH8ndve8hwbvLJ2nMHtOsEiigE4zA7ViADxCJfq9bmUCmkNkcce,
And if another or the same user tried to create another account with the same password i.e. (thisIsMyPassword) the account will be created and the hash value of the password will be something like $2y$10$Hqssc5nn3pzgfwqVwQrQz.Ny71q972RXmCmyV9ykywG8iELbsf47a!
Now you see the same value i.e. (thisIsMyPassword) resulted in different hashes!
Is this OK?
Is it OK to let the users use same passwords, as long as the password hash is different in the database?
The password hash includes a so-called salt, a small random value, which is here to prevent dictionary attacks, here is what PHP manual says:
If omitted, a random salt will be generated by password_hash()
for each password hashed. This is the intended mode of operation.
The value you get as the output, is not really a plain hash, but a
string made of - algorithm id, salt and HASH(password,salt).
The used algorithm, cost and salt are returned as part of the hash.
Therefore, all information that's needed to verify the hash is included.
in it. This allows the password_verify() function to verify the hash
without needing separate storage for the salt or algorithm information.
consider (for an example) that we have encrypted a file (sample.txt) using win-zip 9 by typing a password "agoodpassword".
now if we try to open the file by typing some wrong password, we get a error message saying: the password typed is incorrect.
the question:
how can a software verify if the password typed in is correct or not? the content of the file could be any random data, so checking for errors in the file after decryption is not going to work. But still the software needs some source to verify this password; so how does this win-zip software verify if the decryption is successful or not?
What I suspect is the password could also be there in the same file being encrypted. Is it true or does the software adopt any other method?
Instead of just encrypting, many applications that create a ciphertext also create an authentication tag. This authentication tag can be checked before decryption; if the authentication tag is incorrect than one of the parameters (key, IV or ciphertext) is incorrect.
To use encryption using a password it is common to utilize PKCS#5 (password based encryption). PKCS#5 contains a password hashing method that utilizes "key stretching", making it harder for an attacker to test/compare many passwords using brute force or dictionary attacks. Such a password hashing method is called a Password Based Key Derivation Function or PBKDF. The latest PKCS#5 describes PBKDF2.
Now if you want to create a new password based encryption method, I would propose to do the following:
Perform a PBKDF2 with (very) high iteration count and 128 bit salt;
Make sure that the user gets feedback about the strength of the password;
Perform a KBKDF (key based key derivation function) on the result of PBKDF2, creating a check value, a data encryption key, and a data authentication key;
Use the data encryption key for an encryption method, say AES-128-CBC with random IV;
Use the data authentication key for a HMAC over the IV and the ciphertext;
Store the check value;
To verify the correct password during decryption, use the check value.
Note that I did not discuss the KBKDF yet. You may use a hash over the output of the PBKDF2 and a simple counter or string for that, say SHA-256(key seed, "ENC").
You can use a hash value to provide a very high probability that anything other than the correct password will be rejected. Basically, if you hash a password it produces a number with a certain number of binary digits, and a good cryptographic hash will produce a completely different number (in as much as random thing tend to differ) if you type something even the tiniest bit different (for example, changing the order of two characters, or using uppercase instead of lower).
There's still a very small chance that two different passwords will produce the same hash value... for example if you only had a 32-bit hash value then there's about a 1 in 2^32 (4 billion) chance. It gets quite mathematically complex to create a hash function that doesn't let you retrieve the password (especially if it is a short password, and someone can pre-generate a list of short words with specific hash values too), so you probably want to have a pretty weak hash - just good enough to avoid returning corrupt data for 99.99% of typos - and/or one that's known to be resistant to such attacks.
Is there any way Django provides us to Encrypt all / atleast fields like first_name, last_name, email_id of auth.User model just like how it does encrypts PASSWORD field before storing it into Database ?
My Workaround:
I have gone through documentation & few questions on StackOverflow, according to which it would be possible to inherit default BaseUser model & define our own myUser model the way we want, by defining the Custom Character Field which encrypts & decrypts characters.
Problem with this is in my application, I have provided SEARCH option for easy access of fields which are characters. If I encrypt all such Char Fields, it's difficult for me to query for search option.
For example: If ABCD, ABCDE, ABC are strings in database & user wishes to know all such entries which have BC, none of results pop out. Reason is each of ABCD, ABCDE, ABC encrypts to different / unique strings ( I am using AES encryption provided by PyCrypto ). Also BC gets encrypted to some unique string which has no similarity between that of ABCD, ABCDE, ABC ( for obvious reason that I am using AES algorithm with key length as 32 ). And the query I have written like
MyModel.objects.filter(first_name__icontains='BC')
would not return any result. ( Yes I want search to be not case sensitive ).
[Note: I have added all required methods like "to_python" , "get_db_prep_value" in Custom Field, also tried lookup method. But yeah actual problem is each string gets encrypted to unique characters in AES of same length]
Since I am new to Django, my question may not be that like a Django developer. I would like to know answer for either of above two questions. Unless I get answer I am deadlocked. Thanks in advance, but please be kind to me & answer.
I tried a lot, found no useful answers for querying partial matches if fields are encrypted. So I had to do this in Python (Found no other way to do it).
This work around works fine only if database we are working with is small, otherwise it comes with cost of performance.
Query all tuples from database, use python to do partial matches.
result = []
temp_result = MyModel.objects.all()
for temp in temp_result:
if query.lower() in temp.first_name.lower():
result.append(temp)
or something like above. I know this is rude way of Querying, but for the given conditions this was only available solution.
Here is my simple table definition for a mysql credentials table.
case "credentials":
self::create('credentials', 'identifier INT NOT NULL AUTO_INCREMENT, flname VARCHAR(60), email VARCHAR(32), pass VARCHAR(40), PRIMARY KEY(identifier)');
break;
Please ignore all but the inner arguments...the syntax is good...I just want to verify the form. Basically, I have an auto-incrementing int for the PRIMARY KEY and 3 fields - the users's name, email, and password.
I want this to be as simple as possible. Searches will be based upon the id
Question: Will this work for a basic credentials table?
Please please please do not store passwords in plaintext.
Use a well known iterated hashing function, such as bcrypt or PBKDF2. Don't store a raw MD5 hash, or even a raw SHA or SHA-2 hash. You should always salt and iterate your hashes to be secure.
You'll need one extra column to store the salt, and if you want to be flexible you could also have per-user iteration counts and maybe even per-user hash functions. That gives you the flexibility to change to a different hash function in the future without requiring all users to immediately change their passwords.
Apart from that the table looks fine.
I would suggest that you increase the size of the email field (maximum length of an email can be up to 256 chars). Also you should store your passwords as a hash (e.g. bcrypt) not a plain string.