How do I share my mobile app's secret key with the server the first time I generate it? - django

So I am working on a mobile app right now that will be making requests to a REST API built with Django.
In order to secure the API I plan on using a private/public key pair authentication system.
The workflow I have thought out goes something like this:
The user logs in using Facebook
Once the user signs the app generates a private key
The private key is shared between the server and the app so that the server knows to map that private key to a specific user.
Every time the mobile app makes a request the app generates an HMAC/signature using the request parameters and the private key. In addition to the HMAC the app also sends the user_id of the user who sent it (this will act as the public key).
When the server receives the request it generates its own HMAC. Its takes the user_id and looks up the private key in a table. Using the private key it recreates the HMAC with the request parameters and compares it to the HMAC that the mobile app sent. If the server and the mobile have matching HMACs then it performs the request.
Now my problem lies in step 3 where the private key has to somehow be shared between the mobile app and the server. How can I securely send the private key?

I would start by asking why the server part of your app needs to know the private key. If it only wants to authenticate a user, it only needs the public key and the user id, and the user id cannot iself be the public key (you need a way to find out which public key to use).
For instance, the process of sharing the key, your step three, could look something like this:
The app generates a public-private key pair.
The app sends the public key to the server, not caring who can intercept it.
The server stores that public key, associating it with the id the user provided.
Maybe the integration into Facebook is the part that makes this impossible. I do not quite understand how Facebook comes into this whole process.
One thing that can make the transfer of a key slightly more secure is to use multiple channels to transfer it.
For instance, your application could send the private key that was generated using your REST API but encrypting it with a symmetric encryption scheme. The symmetric encryption key can be sent via some other medium, such as email, or through SMS since this is a mobile app, or maybe even an automated phone call placed to a number provided by the registering user. The key can be a random passphrase that generates the actual symmetric encryption key, to make sure it is something that can be typed in by the user. Then, to unlock the app, the user needs to type in this passphrase into a screen and the secret key is unlocked.
Again, this only improves the security of the transfer by a small margin, especially considering the fact that if you can intercept the transmission of the private key, you can probably intercept the email containing the passphrase. In my opinion, not sending the private key to the server would not only be optimal but required.

Related

How to create a transaction using web3 or ethers.js without setting private_key

What i am trying to do:
Building a small app that allows a user to purchase a service for a set amount of tokens. For example, 100 tokens for service A, 500 tokens for service B. This will be for a custom token on the harmony blockchain.
What i know:
I already know how to connect to metamask and get the users address. Signer and provider are available to me.
What confuses me:
Examples and documentation all refer to a private_key and creating a wallet, i don't need to do that, i need to use the users existing wallet.
What i need to do:
Prompt a transaction in the user wallet (harmony one or metamask) for a set amount of tokens.
Check if the user has required balance (seems trivial knowing i can read their balance).
Make the transaction. Also seems ok after reading the docs.
Get a receipt, then call a callback/my code. Again, seems ok after reading the docs.
All pretty straight forward, but again - every document i read always refers to setting a private key - surely i don't need to do this?
A transaction always needs to be signed by a private key generating the sender address. Otherwise it's rejected by the network.
Examples and documentation all refer to a private_key and creating a wallet, i don't need to do that, i need to use the users existing wallet.
every document i read always refers to setting a private key - surely i don't need to do this?
A backend approach is to import the private key to the app and use it to sign the transaction.
However, there's also a frontend approach: Send a request to a wallet browser extension to sign the transaction and broadcast it to the network. The wallet extension then pops up a window and lets the user chose whether they want to sign the transaction (with their private key, not shared with the app) and broadcast it - or not.
You can find an example of such request in the MetaMask docs page.
An advantage of this approach is that your app doesn't need to ask for the user's private key. A disadvantage is that if the user haven't installed a browser wallet compatible with your app, they can't send the transaction (or at least not so easily).
Note: I'm not familiar with the Harmony wallet, but I'm assuming it works in a similar way as MetaMask - because Harmony is an EVM-compatible network, and MetaMask only supports EVM-compatible networks.

Tronweb authentication

I want to build a webapp that uses the wallet address as account, but yet I want to store the user in my db to allow specifying a nickname.
The problem I'm dealing with is that I want to call different apis, where the user needs to be authenticated / authorized in order to gain access .
Since the authentication happens 100% client side in my case (through the tronlink extension and TronWeb), I don't see another way as to add supplementary authentication for my webapp specifically.
If the user logs in to my app with a different password (not using the private key of the wallet), it seems like bad user experience as the user needs to authenticate twice (through Tronweb AND my webapp with a password).
How do you solve this problem?
It seems that the way to handle this is to foresee a separate login flow for the web app after all.
Even when the user already has logged in into Tronlink, it needs to obtain a token to authenticate rest calls.
The way it would appear to work is by generating a random nonce and storing this nonce along with the public key in the User table.
The login flow then consists of signing the nonce in the front-end, and verifying the signature in the backend after which the token will be generated and returned.

Encryption of a Password send over HTTPS

Good day,
I am very new to database/application/connection security and would like some help on a project.
Let me explain my environment :
I have a username A and password A being saved in a database (A) on a local machine.
Password A is being stored using a type of hashing algorithm with salt A.
I am sending the credentails (Username A and Password A) via a HTTPS SOAP Call to a webservice sitting remotely.
Apon receiving Username A and Password A the webservice validates those credentials to a table sitting in database (B) local to the webservice location.
My Problem : If someone gets access to database A and extracts the hashed passwords they can use a SOAP request to connect to the webservice. This means that my security is null and VOID.
I have to possible solutions :
SOLUTION 1 : Before sending password A to the webservice, I decrypt it and send it over plaintext via the Secured HTTPS connection. The webservice will then encrypt it again when validating agains the hash stored in database B.
SOLUTION 2 : Before sending password A to the webservice, I do a second encryption to that existing hash. When arriving at the webservice, it is decrypted to expose the hash which is .then validated against database B.
My Question : Is any of the 2 solutions above, best practice. If not, what would be a best practive solution for this scenario.
Kind Regards
Just a few notes
there is difference between hash (one way, non-reversible) and encryption (reversible). You cannot decrypt hashed value.
I will assume you are working with service credentials, not user's identity credentials
Here I will assume you are talking bout
SOLUTION 2 : Before sending password A to the webservice, I do a second encryption to that existing hash. When arriving at the webservice, it is decrypted to expose the hash which is .then validated against database B.
The hash effectively becomes a password, it doesn't add any security to the solution
SOLUTION 1 : Before sending password A to the webservice, I decrypt it and send it over plaintext via the Secured HTTPS connection.
There are several standards to authenticate the SOAP WS client, using simple credentials it's WS-UsernameToken. Effectively the client sends its username and password plain, relying HTTPS to handle the channel security.
My Problem : If someone gets access to database A and extracts the hashed passwords they can use a SOAP request to connect to the webservice
One the password is hashed, you won't be able to decrypt it, but as well you cannot use the hashed value as a password. Otherwise you will get the "solution 2" and you are using the hash as a password.
Indeed, this is generally a problem. You may search other questions, how to store service credentials locally. The whole problem is - you need to store the credentials. In my experience the best you can do at least make retrieval somewhat harder, e.g. encrypt the service passwords so they are not stored plain in the database or config files. At the end the client application needs the encryption key somewhere to decrypt the credentials. The key needs to be protected as well.
If you are dealing with user credentials (user identities), do not store the user passwords at all at the client side, there are other ways how to authorize user actions (access token, jwt token, ..)
If you are using xml based SOAP you can use WS-Security to encrypt the password and sign your request data so that the integrity and security of your password is ensured, and the send the data over https.
For storing passwords you should use irreversible crypto hash like sha2, at server you will decrypt the password, create sha2 hash and match it against the one from database

How to implement API security for local and remote requests?

I have setup an web-based API to allow a remote app to GET/POST data. Every API call is authenticated with a User ID and Password that is encrypted with a secret key known only to the remote app and the website. This authentication not only ensures that the user can access the API, but also allows me to implement security features based on the user's profile (i.e. User A can see items A & B, but not item C).
I would like my server-side website pages to be able to call the same API methods remotely via AJAX calls, but, something just doesn't seem right about storing encrypted passwords in the code, and, my website implements a "Login As" feature, which will not allow me to set the encrypted password, since the passwords are not stored in plain text.
What is a good way to implement API security for both remote and "local" calls that doesn't require encrypting the user's password?
You should not be storing usernames and passwords in server side code. Sooner or later someone will lay eyes on your code and your data will be vulnerable.
But you should also not be storing secrets (key) in client side code. You should not assume your client can be trusted to keep that secret.
Giving user A access to item A and B, but not C is called authorization and depends on you knowing who calls your API (authentication).
You should probably look into a authentication protocol like OpenID Connect and an authorization protocol like OAuth 2.0.
Also see my answer to this question.

advantages of access keys in webservices

I just read about how access keys and secret ids could be used to send authenticated requests to a RESTful webservice. However, I dont understand the advantages of using it over other alternatives(such as sending over the username and password, for instance), assuming that all communication with the server is over HTTPS.
What are the advantages of using such a mechanism?
Thanks.
Access key is roughly equivalent to a username, and access secret is roughly equivalent to a password. The access key makes it possible for the service to figure out who you are, and the access secret affirms that it's really you ("you" being your site in this context). The access key is not sensitive, and it is usually okay to be published in frontend code (Javascript, links in HTML, etc), while the access secret you need to keep, well, secret, because otherwise other people/sites will be able to impersonate your requests to the service. There is not much difference between key/secret and username/password scheme; the main difference is that key and secret are usually randomly generated by the service, which prevents people from using values like "default/12345" and similar nonsense.