5

I have developed a REST API which has been configured to only operate over HTTPS. The sole purpose of this API (at least for the moment) is to operate as the backend entry point for a mobile application.

I have rolled my own token authentication protocol (see this question/answers) which is used for client authentication. The main reason behind this was to be able to generate secure/re-usable tokens which the client could store locally & re-use on subsequent requests. As I have control over these tokens server side I have the ability to expire/invalidate forcing the client to re-authenticate (i.e. generate a new token) and I am also taking precautions to avoid the likes of MitM/Replay attacks. For this to work there has to be some sensitive information passed across the wire in plain-text, however, everything is running over SSL so AFAIK there isn't anything to worry about here(?).

There are a couple of parts to this current setup that do concern me though:

  1. For server authentication, when the app receives the server certificate (self-signed) I am only checking whether the certificate subject (e.g. CN=domainname) is the same as the API address i.e. if the API entry point is api.mydomain.com then it must receive a certificate with a subject CN=api.mydomain.com otherwise the SSL session will fail.

  2. There is no protection from the servers point of view from anonymous requests. Client authentication only happens at the point where the header/post information is inspected. I believe this could leave the door open to Dos attacks. Ideally I would like the server to only accept requests which come from a known source.

My concern with the first issue is it's far too easy to circumvent, the api address is configurable from the app settings & anyone can generate a self-signed certificate so it would be fairly trivial to trick the app into thinking it's talking to the correct server. The second issue is more just a general concern, however, if I could filter out any non-authenticated client requests it would be a bonus!

The only thing that springs to mind to solve (at least the 2nd problem) is to introduce client certificates. My concern with this is implementation time, complexity of deployment and management of the certificates themselves. I guess what I am looking for is some advice on whether (based on the current setup) introducing client certificates to the device would gain me anything here?

James
  • 1,698
  • 3
  • 13
  • 18

1 Answers1

3

Authentication is about make sure that whoever is on the other side of the connection is who you believe him to be. Since this is cryptography and computers and networks, "who you are" equates to "what you can compute" (that's all you can observe from a remote server), which itself comes from "what you know" (everybody can buy a PC, so the ability to compute anything is really the knowledge of the inputs for the computations). For instance, for password-based authentication, a user is authenticated relatively to his knowledge of the password.

Such knowledge is linked to an initial registration where the secret value, whatever it is, gains its special meaning. Still for the password example, this is the procedure by which the user chooses his password, and the server records it (or a hash thereof) in its entrails.

Certificates are useful in contexts where registration and authentication are done by distinct entities: the registration is done by a Certification Authority, who issues (signs) the client certificate, while verification is done by the server itself, who validates the certificate (verifies the signature from the CA) and then verifies a fresh signature computed by the client (that's how client certificates are used in SSL).

If you have only one server, who both decides who may connect, and then authenticates these clients, then client certificates are useless to you: they won't bring any additional functionality or security with regards to a simpler show-the-password protocol (as long as the "password" is a key with enough entropy, and the protocol is played within SSL).

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • Isn't it a valid case though to have a server which is *also* a CA? Essentially what I am trying to achieve here is from the servers POV, make sure I only accept requests that come from my mobile app (I thought client certs would have been the solution to this). From the clients POV, I want to make sure I am talking to the *correct* server. Could you suggest a robust way of solving this issue without using client certs? – James Mar 27 '13 at 20:42
  • Client certificates cannot tell anything about the server; for the client to make sure that they talk to the right server, the _server_ must have a certificate (and that's very common with SSL). For the idea of making sure that the requests only come for the mobile app, well, this has no solution _per se_; regardless of certificates, you cannot prevent a user from extracting the private key (or secret password or whatever) from the app and using it from a PC. – Thomas Pornin Mar 27 '13 at 20:49
  • What you can do is to distribute to each user a user-specific secret value which the app will show to the server (within the SSL connection) to authenticate. At least, if a user extracts the secret from the app and begins to distribute it widely, you can deactivate it on the server. Making the secret a private key for a certificate changes nothing at all here. – Thomas Pornin Mar 27 '13 at 20:51
  • Interesting, this is exactly what I am doing at the minute. When a user registers the server generates a public/private (aka API/Secret) key which is sent back to the client all over SSL. The public key is then sent as a header in the request and the private key is used to generate a signature (based on the request data). The server then uses the public key to locate the user, uses the secret stored on the server to re-generate a signature (using request data), if the signatures match, the request is authorised. Both keys are stored on the client securely in a keystore. – James Mar 29 '13 at 22:42