0

I wish to add an extra layer of security to my product (web app that people download and install on their server) that have a module that allows me, the developer, to access their sites instantly with just one link. The way I thought about this specific layer, which is on top of your basic security, is, everyone who buys my product will get a copy of this public hash. As of now, I compute this hash with password_hash( 'mypassword', PASSWORD_BCRYPT, ['cost'=>20'] ), it creates a strong password, supposedly unbreakable.

When I'm trying to access their website with it, and so, I pass the plain-text in a password field, I simply do password_verify on the input. If the input provided matches (after hashing) the public hash, then it means the passwords match.

A problem with all of this, however. If one of my customers is running on HTTP only or an attacker tricked me into accessing his evil site, he'll see this in plain-text. Now, this password is cycled every 12h or on some triggers and on its own, it's useless, but is this really a good way of solving the issue?

In other words, if I "leak" my hash to the public, is bcrypt, 12 hours with resets happening on triggers such as if a customer's site is on HTTP enough to stagger attackers enough?

This is just an additional layer that adds an extra step for an attacker to work through.

7
  • Public key cryptography.
    – user
    Feb 24, 2020 at 14:47
  • @user Well, yes, sure, but can you give me any hints as to what that is? Names, implementations, etc.? Anything to go on?
    – Daniel M
    Feb 24, 2020 at 14:49
  • Look at RSA or elliptic curves (probably ed25519 or similar).
    – user
    Feb 24, 2020 at 14:51
  • @user Right, but this doesn't help, I mean, clearly, we all know what that's supposed to do, but as to my answer, what does the process look like? I provide each customer with the public key, then, when I access their site, I also provide a signed message with my private key?
    – Daniel M
    Feb 24, 2020 at 14:54
  • I don't use PHP so I have no idea what the code would look like, but what you want to do is best accomplished with public key crypto. The other "secure" option would be to have unique, random passwords for every site so that a malicious one can't compromise them all.
    – user
    Feb 24, 2020 at 14:56

2 Answers 2

2

You can do it with a public key, and a random challenge.

Ship your public key on your product, and keep the private key well protected. When you try to login:

  1. Module generates a long (512 byte or more) random token

  2. Encrypted token is sent to you

  3. You decrypt the token, sign it, and send back

  4. Module checks if the token is the same it sent, and if the signature matches

This way, you don't need to keep a secret on the client (the public key is public anyway), it is secure even over HTTP (attacker cannot forge another token, or the client will reject it), and your private key keeps secured with you.

10
  • This makes sense, but the goal here is that my customer provides me with a link and he knows, by virtue of crypto, that it's me who's accessing it. Wouldn't it be better if I were to sign a message with my private key, then send it in the headers to my customer's site to verify that, indeed, it's been signed with my private signature?Sign a message with my private key, then everyone can tell that it's indeed me.
    – Daniel M
    Feb 24, 2020 at 15:07
  • That is to say, can't my customers ever tell, based on a signature, that it's me instead of doing all this back-and-forth with signing?
    – Daniel M
    Feb 24, 2020 at 15:07
  • It could, but it would be susceptible to a replay attack. Your client must send you something first. And if this is supposed to be a module, it can be automated. You create a module on your side that talks this protocol to the module on the client.
    – ThoriumBR
    Feb 24, 2020 at 15:08
  • This is incredibly complex for a new person but paragonie made it flawless. If I understand correctly: I ship my public key with my product. Every time I want to login to my customer's site, the site generates its own keys and based on my developer public key, generates a challenge string. It then sends this string, together with the customer public key to my developer server, my developer server says "aha, I can actually decrypt this, because I have the private key" and then the server says "yup, you are actually the developer since you decrypted my message". Correct?
    – Daniel M
    Feb 24, 2020 at 17:03
  • It was not how I imagined it, but this will work even better. You are generating a keypair and sending back, I was just sending a token. Do as you said, it's even better, but a little more complex.
    – ThoriumBR
    Feb 24, 2020 at 18:16
0

I've made it work, but I am susceptible to replay attacks if there's a MITM between the customer site and the developer. Here are the steps. I am using the PHP implementation of libsodium provided by paragon.ie: https://paragonie.com/book/pecl-libsodium/read/05-publickey-crypto.md , where me, the developer is Bob and the customer is Alice.

  1. As a developer, you generate your keys: the public/private box keys and the sign keys.
  2. Every single copy of your product will have your public box key.
  3. When a customer wants to give you access, he will create a challenge string together with one-time use public/private keys. This challenge string is stored in the database using bcrypt but its plaintext is encrypted with the developer's public key such that only the developer himself (or whoever holds the key) can ever decrypt it. The plaintext is then discarded.
  4. The customer sends this challenge string to the developer and the developer has 3 days to decrypt it.
  5. The developer is able to decrypt this string and use it for the login process.
  6. When the developer is trying to login, he will provide the original plaintext string that is encrypted with the customer's public keys. The login mechanism first decrypts it with the customer's private keys, then it should get the original plaintext in-memory. It then goes ahead and checks this plain-text against the bcrypt value using password_hash to see if they match.
  7. If they match, the login happens.
  8. If they match and the login happens, if 3 days have passed since the keys/access string were generated, the system auto-deletes the one-time keys, the access string and in doing so, invalidates the link. Even if you had the link before, it is now no longer relevant.

Going back to the problem of replay attacks, I'm not sure how to avoid it. If I sign this challenge with my private developer key, an attacker can just grab the link from a network sniffer and enter it in his browser and bang, he has a "signed message from me" that he can keep re-using.

Not sure how to ensure security over HTTP.

A thought that comes to mind is I could also send a developer signed nonce, when a login process happens with this nonce, it is stored in the database and cannot be re-used. The idea of this signed nonce is that the customer site will be able to tell that, indeed, the message is coming from someone who has the developer keys. Well, then again, if the attacker is intercepting traffic, he could just catch this request and not redirect it to the site and instead to him so he could use it. A race condition if you will.

6
  • What about using an OTP? This would likely mitigate the risk of a replay attack since including an OTP should solve that problem. The key on this however is that the OTP doesn't appear in the challenge and is an additional step to make it more complex. However here is a little thread to maybe get you started on how the mechanism works: crypto.stackexchange.com/questions/50475/…
    – Nico
    Mar 6, 2020 at 7:32
  • @Nico In a way, this is an OTP as well, my problem is that there's no way to stop attacks where a request could be intercepted. If an attacker sees the request over non-HTTPS, he can replicate it because the request never reaches the customer site to invalidate the OTP. I'm afraid that this is not something I can stop.
    – Daniel M
    Mar 6, 2020 at 8:01
  • That is generally true, I don't know of a way to stop that problem. Even splitting the login process into two steps to isolate the OTP part into a second step it would be still a problem. Is there no way to setup a VPN or maybe even force HTTPS on your clients if your that scared of the implications?
    – Nico
    Mar 6, 2020 at 9:05
  • @Nico No. So, for all intents & purposes, this is secure. I will simply disallow the module over HTTP or give a big warning before using it.
    – Daniel M
    Mar 6, 2020 at 9:15
  • @Nico Sorry, it seemed as if I "already knew the answer, don't bother me". What I meant was that the process of ensuring that the so-called access string/password can only be used once and is properly disposed of, etc. is there. I was just wondering if there was a way to secure all this over HTTP.
    – Daniel M
    Mar 6, 2020 at 9:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .