3

I am trying to add authentication to a xmlrpc server (which will be running on nodes of a P2P network) without using user:password@host as this will reveal the password to all attackers. The authentication is so to basically create a private network, preventing unauthorised users from accessing it.

My solution to this was to create a challenge response system very similar to this but I have no clue how to add this to the xmlrpc server code. I found a similar question (Where custom authentication was needed) here.

So I tried creating a module that would be called whenever a client connected to the server. This would connect to a challenge-response server running on the client and if the client responded correctly would return True. The only problem was that I could only call the module once and then I got a reactor cannot be restarted error. So is there some way of having a class that whenever the "check()" function is called it will connect and do this?

Would the simplest thing to do be to connect using SSL? Would that protect the password? Although this solution would not be optimal as I am trying to avoid having to generate SSL certificates for all the nodes.

Community
  • 1
  • 1
bradleyjkemp
  • 247
  • 3
  • 13

3 Answers3

2

Don't invent your own authentication scheme. There are plenty of great schemes already, and you don't want to become responsible for doing the security research into what vulnerabilities exist in your invention.

There are two very widely supported authentication mechanisms for HTTP (over which XML-RPC runs, therefore they apply to XML-RPC). One is "Basic" and the other is "Digest". "Basic" is fine if you decide to run over SSL. Digest is more appropriate if you really can't use SSL.

Both are supported by Twisted Web via twisted.web.guard.HTTPAuthSessionWrapper, with copious documentation.

Jean-Paul Calderone
  • 47,755
  • 6
  • 94
  • 122
  • The only problem is that these assume that the server is trusted. If a P2P node was accidently given the IP of an attacker then using user:pass@host would give them the login details. My authentication is mutual and so also ensures that the server knows the password. – bradleyjkemp Jun 28 '12 at 12:05
  • Digest authentication does not reveal the plaintext password to the server. However, it sounds like you'd really be better off using SSL. Generating SSL certificates for all nodes really isn't that hard and provides you much stronger guarantees. – Jean-Paul Calderone Jun 28 '12 at 13:10
  • What I want to do is check that the node I am connecting to is authorised to be part of the network. To do this in SSL I would need a Certificate Authority to sign all of the certificates and only trust those ones. Parallel Python has a system similar to the one I am trying to create but I am unsure how that is implemented. – bradleyjkemp Jun 28 '12 at 13:19
  • It's easy to have a certificate authority. What about that approach concerns you enough to want to avoid it? – Jean-Paul Calderone Jun 28 '12 at 17:54
  • Because I want new nodes to be able to be quickly added to the network without having to sign certificates for them. The signing of certificates would have to be done manually as otherwise you just get the same problem of checking that the client is authorised to have a certificate signed. I have looked into how Parallel Python does it's authentication and it does it the method I said above; the only problem is that they use raw sockets whereas I want to add it to twisted. – bradleyjkemp Jun 28 '12 at 18:12
  • You have to provision credentials *somehow*. How do new nodes get passwords? Either they're manually approved following some verification, in which case it's just as slow as the SSL scenario you described, or it's automatic in which case you have no idea if the node is really trustworthy. – Jean-Paul Calderone Jun 28 '12 at 19:17
2

Based on your problem description, it sounds like the Secure Remote Password Protocol might be what you're looking for. It's a password-based mechanism that provides strong, mutual authentication without the complexity of SSL certificate management. It may not be quite as flexible as SSL certificates but it's easy to use and understand (the full protocol description fits on a single page). I've often found it a useful tool for situations where a trusted third party (aka Kerberos/CA authorities) isn't appropriate.

Rakis
  • 7,779
  • 24
  • 25
  • Thanks this is exactly the sort of thing I was looking for. Do you know however how I would add this to twisted? One problem may be that XMLRPC is stateless and so I may have to use some other stateful protocol. – bradleyjkemp Jun 29 '12 at 08:32
2

For anyone that was looking for a full example below is mine (thanks to Rakis for pointing me in the right direction). In this the user and password is stored in a file called 'passwd' (see the first useful link for more details and how to change it).

Server:

#!/usr/bin/env python
import bjsonrpc
from SRPSocket import SRPSocket
import SocketServer
from bjsonrpc.handlers import BaseHandler
import time

class handler(BaseHandler):
    def time(self):
        return time.time()

class SecureServer(SRPSocket.SRPHost):
    def auth_socket(self, socket):
        server = bjsonrpc.server.Server(socket, handler_factory=handler)
        server.serve()

s = SocketServer.ForkingTCPServer(('', 1337), SecureServer)
s.serve_forever()

Client:

#! /usr/bin/env python
import bjsonrpc
from bjsonrpc.handlers import BaseHandler
from SRPSocket import SRPSocket
import time

class handler(BaseHandler):
    def time(self):
        return time.time()

socket, key = SRPSocket.SRPSocket('localhost', 1337, 'dht', 'testpass')

connection = bjsonrpc.connection.Connection(socket, handler_factory=handler)

test = connection.call.time()
print test
time.sleep(1)

Some useful links:

bradleyjkemp
  • 247
  • 3
  • 13