I want to allow users to validate their email address by clicking on a link. The link would look something like
http://www.example.com/verifyemail?id=some-random-string
When I am sending this email, I want to be able to easily generate this 'some-random-string' from row id of user, an integer. and when user clicks on this link, generate that integer back.
Only requirement is this 'some-random-string' should be as opaque and non-guessable to the user as possible.
Finally, this is what I settled on
def p3_encrypt_safe(plain, key):
return base64.urlsafe_b64encode(p3_encrypt(plain, key))
used the nice crypto library from http://www.nightsong.com/phr/crypto/p3.py
addition of base64 safe encoding is mine.
Use encryption, that's exactly what it's designed for. Blowfish, AES, even DES3 if you don't need particularly high security.
Alternatively, you could compute an SHA-256 or SHA-512 (or whatever) hash of the email address and store it in a database along with the email address itself. That way you can just look up the email address using the hash as a key.
Your best choice is to generate a hash (one-way function) of some of the user's data. For example, to generate a hash of user's row id, you could use something like:
>>> import hashlib
>>> hashlib.sha1('3').hexdigest()
'77de68daecd823babbb58edb1c8e14d7106e83bb'
However, basing your pseudorandom string only on a row id is not very secure, as the user could easily reverse the hash (try googling 77de68daecd823babbb58edb1c8e14d7106e83bb) of such a short string.
A simple solution here is to "salt" the hashed string, i.e. add the same secret string to every value that is hashed. For example:
>>> hashlib.sha1('3' + 'email#of.user' + 'somestringconstant').hexdigest()
'b3ca694a9987f39783a324f00cfe8279601decd3'
If you google b3ca694a9987f39783a324f00cfe8279601decd3, probably the only result will be a link to this answer :-), which is not a proof, but a good hint that this hash is quite unique.
Related
I'm using Django and into a my model I'm using UUID v4 as primary key.
I'm using this UUID to generate a Qrcode used for a sort of giftcard.
Now the customer requests to have also a giftcard code using 10 characters to have a possibility to acquire the giftcard using the Qrcode (using the current version based on the UUID) as also the possibility to inter manually the giftcard code (to digit 10 just characters).
Now I need to found a way to generate this gift code. Obviously this code most be unique.
I found this article where the author suggest to use the auto-generaed id (integer id) into the generate code (for example at the end of a random string). I'm not sure for this because I have only 10 characters: for long id basically I will fire some of available characters just to concatenate this unique section.
For example, if my id is 609234 I will have {random-string with length 4} + 609234.
And also, I don't like this solution because I think it's not very sure, It's better to have a completely random code. There is a sort regular-format from malicious user point of view.
Do you know a way to generate an unique random string using, for example from an input unique key (in my case the UUIDv4)?
Otherwise, do you know some algorithm/approach to generate voucher codes?
import string
import secrets
unique_digits = string.digits
password = ''.join(secrets.choice(unique_digits) for i in range(6))
print(password)
The above code pallet generates a unique code of integers for the number of digits you want. In the above case, it will print a 6-digit unique Integer code.
If it doesn't let me know, what exactly you want.
I am trying to write a token based auth in flask for my android app. For that I need a unique token using which I can verify the user.
Itsdangerous library provide a JSONWebSignatureSerializer function using which I can create JWT token. So my first question is, is it safe to use JWT for mobile based auth ?
Secondly, I did a little bit research on how django rest framework generates its token.
def generate_key(self):
return binascii.hexlify(os.urandom(20)).decode()
Is this token unique or just a random one? Which one should I use for a mobile based auth?
What is the based way to generate a unique token for mobile application in python ?
You can use like as mentioned the builtin uuid module. The new secrets module released in 3.6 is also capable of creating unique tokens also.
from uuid import uuid4
rand_token = uuid4()
The function below creates a unique token every time it's called. The os.urandom method returns 20 random bytes as a string and the binascii.hexlify method converts each of those 20 bytes into 2-digit hex representation of that byte. This is why the return value is twice as long.
If you want to use this approach and need tokens to be specific length, use half of the length you need as an argument to the os.urandom method.
def generate_key(self):
return binascii.hexlify(os.urandom(20)).decode()
OK, this is old, but I'm chiming in anyway. You need to decide: Do you want unique or random? Choose one.
If you want unique, use UUID. The whole purpose of UUIDs is to make sure you generate something that's unique. UUID stands for Universally Unique ID.
If you want something that's random, use os.urandom. Truly random results cannot be limited to uniqueness constraints! That'd make them not random. Indeed, it'd make them UUIDs.
Now, for your question, you're asking for an auth token. That means you're using this for security purposes. UUIDs are the wrong solution and generating a secure number is the right one. Could you have a collision when generating a random number instead of a UUID? Yes. But it's unlikely unless you've got a gazillion users. You'll want to do your math on this, but my recommendation is: Don't use UUID when you mean to use random.
Oy.
Look at the uuid() library. Docs are here:
https://docs.python.org/2/library/uuid.html
and a previous discussion of the question is here:
How to create a GUID/UUID in Python
with lots of good details.
I wrote a little helper function for generating a unique token in django models. You can call it from the save() method of your model. It generates a candidate token using a defined function, searches the existing rows in the database for that candidate token. If it finds one, it trys again, otherwise, it returns the candidate string. Note that there is a small race condition in this, but is unlikely to occur with a token function with a sufficiently large range of outputs.
def generate_unique_token(Model,
token_field="token",
token_function=lambda: uuid.uuid4().hex[:8]):
"""
Generates random tokens until a unique one is found
:param Model: a Model class that should be searched
:param token_field: a string with the name of the token field to search in the model_class
:param token_function: a callable that returns a candidate value
:return: the unique candidate token
"""
unique_token_found = False
while not unique_token_found:
token = token_function()
# This weird looking construction is a way to pass a value to a field with a dynamic name
if Model.objects.filter(**{token_field:token}).count() is 0:
unique_token_found = True
return token
Then, you can find a unique token simply by calling
token = generate_unique_token(MyModelInstance, "token_field_name")
It even supports using other methods of generating tokens. For example, if you want to use the full uuid, you can simply call it like this:
token = generate_unique_token(MyModel, "token_field_name", lambda: uuid.uuid4().hex)
A possible solution is to AES encrypt the time when the token expires + the username which makes it fairly easy to spot expired tokens and requires no extra database space for the tokens
We have successfully implemented in our Python+pyramid program Encrypted Website Payments for PayPal, except for a tiny detail: input sanitization. Namely, we would like to help the user by providing as much data as possible to the PayPal from our user database. Now, it occurred to me that a malicious user could change his name to 'Mr Hacker\nprice=0.00' or similar, and thus completely negate the security offered by EWP. I did try URL-encoding the values, but PayPal does not seem to decode the percent escapes in the file.
Our code is based on the django-paypal library; the library completely neglects this issue, outputting happily bare name=value pairs without any checks:
plaintext = 'cert_id=%s\n' % CERT_ID
for name, field in self.fields.iteritems():
value = None
if name in self.initial:
value = self.initial[name]
elif field.initial is not None:
value = field.initial
if value is not None:
# ### Make this less hackish and put it in the widget.
if name == "return_url":
name = "return"
plaintext += u'%s=%s\n' % (name, value)
plaintext = plaintext.encode('utf-8')
So, how does one properly format the input for dynamically encrypted buttons? Or is there a better way to achieve similar functionality in Website Payments Standard to avoid this problem, yet as secure?
Update
What we craft is a string with contents like
item_number=BASIC
p3=1
cmd=_xclick-subscriptions
business=business#business.com
src=1
item_name=Percent%20encoding%20and%20UTF-8:%20%C3%B6
charset=UTF-8
t3=M
a3=10.0
sra=1
cert_id=ABCDEFGHIJKLM
currency_code=EUR
and encrypt it for EWP; the user posts the form to https://www.sandbox.paypal.com/cgi-bin/webscr. When the user clicks on the button, the PayPal page "Log in to complete your checkout" the item name displayed is "Percent%20encoding%20and%20UTF-8:%20%C3%B6". Thus, for EWP input it seems that percent encoding is not decoded.
You could filter out key-value pairs with regular expressions;
>>> import re
>>> text = 'Mr Hacker\nprice=0.00\nsecurity=false'
>>> re.sub('[\n][^\s]+=[^\s]*', '', text)
'Mr Hacker'
Or even more simple, ditch everything after the first newline;
>>> text.splitlines()[0]
'Mr Hacker'
The latter assumes that the first line is correct, which might not be the case.
I have been looking through ths hashlib documentation but haven't found anything talking about using salt when hashing data.
Help would be great.
Samir's answer is correct but somewhat cryptic. Basically, the salt is just a randomly derived bit of data that you prefix or postfix your data with to dramatically increase the complexity of a dictionary attack on your hashed value. So given a salt s and data d you'd just do the following to generate a salted hash of the data:
import hashlib
hashlib.sha512( s + d ).hexdigest()
See this wikipedia article for more details
Just add the salt to your sensitive data:
>>> import hashlib
>>> m = hashlib.sha512()
>>> m.update('salt')
>>> m.update('sensitive data')
>>> m.hexdigest()
'70197a4d3a5cd29b62d4239007b1c5c3c0009d42d190308fd855fc459b107f40a03bd427cb6d87de18911f21ae9fdfc24dadb0163741559719669c7668d7d587'
>>> n = hashlib.sha512()
>>> n.update('%ssensitive data' % 'salt')
>>> n.hexdigest()
'70197a4d3a5cd29b62d4239007b1c5c3c0009d42d190308fd855fc459b107f40a03bd427cb6d87de18911f21ae9fdfc24dadb0163741559719669c7668d7d587'
>>> hashlib.sha512('salt' + 'sensitive data').hexdigest()
'70197a4d3a5cd29b62d4239007b1c5c3c0009d42d190308fd855fc459b107f40a03bd427cb6d87de18911f21ae9fdfc24dadb0163741559719669c7668d7d587'
Salting isn't a magical process that the library needs to help you with—it's just additional data provided to stop rainbow tables from working.
>>> import hashlib
>>> m = hashlib.sha512()
>>> m.update(b"Nobody inspects")
>>> m.update(b" the spammish repetition")
>>> m.digest()
b'\xd0\xf4\xc1LH\xadH7\x90^\xa7R\x0c\xc4\xafp\x0fd3\xce\t\x85\xe6\xbb\x87\xb6\xb4a|\xb9D\xab\xf8\x14\xbdS\x96M\xdb\xf5[A\xe5\x81+:\xfe\x90\x89\x0c\nM\xb7\\\xb0Cg\xe19\xfdb\xea\xb2\xe1'
>>> m.update(b"My super-secret salt.")
>>> m.digest()
b'\xcd\xd7K\xd9!~\xa8\x1d6\x9b\xa6\xde\x06\t\x02\xa1+}\xaeNA\x94a`\xaa\xf4\xe9\xb5\xff\x1f\x9cE\x84m\xbb\x98U\xb4z\x92\x9e\xe8\xc9\xc2\xc8\x8f\x068e\xb0\r\xed\xb7\xde\x80\xa6,\n\x111w{\xa2\x9b'
If you're looking for a replacement for crypt(), newer versions of glibc have SHA-512-based "$6$" with a variable iteration count (see Ulrich Drepper's page, which has a description and links to a complete C implementation of sha512_crypt_r()).
Writing your own crypto is highly unadvisable — the above sha512(salt+password) doesn't help against a brute-force attack.
For generating salt, use something like os.urandom(16) for random bytes or ''.join(map(lambda x:'./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'[ord(x)%64], os.urandom(16))) for random base64-alike chars (for use with crypt()-alikes).
(I say base64-alike it's not the same as the Base64 in PEM/MIME.)
use passlib, writing your own password crypto is an almost sure way to failure.
SHA512 isn't a great way to store hashed passwords these days. You should be using bcrypt or something similar. What's important is that salting is built in and that the algorithm has a significant work factor.
If you salt your SHA512 passwords by simply appending (or prepending) the salt to the plaintext, anyone who gets their hands on a set of your hashed passwords and applies a modern cracking tool (http://arstechnica.com/security/2013/05/how-crackers-make-minced-meat-out-of-your-passwords/) will be able to see the concatenated password+salt values and will probably, through trivial pattern matching, be able to separate the password portion from the salt portion for most if not all of the accounts in question.
I haven't thought this through all the way, and I am by no means a security expert, but it seems to me that if you were to encrypt (using, for example, AES256) the password using the salt as the key, and then hash that with SHA512, you'd be safe from the vulnerability I described above.
However, at that point you've put in more effort than it would have taken to switch to bcrypt and you still wouldn't have the protection of a work factor, so I would only recommend an approach like that if the environment you're working in does not offer that option.
yes yes if my password is "pass" and my salt is "word"
my pass+salt is "password" same as just use password xD
or we use very secure crypth that safe salt to hashed output lol.
we just strip salt and generate hash with random passwords when we got same hash we got password lol lol
How do you store a password entered by the user in memory and erase it securely after it is no longer need?
To elaborate, currently we have the following code:
username = raw_input('User name: ')
password = getpass.getpass()
mail = imaplib.IMAP4(MAIL_HOST)
mail.login(username, password)
After calling the login method, what do we need to do to fill the area of memory that contains password with garbled characters so that someone cannot recover the password by doing a core dump?
There is a similar question, however it is in Java and the solution uses character arrays:
How does one store password hashes securely in memory, when creating accounts?
Can this be done in Python?
Python doesn't have that low of a level of control over memory. Accept it, and move on. The best you can do is to del password after calling mail.login so that no references to the password string object remain. Any solution that purports to be able to do more than that is only giving you a false sense of security.
Python string objects are immutable; there's no direct way to change the contents of a string after it is created. Even if you were able to somehow overwrite the contents of the string referred to by password (which is technically possible with stupid ctypes tricks), there would still be other copies of the password that have been created in various string operations:
by the getpass module when it strips the trailing newline off of the inputted password
by the imaplib module when it quotes the password and then creates the complete IMAP command before passing it off to the socket
You would somehow have to get references to all of those strings and overwrite their memory as well.
There actually -is- a way to securely erase strings in Python; use the memset C function, as per Mark data as sensitive in python
Edited to add, long after the post was made: here's a deeper dive into string interning. There are some circumstances (primarily involving non-constant strings) where interning does not happen, making cleanup of the string value slightly more explicit, based on CPython reference counting GC. (Though still not a "scrubbing" / "sanitizing" cleanup.)
The correct solution is to use a bytearray() ... which is mutable, and you can safely clear keys and sensitive material from RAM.
However, there are some libraries, notably the python "cryptography" library that prevent "bytearray" from being used. This is problematic... to some extent these cryptographic libraries should ensure that only mutable types be used for key material.
There is SecureString which is a pip module that allows you to fully remove a key from memory...(I refactored it a bit and called it SecureBytes). I wrote some unit tests that demonstrate that the key is fully removed.
But there is a big caveat: if someone's password is "type", then the word "type" will get wiped from all of python... including in function definitions and object attributes.
In other words... mutating immutable types is a terrible idea, and unless you're extremely careful, can immediately crash any running program.
The right solution is: never use immutable types for key material, passwords, etc. Anyone building a cryptographic library or routine like "getpass" should be working with a "bytearray" instead of python strings.
If you don't need the mail object to persist once you are done with it, I think your best bet is to perform the mailing work in a subprocess (see the subprocess module.) That way, when the subprocess dies, so goes your password.
This could be done using numpy chararray:
import numpy as np
username = raw_input('User name: ')
mail = imaplib.IMAP4(MAIL_HOST)
x = np.chararray((20,))
x[:] = list("{:<20}".format(raw_input('Password: ')))
mail.login(username, x.tobytes().strip())
x[:] = ''
You would have to determine the maximum size of password, but this should remove the data when it is overwritten.
EDIT: removed the bad advice...
You can also use arrays like the java example if you like, but just overwriting it should be enough.
http://docs.python.org/library/array.html
Store the password in a list, and if you just set the list to null, the memory of the array stored in the list is automatically freed.