Question

A commonly asked question in python, is how to store user information, like usernames, passwords, and in-game money, so that it can be accessed later. Is this possible? If so, how is it done?

Was it helpful?

Solution

It depends on how important security is for you.

Generally, if the stored information and the program to read it are available on the same machine, it is impossible to securely store data. In thise case secure means mostly to safeguard it from manipulation.

As long as an attacker can study the program to see how it stores information, he can read the information. The best you can do is obfuscate it.

To verify user-entered credentials, you can store not the username and password itself but a hash of the them. A hash function is non-reversible, so it cannot be undone.

In [1]: import hashlib

In [2]: data = {'user': hashlib.sha256('Roland').hexdigest(), 'password' : hashlib.sha256('mysecretpassword').hexdigest(), 'amount': 273}

In [3]: data
Out[3]: {'amount': 273, 'password': '94aefb8be78b2b7c344d11d1ba8a79ef087eceb19150881f69460b8772753263', 'user': 'a1ef7bf9b9098c49c8aa4e6e8b42b199762a55f85ec6ad215a76045088276fcc'}

To use it, you hash the user input and compare that to the stored hashes.

In [45]: hashlib.sha256('Ronald').hexdigest() == data['user']
Out[45]: False

In [46]: hashlib.sha256('Roland').hexdigest() == data['user']
Out[46]: True

A flexible way to store data is to use json. You can easily save and load a dict or a list of dicts that way.

In [4]: import json

In [5]: datastring = json.dumps(data)

In [6]: datastring
Out[6]: '{"amount": 273, "password": "94aefb8be78b2b7c344d11d1ba8a79ef087eceb19150881f69460b8772753263", "user": "a1ef7bf9b9098c49c8aa4e6e8b42b199762a55f85ec6ad215a76045088276fcc"}'

In [7]: json.loads(datastring)
Out[7]: {u'amount': 273, u'password': u'94aefb8be78b2b7c344d11d1ba8a79ef087eceb19150881f69460b8772753263', u'user': u'a1ef7bf9b9098c49c8aa4e6e8b42b199762a55f85ec6ad215a76045088276fcc'}

Note that while the username and password are unreadable, the amount is readable and can be changed on-disk. The problem is that you cannot hash the amount, because you cannot unshash it.

You can e.g. compress the data to obfuscate it.

In [8]: import bz2

In [9]: bz2.compress(datastring)
Out[9]: 'BZh91AY&SY\xbf\x86\x82)\x00\x00T\x99\x80P\x04\x7f\xf0?\x03\xde\x8a \x00\x8a\x88\xa9\xf8\x93\xd4\xf4\xa7\xe4\xc9!\xfa\x88\xd0\n4\xf4\x91\xfa\x81\x00\x01\xa3\x00`:\x9e\xdey?\xa2\x1e\x12\xf3\xbeC\xb9\xb1f\x80\xf6\xaa6\xc5[\xad\\\xac\xf3e\xa8\xb0\xdf:!{\xe5\x10\xae\xae\x07p\xc0\xc3\x14*.\xa0j$\xda\t\xb9K\xa7\\\x81\x11\xa1@\x06\xc4C\x8b\xae\xbc\xc2\xa0\x0e\x1e#H\x91%\xd1\n\x9drS-\x97e_lb\x97C\x0fm\xe6\xb0\xb2\xc2V\x10\x7f\xc9\xf8\xbb\x92)\xc2\x84\x85\xfc4\x11H'

In [10]: len(bz2.compress(datastring))
Out[10]: 157

In [11]: len(datastring)
Out[11]: 171

In [12]: compressed = bz2.compress(datastring)

The compressed data will be unreadable at first glance.

Reading the data is still pretty simple:

In [13]: json.loads(bz2.decompress(compressed))
Out[13]: {u'amount': 273, u'password': u'94aefb8be78b2b7c344d11d1ba8a79ef087eceb19150881f69460b8772753263', u'user': u'a1ef7bf9b9098c49c8aa4e6e8b42b199762a55f85ec6ad215a76045088276fcc'}

However, an attacker could use e.g. the file command on UNIX to determine the nature of the stored data;

In [18]: with open('data.bin', 'w') as storage:
   ....:     storage.write(compressed)
   ....:     

> file data.bin 
data.bin: bzip2 compressed data, block size = 900k

OTHER TIPS

Try pickle and SQLite... both work in this situation :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top