Ok, so here’s an experimental, proof of concept plugin for Idno that provides OpenPGP encryption for form posts between web clients and the server (just in time for Reset the net 😉 ).

It makes use of OpenPGP.js, a pure javascript implementation of the OpenPGP spec. On form submission, the plugin will encrypt all form variables, client side in the browser, before transmitting them to the server.

What this for

Primarily, this is aimed at (partially) addressing a situation where you have an Idno site sitting behind a load balancer/reverse proxy like Squid, Nginx or Pound.

In this configuration it is common for the connection to be HTTPS only between the client and the load balancer node, at which point HTTPS is stripped and the connection to the back-end web server is conducted over HTTP. As we know from the NSA smiley, attacking this point where HTTPS is stripped at the load balancer was one of the ways the NSA and GCHQ was able to burgle customer data from Google’s cloud.

Using this plugin, the contents of the form will be encrypted with the back end server’s public key, meaning that the payload will remain encrypted as it transits through your data centre until it’s final destination, where, if you redesign your system as such, it could be stored in encrypted form and decoded only when necessary.

What this is NOT for

This is not intended to be a replacement for HTTPS.

Encrypting the form on the client does raise the bar slightly, making it much harder for a passive attacker to simply read your username and password as it travels over the wire. However, it does not protect against a more sophisticated attacker capable of launching a “Man in the middle“, or “Man on the side attack“.

Using HTTPS is important, because without it an attacker could insert their own public key into the mix, or modify the javascript sent.

Usage and limitations

The plugin currently piggybacks off of gnuPG to do the decryption on the server end, and so this requires you to perform a couple of configuration steps.

  • Make sure you’ve got gnuPG installed. If the binary isn’t at at /usr/bin/gpg, you can set opengpg_gnupg in your config.ini
  • Generate a keypair for your web server user
su www-data
gpg --gen-key
  • Make sure that the .gnupg directory is not accessible publicly, using a .htaccess or similar, since it’ll contain a secret key!
  • Get a copy of the public key gpg --export -a "User Name", and save it as openpgpPublicKey in your config.ini

Once you’ve done this, activate your plugin in your Idno settings, and you should be ready to rock and roll!

It was enjoyable playing with OpenPGP.js, and I can already think of some other cool uses for it (most obvious might be to enhance my OpenPGP elgg plugin).

Have fun!

» Visit the project on Github...

Yesterday, I wrote a post outlining a draft specification for a possible way to handle login on a distributed social network, together with a reference implementation for Known.

I got some really positive feedback, including someone pointing out a potential replay vulnerability with the protocol as it stands.

I admit I had overlooked replay as an attack vector (oops!), but since peer review is exactly why open standards are more secure than propriatory standards, I thought I’d kick off the discussion now!

The Replay problem

Alice wants to see something that Bob has written, so logs in according to the protocol, however Eve is listening to the exchange and records the login. She then, later, sends the same data back to Bob. Bob sees the signature, sees that it is valid, and then logs Eve in as Alice.

Worse, Eve could send the same packet of data to Clare and David’s site as well, all without needing access to Alice’s key.

Eve needs to be able to intercept Alice’s login session, which, if HTTPS has been deployed is largely impractical, but since this can’t always be counted on I’d like to improve the protocol.

Countermeasures

Largely, countermeasures to a replay attack take the form of creating the signature over something non-repeatable and algorithmically verifiable that Alice can generate and Bob can check.

This may be some sort of algorithmically generated hash, a timestamp, or even just a random number, or record whether we have seen a specific signature before.

My specific implementation has an additional wrinkle in that it has to function over a distributed network, in which each node doesn’t necessarily talk to each other (so we can’t check whether we’ve seen a signature or random number before, since Bob might have seen it, but Clare and David won’t have).

I also want to avoid adding too much complexity, so I’d like to avoid, if I can, doing some sort of multi-stage handshaking; for example hitting an endpoint on the server to obtain a random session id, then signing that and sending it back. Basically, I’d still like to be able to talk to a server using Unix command line tools (gpg) and CURL if I can!

Proposed revision

Currently, when Alice logs in to Bob’s site, Alice signs their profile URL using her key and sends it to Bob. Bob then uses this profile url to verify that Alice is someone with access to Bob’s site/post and then users the signature to verify that it is indeed Alice who’s attempting to log in.

What I propose, is that in addition to forming the signature over Alice’s profile URL, she also forms it over the URL of the page she is trying to see, and also the current time in GMT.

Including the requested URL in the signature allows Bob to verify that the request is for access on his site. If Eve sent this packet to Clare or Dave, it could be easily discarded as invalid.

Adding the timestamp allows Bob to check that this isn’t an old packet being replayed back. Since any implementation should have a small tolerance (perhaps a few minutes either side) to allow for clock drift, using a timestamp allows a small window of attack where Eve could replay the login. To counter this, Bob’s implementation should remember, for a short while, timestamps received for Alice and if the same one is seen twice invalidate all of Alice’s sessions.

  • Why invalidate all of Alice’s sessions when we see the same timestamp twice, can’t we just assume that the second packet is Eve?”

    Sadly not – sophisticated attackers are able to attack from a position physically close to you, so Eve’s login may be received first. In the situation where two identical login requests are received, it is probably safer to treat both as invalid.

    Perhaps a sophisticated implementation could delay Alice’s first login for a few seconds (after verifying) to see if any duplicates are received, and only proceed if there are none. This would limit the need to permanently store timestamps against a user’s account, but may be more complex from an implementation point of view.

  • Why use a timestamp rather than a random number?

    I was going back and forth on this… a random number (nonce) would remove the vulnerability window, but it would require Bob’s site to store every number we’ve seen thus far, so I finally opted not to take this approach.

I’d be interested in your thoughts, so please, leave a comment!