Should the secret key for Google Authenticator be kept secret? - python

I'm using pyotp https://github.com/pyotp/pyotp to integrate my application with Google Authenticator.
The documentation suggest using qrious https://github.com/neocotic/qrious this is fine and works well. Essentially qrious is able to generate a QR code purely in the browser. In this case, the provisioning URI is passed to the QR code generator and a QR code is made from that.
The thing that puzzles me is that the provisioning URI contains the secret key, and yet we send this URI to the client end to be turned into a QR code by qrious. So the secret key isn't secret because it has been sent to the client.
I would have expected that the secret key must never be sent out of the back end - what am I failing to understand?
# generate a base32 secret key
>>> pyotp.random_base32()
'55OZSEMXLL7VAUZP'
# make a provisioning_URI
>>> provisioning_URI = pyotp.totp.TOTP('55OZSEMXLL7VAUZP').provisioning_uri('someperson#example.org',issuer_name="FooCorporation")
>>> provisioning_URI
'otpauth://totp/FooCorporation:someperson%40example.org?secret=55OZSEMXLL7VAUZP&issuer=FooCorporation'
>>>
The provisioning_URI gets sent to the browser to be turned into a QR code - but it includes the secret key - surely that's not secure?

Yes, you should keep it secret from others and share the QR code with the intended users only so they will scan it using their phone app. And you are right. Sending it to the client-side is risky but even if you are going to generate the QR code on the server and show it to the user, still chances are that it may get compromised anytime. The user's phone may get stolen too. So there are a lot of risks. But it is the best idea to generate the QR code on the server and present it to the user so they will scan it. Just don't use any remote solution or any browser extension to generate the code to make your life easier.
In short, you should never consider this form of verification alone and this verification should be always implemented only after the user enters and verify their password.
When it comes to storing the secret key on your server, you should always encrypt it using a technique like this one and then decrypt it on the fly when you need the secret for verification. And obviously, the secret should be generated for each user separately, otherwise, this doesn't make sense. If you will use the same secret, then secrets can be generated for any user by just swapping their emails.
I will once again repeat here that 2FA should never be considered as a standalone security measure. It should be implemented always as the second layer of the authentication.

Related

Serialisation and timed web tokens in python flask

Hi I am struggling to understand the following example.
I want to add functionality for a user to reset password for my website.
As a lot of sites do I want to send a token to the users email that will let them reset their password.
I am following a guide that suggests using a python module called itsdangerous.
I have been given the following code as a simple example from the tutorial to understand how the module works before deploying to my website:
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
s = Serializer('secret_key',30)
token = s.dumps({'usr_id': 1}).decode('utf-8')
s.loads(token)
Now if I run this here is what happens:
I use s to create a token that allows me to take a dictionary {'usr_id':1} then if I run s.loads(token) within 30 seconds I can get this dictionary {'usr_id':1} back otherwise I get an error.
Can anyone explain (in a simple way for a beginner) what is going on here?
I don't really understand what is happening and I don't see what the secret_key argument to the Serializer is doing?
Also if someone could explain how this kind of code can help me with allowing users to get an email to reset their password that would be great. Thanks!
So this kind of serialization provided by itsdangerous library is JSON Web Token based. In order to create a JSON Web Token you need a secret key, which is a signature to certify that the information tokenized was provided by you and can only be edited with this signature.
A JSON Web Token can be read by anyone but can only be edited by someone who knows the secret key - so you shouldn't tokenize sensitive information like a password, but a user id is ok, which alongside a expiry time set is just enough to check its identity. You must hide your secret key and keep it safe.
A good usage in your case would be to send a expiring token - let's say one day - to the user email, to proof it has authorization to change the password. And after one day it'll be invalid, so you won't compromise your system.
What is the JSON Web Token structure?
In its compact form, JSON Web Tokens consist of three parts separated by dots (.), which are:
Header: The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA.
Payload: The information and the expiry time is held here.
Signature: The signature is used to verify the message wasn't changed along the way, and, in the case of tokens signed with a secret key, it can also verify that the sender of the JWT is who it says it is.
Therefore, a JWT typically looks like the following. xxxxx.yyyyy.zzzzz
You can play around seeing what is inside a JWT by pasting it on the link below:
https://jwt.io/
More info on:
https://jwt.io/introduction/

check user security for modifying objects

I am thinking about security implementation for my python web app.
For example I have user and profiles.
Each user can edit his profile by sending POST at /profile/user_id
On every request i can get session user_id and compare it with profile.user_id if they not same - raise SecurityException().
But I also can do it another more common way:
generate for each profile
secret = hash(profile_data+secret_key)
and render for auth. users links like this:
/profile/4?key=secret
So idea is to generate secret key based on editable object data and check this key on server side. If user don't know secret key it can't get links to edit other profile, and so can't modify them.
How this method of protection called?
Has it any problems in comparsion with session based user_id check?
/profile/4?key=secret
Practical issues:
it's generally a bad idea to put a secret in a URL. URLs leak easily through logs, history, referrers etc. Also it breaks navigation. It's better to put the secret in a cookie or POST data.
you would typically include a time limit in the signed data, so tokens aren't valid forever
you would typically include some kind of flag/counter/state on the user information and in the signed data, so that a user can update something (eg change password) to invalidate previously-issued tokens
you also have to ensure that the lifecycle of signed data can't be longer than that of the token, eg that you can't delete user 4 and create a new user 4 for whom the token is still valid
the hash you would use would be an HMAC using a server-side secret for the key
Signed authentication tokens are typically used as an alternative to database-backed session storage, for performance or operational reasons. It's certainly possible to do sessions securely with signed tokens, but if you're already using stored sessions for other purposes anyway you don't have a lot to gain.

How to encrypt and decrypt passwords for selenium testing?

The context is testing of a web app with selenium while using a number of virtual user accounts we created for this very purpose. And so the testing process needs to access our sites and log-on with the virtual user's id and password.
None of these accounts are critical and they are flagged as testing accounts so no damage can be done. Still, it would probably be a good idea to encrypt the passwords and decrypt them prior to use.
If it matter, our test app is written in Python, Django and uses PostgreSQL for the database. It runs on a small Linode instance.
What might best practices be for something like this?
EDIT 1
The other thought I had was to store the credentials on a second machine and access them through and API while only allowing that access to happen from a known server's non-public IP. In other words, get two instances at Linode and create a private machine-to-machine connection within the data center.
In this scenario, access to the first machine would allow someone to potentially make requests to the second machine if they are able to de-obfuscate the API code. If someone really wants the data they can certainly get it.
We could add two factor authentication as a way to gate the tests. In other words, even if you had our unencrypted test_users table you couldn't do anything with them because of the 2FA mechanism in place just for these users.
Being that this is for testing purposes only I am starting to think the best solution might very well be to populate the test_users table with valid passwords only while running a test. We could keep the data safe elsewhere and have a script that uploads the data to the test server when we want to run a test suite. Someone with access to this table could not do thing with it because all the passwords would be invalid. In fact, we could probably use this fact to detect such a breach.
I just hate the idea of storing unencrypted passwords even if it is for test users that can't really do any damage to the actual app (their transactions being virtual).
EDIT 2
An improvement to that would be to go ahead and encrypt the data and keep it in the test server. However, every time the tests are run the system would reach out to us for the crypto key. And, perhaps, after the test is run the data is re-encrypted with a new key. A little convoluted but it would allow for encrypted passwords (and even user id's, just to make it harder) on the test server. The all-important key would be nowhere near the server and it would self-destruct after each use.
What is generally done in a case like this is to put the password through a cryptographic hash function, and store the hashed password.
To verify a login, hash the provided password and compare the calculated hash to the stored version.
The idea behind this is that it is considered impossible to reverse a good cryptographic hash function. So it doesn't matter if an attacker could read the hashed passwords.
Example in Python3:
In [1]: import hashlib
In [2]: hashlib.sha256('This is a test'.encode('utf8')).hexdigest()
Out[2]: 'c7be1ed902fb8dd4d48997c6452f5d7e509fbcdbe2808b16bcf4edce4c07d14e'
In [3]: hashlib.sha256('This is a tist'.encode('utf8')).hexdigest()
Out[3]: 'f80b4162fc28f1f67d1a566da60c6c5c165838a209e89f590986333d62162cba'
In [4]: hashlib.sha256('This is a tst.'.encode('utf8')).hexdigest()
Out[4]: '1133d07c24ef5f46196ff70026b68c4fa703d25a9f12405ff5384044db4e2adf'
(for Python2, just leave out the encode.)
As you can see, even one-letter changes lead to a big change in the hash value.

Verify file authenticity from Flash client without revealing key

I'm building a Flash application to run on the web, where users can visit and create their own content in conjunction with my service (built with Python). Specifically: the user sends in some data; some transformation is performed on the server; then the finished content is sent back to the user, where it is rendered by the client app.
I want to be able to prevent the client from rendering bogus content, which I can do by passing a keyed hash along with the main content, generated by the server. The client would then use the same key to hash the content once again, and confirm that the hashes/signatures match. If there's a mismatch, it can be assumed that the content is inauthentic.
The problem I have is that keeping the key inside the SWF is insecure. I've considered a number of ways to obfuscate the key, but am learning that if an attacker wants it, they can get it quite easily. Once an attacker has that, they can start creating their own content to be unknowingly accepted by the client.
Is there another way that I can verify a file's signature on the client side, without exposing the method used to create that signature?
Is there another way that I can verify a file's signature on the client side, without exposing the method used to create that signature?
Public key crypto. You have only a public key at the client end, and require the private key on the server side to generate a signature for it to verify.
What is the attack you're trying to prevent? If you are concerned about a man-in-the-middle attack between an innocent user and your server, the sensible choice would be TLS (HTTPS). This is a pre-cooked, known-good implementation including public key cryptography. It's far preferable to rolling your own crypto, which is very easy to get wrong.

Security measures for controlling access to web-services/API

I have a webapp with some functionality that I'd like to be made accessible via an API or webservice. My problem is that I want to control where my API can be accessed from, that is, I only want the apps that I create or approve to have access to my API. The API would be a web-based REST service. My users do not login, so there is no authentication of the user. The most likely use case, and the one to work with now, is that the app will be an iOS app. The API will be coded with django/python.
Given that it is not possible to view the source-code of an iOS app (I think, correct me if I'm wrong), my initial thinking is that I could just have some secret key that is passed in as a parameter to the API. However, anyone listening in on the connection would be able to see this key and just use it from anywhere else in the world.
My next though is that I could add a prior step. Before the app gets to use API it must pass a challenge. On first request, my API will create a random phrase and encrypt it with some secret key (RSA?). The original, unencrypted phrase will be sent to the app, which must also encrypt the phrase with the same secret key and send back the encrypted text with their request. If the encryptions match up, the app gets access but if not they don't.
My question is: Does this sound like a good methodology and, if so, are there any existing libraries out there that can do these types of things? I'll be working in python server-side and objective-c client side for now.
The easiest solution would be IP whitelisting if you expect the API consumer to be requesting from the same IP all the time.
If you want to support the ability to 'authenticate' from anywhere, then you're on the right track; it would be a lot easier to share an encryption method and then requesting users send a request with an encrypted api consumer handle / password / request date. Your server decodes the encrypted value, checks the handle / password against a whitelist you control, and then verifies that the request date is within some timeframe that is valid; aka, if the request date wasnt within 1 minute ago, deny the request (that way, someone intercepts the encrypted value, it's only valid for 1 minute). The encrypted value keeps changing because the request time is changing, so the key for authentication keeps changing.
That's my take anyways.
In addition to Tejs' answer, one known way is to bind the Product ID of the OS (or another unique ID of the client machine) with a specific password that is known to the user, but not stored in the application, and use those to encrypt/decrypt messages. So for example, when you get the unique no. of the machine from the user, you supply him with password, such that they complete each other to create a seed X for RC4 for example and use it for encryption / decryption. this seed X is known to the server as well, and it also use it for encryption / decryption. I won't tell you this is the best way of course, but assuming you trust the end-user (but not necessarily any one who has access to this computer), it seems sufficient to me.
Also, a good python library for cryptography is pycrypto
On first request, my API will create a random phrase and encrypt it with some secret key (RSA?)
Read up on http://en.wikipedia.org/wiki/Digital_signature to see the whole story behind this kind of handshake.
Then read up on
http://en.wikipedia.org/wiki/Lamport_signature
And it's cousin
http://en.wikipedia.org/wiki/Hash_tree
The idea is that a signature can be used once. Compromise of the signature in your iOS code doesn't matter since it's a one-use-only key.
If you use a hash tree, you can get a number of valid signatures by building a hash tree over the iOS binary file itself. The server and the iOS app both have access to the same
file being used to generate the signatures.

Categories

Resources