1

as title says I'm writing a paid Desktop App that automates some process, it indirectly requires internet connection because MY app automates another Desktop app that requires internet connection. There is no webpage or such, only my Desktop App and my API.

Normal Workflow:

  1. User opens Desktop App: Login prompt shows on screen (it's a simple interface written in c++ that then posts to my API).
  2. User presses the "Login" button: Data is sent via POST to my API.
  3. API validates and verifies the data, then generates a JWT and sends it to the user.
  4. User then uses the App all the time he/she wants: Every X seconds the JWT is sent to the API to see if it's still valid.
  5. The user stops using the App: It might be because the App crashed, because he lost connection or because he closed it.

What I want to achieve:

  1. I need it to be secure for the users and for me (by me I mean I don't want it to be easily pirated):
    • I'm using HTTPS.
    • I'm hashing the Password before sending it to my API.
    • I'm validating and verifying all the data.
    • I don't know how to make sure that this data comes from my Desktop App and was not modified in the middle by the user (like replacing an unique identifier with a simple string).
  2. I want to prevent multiple clients logging in using the same account at the same time:
    • I don't want multiple Apps connected at the same time using the same account. I don't mind if an user uses the same account on different computers as long as he is not having more than 1 App connected at the same time.
    • When a user logs in with an account it will kill the rest of the "sessions" that this account had. (Like an online game where if you log in with an account that's already logged in, it will kick the user that was logged in preventing from 2 clients using the same account at the same time).

My schema:

Using JWT, when user "A" logs in it will generate a new JWT using his username and some kind of unique information like IP or computer information.

My Desktop App will verify and store this JWT in memory. Then every X seconds it will do a POST request sending the JWT to see if it's still valid.

  • If everything is okay then the App will continue to run normally.
  • If the token is not valid anymore or something is wrong it will log out.

Problems I found:

  1. Let's say User "A" logs in and a JWT is then generated and sent to the Desktop App, how can the Desktop App tell that this JWT is valid and that is not a fake response the user is using so the App thinks it's logged in?.

  2. What happens if user "A" logs in and then fakes responses every X seconds? I mean, how can I make this response unique? Is it a good fix to generate a new JWT everytime it performs this check?

  3. Let's say I make it unique using some kind of unique identifier for each client (like IP, computer information, etc.), what if the user intercepts the information and replaces it with something simple like "hello world" so then all clients can use the same account and have a valid token at the same time. How do I prevent user from being able to intercept the data sent?

So my questions are:

  • How do I fix those problems.
  • Is it a good schema? I mean is it secure (to prevent piracy)? (I know nothing is 100% secure, but I don't want to make an authentication system that can be easily broken or with no security at all).
  • Is JWT a good choice here? Are there alternatives that are "better" or "different"?
  • Do you see any other problems, flaws, bugs, etc.?
  • Do you have another schema or idea to achieve this?

Thanks in advance.

P.S.: I'm not taking into account what happens if the user reverses my Desktop App because that's another topic and in that case nothing here is important.

1 Answers1

2

Problem 0: You don't need to send the hash of the password, because you're already using TLS (HTTPS). If you do send the hash, then the hash becomes the password.

Problem 1: Preventing users from generating a fake JWT response.

You're already using TLS. Pin your server's certificate. That is, include the server's public key in your app. If anything answers with a certificate that doesn't match the public key, then the app isn't connecting directly to your server.

Problem 2: Preventing replays of a valid JWT response.

Use a new nonce each time. (Also, every few seconds? If their connection to the internet needs to be reset, and they don't need to access resources on a server to do work in your app, only to make sure that their session hasn't been revoked, then give them a few minutes.)

Problem 3: Keeping different computers uniquely identified.

You're using TLS, so they can't change the bytes on the network. Simply produce a random nonce when the user logs in, identifying that session. Don't store it on disk, keep it in memory. They would have to crack your app to change that, which you've already said is beyond the scope of this question.

Ghedipunk
  • 5,766
  • 2
  • 23
  • 34
  • Hello, first of all thank you (I upvoted but it won't show because of reputation). Wow, when I read your answer about Problem 0 I realized how stupid I was. About Problem 1: I'm not exactly sure how to do that, I'm using Hostinger and got my cert from Let's Encrypt. About Problem 2: You mean that I should generate a new JWT each time?. About Problem 3: Understood!. – roberto carlos Oct 18 '19 at 00:30
  • For problem 2... You may not need formal JWTs. You just need shared secrets set up for that session. The message would come down to this... Client: "Is my session, 51821, still valid? 24601." Server: "Yes, your session is valid. 24601 hashed with our secret is '#D34DB33F'." -- I suggest some study of TLS and assynchronous key cryptography to get a better grasp on problem 1. – Ghedipunk Oct 18 '19 at 05:01
  • Also, thank you for marking my question as the accepted answer. I'm glad that I'm able to help. It's traditional to wait at least 24 hours before accepting an answer, as it might discourage others from attempting to answer too, which could keep you from seeing other perspectives -- or even keep someone from posting an even better answer. – Ghedipunk Oct 18 '19 at 05:07
  • Also, thank you for marking my question as the accepted answer. I'm glad that I'm able to help. It's traditional to wait at least 24 hours before accepting an answer, as it might discourage others from attempting to answer too, which could keep you from seeing other perspectives -- or even keep someone from posting an even better answer. – Ghedipunk Oct 18 '19 at 05:07
  • Thank you. Should I undo the acceptance of this answer to see if someone has other perspective? – roberto carlos Oct 18 '19 at 12:52
  • In case you want to visit this post as well: https://security.stackexchange.com/questions/219797/is-this-schema-between-a-desktop-app-and-an-api-secure Thanks to your answer I designed that schema and new questions arose. – roberto carlos Oct 18 '19 at 15:08