views:

114

answers:

3

I've got two systems that need to talk. The systems are setup likeso:

System A, running Django (Python 2.5) on Google App Engine (GAE)

System B, running Django (Python 2.6) on Ubuntu/Linux over Lighttpd (maybe nginx, later)

System A will periodically make requests ('requisitions') of System B using Url Fetch.

System B has a Django app setup to listen for these requests with a urls.py with something like:

urlpatterns = patterns('producer.views',
    url(r'^requisition$', 'requisition', name='requisition'),
)

And a corresponding views.py with something like:

import json
from django.http import HttpResponse

def requisition(request):
    " do something "
    response = HttpResponse()
    response['Content-type'] = 'application/json'
    response.write(json.dumps(...))
    return response

It would be a valuable addition to security of the system if System B responded to requisitions only from System A.

I'd like to know what options are available for System B to verify that requests have come from System A. I've considered the following:

  • Check that the IP address is from GAE (however I don't know the GAE IP addresses, they may change, and they may be spoofed)
  • Check that the reverse DNS of the IP is from GAE (however I don't know what GAE's DNS entries are, if they will change, and they may be spoofed)
  • Use a TLS client certificate from System A - but I don't know how to do this with GAE
  • Do a challenge/response based on something shared, like a salt, with pycrypto

Ideally I want to end up with a views.py with something likeso:

... 
from django.http import HttpResponseForbidden 

def requisition(request):
   " do something "
  if not verify_request_origin():
     return HttpResponseForbidden("Denied.")

  response = HttpResponse()
  ...

Where verify_request_origin() returns true when the request made to System B was from System A on GAE.

Thank you and I look forward to hearing your thoughts.

+2  A: 

It sounds like it would suffice to use SSL on the link and include a password in the query string.

SSL keeps out sniffers, and you're not going to reveal the queries outside systems under your control, so a shared secret will do (and will be more secure than IP tracking, as other GAE sites will use those addresses).

Andrew Aylett
+1  A: 

You are spot on, the first two bullet points are no use.

A password as Andrew says is good enough, unless you are worried about issues on browser caches. If you are then you should still use SSL, but to authenticate one app to the other via, for instance, hmac, and use that to generate a shared secret for the session. The secret should reside in the code, not the transmitted data.

Vinko Vrsalovic
+1  A: 

System A can send HTTPS requests via urlfetch.fetch -- just have the URL parameter start with https://. However this does not authenticate it to system B (it does prevent sniffers and man-in-the-middle attacks); there's no way to use a client TLS certificate.

Verifying that the request does come from GAE (which would be perfectly feasible: just use Google's own DNS server at 8.8.8.8 -- if somebody's managed to pwn Google's own DNS, their ability to trick your system B would be the least of the world's worries;-) doesn't help either for the same reason: it could be any GAE app (they all share a bunch of IP addresses and a given IP address could be in use by any number of GAE apps over a short period of time).

So encrypting the payload with a shared secret seems simplest given GAE's limitations. PyCrypto -- perhaps with exPyCrypto in front -- might be good; or, you might like to try SlowAES (I have a weak spot for the latter, of course;-).

Alex Martelli
There's no need to encrypt the payload - and, in fact, doing so without an HMAC doesn't guarantee integrity. Simply applying an HMAC is the simplest approach.
Nick Johnson