I'm developing a REST API but I am unable to use HTTPS without using self-signed certificates. I understand that that might be acceptable for some, but I don't want security messages popping up on client browsers.

The information being passed on the network is not sensitive, so I don't care about eavesdropping, but I want to make sure that only authorized clients are able to make requests and prevent replay attacks. Here's my idea:

A user is registered with the web application running the service. They want to register an API client, but they are not a developer, so they download a supplied client application (in this instance, an IC Card reader they will use with a computer that can communicate data read from the scanned cards to the web service over the API).

Step One: The API client application generates a key pair (e.g. OpenSSL) and sends the public key to the server (this can be a manual upload step when the user registers the client with the server). The server stores the public key in the database associated with the user and a description of the client (e.g. “IC Card Reader on PC01”).

Why do I want to use a key pair (like SSH)? I feel that a shared secret is vulnerable to eavesdropping as it has to be transferred over the network at least once. While this could be prevented by manually entering the key on the server's terminal rather than transporting it over the network, one design goal of the system is to allow users other than myself to register clients and get an API access token using the web interface for the application. Under this circumstance, an eavesdropper could intercept a shared secret key, while a keypair generated by the client would prevent that.

Step Two: When making a request the client first gets a nonce from the server (which stores it in a list or database of nonces and issued timestamps) and then makes the request including the nonce while signing the request with their private key. The server verifies that the message is authentic (was signed by the client and no one else) before executing the request.

My goal with this approach is to ensure that only valid clients are accessing the API, while also preventing replay attacks. An attacker should be able to see the contents of the messages (not really sensitive), but should be unable to modify them. The client doesn't really care whether the data coming from the server is authentic (because in this case the client is changing the state of the server, not the other way around).

  • Does this approach meet these design goals?
  • And does it prevent against man-in-the-middle attacks (assuming the original registration of the client was with the real server and not an attacker's fake one)?
  • 1
    Why can't you use HTTPS? – Neil McGuigan Jul 11 '15 at 20:26
  • The webserver in question is behind a firewall that denies inward access (so is only accessible on the LAN). The network/firewall administrators refuse to provide a signed certificate for my server, and a Let's Encrypt certificate would require access through the firewall (which I don't have). That limits me to self-signing, which causes certificate errors on client browsers - something I'd rather avoid - or paying for a certificate, which is overkill for this point in the project. I'm sure in the future I'll be able to use HTTPS but for now, I'd like to know if I can secure my API without it. – Aaron D Jul 12 '15 at 0:42
  • They allow port 80 but not 443? – Neil McGuigan Jul 12 '15 at 2:13
  • Both ports should be accessible, but only to those on the LAN. All inbound traffic from the Internet is blocked - it's an intranet-only server. – Aaron D Jul 12 '15 at 3:29

Please note that HTTPS (without client authentication) actually won't help you to achieve your goal of:


HTTPS (without client authentication) will prevent your clients talking to someone impersonating your server; it will not prevent someone impersonating clients from talking to a real server.

So even if you manage to obtain a proper TLS certificate you will still have to put some security measures to achieve stated goals.

Does this approach meet these design goals?

I would say it does, provided that:

  • server properly enforces nonce uniqueness and prevents nonce reuse;
  • client includes that nonce in response and signs complete response, including URI, headers, payload.

You can use asymmetric signatures (as you propose) or symmetric ones (e.g. HMAC). Both approaches should work provided you can guarantee that initial exchange (public key or shared secret upload) happens over secure channel. Amazon prefers HMAC and this library supports RSA, DSA, and HMAC ones.


It depends. Attacker is still able to impersonate server and feed malicious data to the client (because client doesn't authenticate server in any way – this is the part where HTTP could help).

At the same time, if you can ensure that initial exchange of authentication data (public key in case of RSA or shared secret in case of HMAC) was done over secure channel, then server should be able to detect and reject any tampered responses (i.e. ones with invalid nonce or signature) and this provides client authentication that's resistant to MITM.

This part should be evaluated very carefully with regards to protocol flows (who initiates the request, what are data flows, etc) because client has no means of authenticating the server.



Use an ever-increasing nonce value.


Have an API key and secret.

Your requests contain the key in plaintext.

They also include a 'hash' value. This hash value is a hash (eg, sha256) of the concatenation of the API secret, your ever-increasing nonce value, and the data of the request itself. The server generates its own hash, and compares it to the one your client sent.

An attacker can read your API request, but since he doesn't have your API secret, he won't be able to craft a new 'hash' value and send his own arbitrary data. He also won't be able to replay old API calls because of your nonce value.

  • The problem is that the API key's secret has to be transported over the network at least once (either from the client to the server, or the server to the client). Since it's plain HTTP, an attacker could intercept it at that point and impersonate the client. Would sending only a public key from the client to the server avoid this? Can I use a public key to verify that client messages are authentic? Obviously a MITM attack owns the key exchange (fake server impersonation), but I think that weakness is unavoidable without HTTPS. – Aaron D Jul 11 '15 at 17:20
  • 2
    So instead of transporting it over the network, why wouldn't you be able to transport it some other way - eg, writing it on a piece of paper and manually typing it in to a config file?If your network is completely untrusted, and it's completely impossible to have any type of trusted PKI, with no pre-shared secret, what you described would be impossible. – ieatpizza Jul 12 '15 at 8:20
  • Think about it - what's stopping a potential attacker from intercepting your public key, and just replacing it with their own? – ieatpizza Jul 12 '15 at 8:21
  • 1
    I can't eavesdrop on you if you're literally physically transporting the secret on a piece of paper, USB thumbdrive. Also, if the attacker has enough access to your client to get this secret, he probably has enough access to get a private key off of the same client. – ieatpizza Jul 12 '15 at 17:46
  • 1
    In regards to MITM - look at what the NSA wanted to try to do with Lavabit. – ieatpizza Jul 12 '15 at 17:48

No it does not prevent a MITM attack. You can't have authentication of the client without authentication of the server. The reason why is the client has on assurance it is even talking to your server and your server has no assurance it is actually talking to the client.

Without authenticating the server this:

Client <--------> Server

is identical to this:

Client <-----> MITM <--------> Server

The MITM can modify anything sent from the server to the client or from the client to the server. The client sees only what the MITM wants it to see and the only requests that make it to the server are the ones allowed by the MITM.

So in your example client requests a nonce, server sends nonce (MITM makes a copy). Client creates a request, MITM intercepts it and modifies it to whatever he wants and relays it to the server. Server believes the request is authentic.

Now self signed cert "could" be used if you have some method to provide the id (fingerprint, or public key) to the client using out of band communication. This way the client can securely establish an encrypted and authenticated communication channel with server by ensuring that the server hello (part of SSL handshake) matches the pre-shared "Id" of the expected server cert.

This may work in your scenario but in most scenarios it leads to a chicken and egg situation. The communication is secure IF I can securely get the valid Id of server cert to the client but to do that I need some sort of secure communication. The point of CA is to bootstrap that process.

  • Thanks, I rather suspected that ultimately the answer to "does it protect against MITM" was "No". – Aaron D Jul 12 '15 at 20:46

No idea why the OP canot allow port access to 443 but to 80. In that case, you can just set an inbound rule for any port which is HTTPS compatible (any TCP/IP is ..). Just set about the configured port and set-up a HTTPS.

Also, for API's, there is a whole set of API security at OWASP which you can look at. Here's a cheatsheet which you enable you to defend:


You can also chose to implement a ready-made good security measure by implementing this:


All guides are maintained by the OWASP community. Not sure if your TLS certificates are having problem with your set-up, in-case if it is, contact your vendor for this support.

Your Answer

