4

I have a general security question:

Let's say there is a client-server application with authorisation by login and password using a secure connection between server and client (https). User can have different permissions that allow user to access to different kind of information provided by the server. This is only a part of server functionality. But it creates high traffic load.

So I want to introduce another one kind of server (info-server) only for providing info purpose apart from the main server. It should be as simple as possible, so I don't want to introduce any kind of interaction between main and info servers via web.

So what solution I see now (all connections between client and servers are secure):

  1. The main server performs user authorisation via login and password;
  2. The main server detects what permissions user has, stores user info and permissions to a string, encrypts the string with a symmetric private key. So now we have a token;
  3. The main server sends the token and an address of an info server to the client;
  4. The client connects to the info server and sends the token to it;
  5. The info server decrypts token with the symmetric private key and detects what permisiions user has;

I'm not sure if this approach is secure or not. Is there any vulnerabilities? If I use token-authorisation what kind of encryption should I prefer?

I would appreciate your help. Thanks!

Dmitry P.
  • 163
  • 4
  • 4
    Are the downvoters going to bother leaving a comment, or should our new guy just sit here thinking "wow these guys are assholes!"? – Polynomial Jan 21 '14 at 10:47
  • @Polynomial I received two very good answers here, think that's more important than votes :) Thanks anyway. – Dmitry P. Jan 21 '14 at 12:34
  • 1
    We seem to have a problem with new users being put off by people who downvote needlessly, without explanation. Whilst you clearly took it in your stride, many don't, and it can be frustrating for both them and moderators to deal with. I like people to stick around here because it's genuinely a good place to be, hence my interest. Anyway, glad you got the answers you needed! :] – Polynomial Jan 21 '14 at 13:32

2 Answers2

5

This is not encryption that you need. Well, you might need it too, but that won't do the whole job.

Encryption is for confidentiality: you encrypt the token if you don't want the client to learn the token contents, i.e. his permissions. Maybe you indeed want to hide that information from the client, but that's a secondary concern. The primary security characteristic that you wish to achieve is integrity: you don't want clients to be able to produce fake tokens and be granted entry. As a general rule, encryption does not provide integrity; for that you need a MAC, or a digital signature. Encryption may, as a by-product, make data alteration a bit harder, but certainly not impossible.

Digital signatures are more generic, but heavier (higher size and CPU overhead). What digital signatures provide is the following: whoever verifies the signature needs not be able to generate other signatures; the verification and generation powers are disjoint. With a MAC, the same key is used to produce the MAC and to verify it, so the two powers are equivalent. In your case, the exta genericity of signatures may be unnecessary, because both servers are yours, so you can probably arrange for a shared secret key between both servers. However, you might want to use a signature so that an attacker who obtains a read-only glimpse of the data server (e.g. through an old discarded hard disk) does not obtain enough information to be able to fake tokens, and thus obtain all write accesses for all possible users in your system.


If you follow the simple road of a shared key, and you want both encryption and MAC, then you are encouraged to use an "encryption mode" which provides both, because decades of research have come to the conclusion that mixing encryption and MAC together is a complex endeavour, prone to catastrophic silent failures. So use GCM or EAX.

If you want signatures and encryption, then again this is not a light job. An extra complication is that the power to decrypt must be on the data server side, while signature generation will be on the info server. In this model, both servers would have their own key pair. The smart thing to do would be to use an existing format and library which handles the tricky points. I suggest OpenPGP; it is a well-studied format, and there are open-source implementations available (e.g. GnuPG, which has bindings in many frameworks).


Regardless of the model and implementation, absence of direct communication between your two servers necessarily gives some extra power to the client: an evil client may decide to send the token, or not, or send another token. Replay attacks are an illustration: the client may want to send an old token value, thus allowing him entry with privileges which have since then been revoked.

One method to block replay attacks is to embed in the token an expiry date (under the protection of the MAC or signature, of course: evil clients would love to be able to modify that date). This works, but implies an inherent latency: if you decide, on the info server side, to revoke the privileges of a given user, then the said user can still use his current token until its expiration. This can lead to uncomfortable situations: emergency stop buttons should work immediately, not "within 15 minutes".

You may want to separate authentication from authorisation. Authentication is about making sure of the identity of the client; authorisation is about deciding what a given client should be allowed to do. The login+password procedure is authentication. If the bulk of the "high traffic load" comes from the password processing (e.g. because you hash password with a good password hashing function, as you should), then you might want to offload authentication on the "info server", while keeping authorisation on the "data server". In that model, the token will contain "this is Bob", instead of "the holder of this token is allowed to read data elements 1 and 2".

With such a setup, you still have an immediate, no-latency method to block indelicate users. An evil user is still himself, so his authentication token can remain valid for a long time; and if a user's password is stolen and you notice it (almost always asynchronously), you still have the option to block that user on the data server until the crisis is resolved.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • Wow! Thanks for such a detailed answer! Unfortunately, can't give you +1 yet because of my low reputation. //Edit: Great! Now I can :) – Dmitry P. Jan 21 '14 at 12:29
  • When sharing photos of pets in hats, I'd say 15 minutes latency is completely acceptable for revoking access. – paj28 Jan 21 '14 at 12:39
2

This approach can work; a notable example is how Facebook photos work - there are separate photo servers that are passed tokens in a similar manner to how you suggest (at least it used to, not checked recently). I wouldn't use this in a high-security situation like online banking. Also, it is quite an advanced technique with some subtleties to doing well, so I only recommend this to experienced developers.

There are a couple of specific problems with what you suggest:

1) Although the permissions data is encrypted, it could be tampered with. You need to use a "Message Authentication Code" (MAC) which also uses a private symmetric key, and this prevents tampering. In fact, at this point, encryption is optional. I would probably use HMAC-SHA1 as the MAC algorithm.

2) This is vulnerable to replay attacks. If a permission is revoked from a user, the token they have will still allow them access. The solution to this is to include a timestamp in the token and have a fixed expiry time - perhaps 15 minutes.

paj28
  • 32,736
  • 8
  • 92
  • 130