From my previous question: How secure is this schema between a Desktop App (c++) and an API (php).
Introduction
I made a paid Desktop-app that required constant internet connection (because of its nature, not because of security or this schema). Because this is an specific situation I decided to design my own schema.
My lack of knowledge (I'm an student and I've been programming Desktop Apps for like 3 years, all of those free without any kind of internet connection) led me to make bad / insecure schemas that affected user experience or had some serious flaws. After doing A LOT of research I designed a lot more and found flaws on all of them until I came with this one.
But why open a question on StackExchange? On this schema I use JWT to solve most of my problems (data signing, dynamic answers, etc.) but because of my knowledge I'm not able to tell if it is secure or not and if it's a good implementation.
About the Schema
Normal Workflow:
Client logs in using the Desktop App (and receives a JWT) and every X seconds/minutes the Desktop App sends this JWT to see if it's still valid. My questions are probably simple but couldn't be answered using google.
No browser is involved, everything is done between the Desktop App sending POST requests and the API answering.
I have 2 .php files:
- check.php: it's the one that receives the Requests every X seconds/minutes.
- login.php: used once to log in everytime the user opens the Desktop App.
Login.php
Receive username, password and a random value. Check if username and password are okay, then generate and store in DB a JWT using random value + SharedSecret_1 . Send the JWT back to the Desktop App so it can check if it's valid and proceed to let the user use the software.
Check.php
Receive a JWT and a random value. Check if the JWT is the same than the one in the DB then generate and store in DB a new JWT using random value + SharedSecret_2. Send the JWT back to the Desktop App so it can check if it's valid.
I had 4 main problems:
- How to make sure the Desktop App knows if the JWT it receives is valid and not faked by the user.
- How to make sure the API knows if the data sent by the Desktop App is valid and not faked.
- The API needs to send a unique JWT everytime because if it's always "Y" then user would be able to forward the data send by the Desktop App and fake an answer "Y".
- I don't want multiple users using the same account at the same time. Only 1 connection per account. (Like in an online game were if someone logs in while you are logged in, you get kicked).
From the answer I came with this idea:
- Solution for 1st problem: Both Desktop App and API share a Secret Key that the API will use to generate the JWT and the Desktop App will use to verify this JWT.
- Solution for 2nd problem: Desktop App signs data before sending it.
- Solution for 3rd problem: A random value is sent by the Desktop App (along the JWT) everytime it performs the checks so the API uses it to generate a different JWT.
- Solution to 4th problem: Using different SharedSecrets for "login" and "check", If a user forwards the checks to the login, it will generate a token with SharedSecret_1 and when the Desktop App verifies this token it will use SharedSecret_2 (because that's what's used for check.php) making it invalid.
My questions are:
From Solution to 2nd problem (client-side data signing):
- When the Desktop App sends the data, is it secure to "sign" it generating a JWT on the client-side and verifying it on the API using a Shared Secret? Or should I use RSA with public/private key pair?.
From Solution to 3rd problem (random value on JWT):
- Can this random value be known by anyone without risking security? (Because the user would still need the shared secret to be able to generate a valid JWT)
- Should the random value be sent inside the JWT?
- How "random" should this value be? Is it okay if it's a simple number from 1 to 100000?
General:
- Is this approach secure enough to be implemented? I know how secure are JWT but maybe MY implementation makes it non-secure.
When I'm asking about security I mean against piracy, preventing users from accessing my paid app for free. (I know it can't be 100% secure, but I want it to be as secure as possible without affecting user experience).
I'm not taking into account what happens if a user reverses my Desktop App or gets access to my cloud hosting account because if this happens then the user will simply remove the checks or will know the shared secret.
Thanks in advance.