[Twisted-Python] Re: cred and stateless protocols
Phil Mayers
p.mayers at imperial.ac.uk
Wed May 10 04:42:32 MDT 2006
Manlio Perillo wrote:
>> The only sensible solution to HTTP authentication for important
>> applications is to use an HTTPS link, signed server certs and ideally
>> client certs as well,
>
>
> Yes, but how many people knows how to set up a private certificate?
> And how many sites uses certs verification?
Lots. I honestly don't think it's that hard but we might have to agree
to disagree on this. If it has a fault, it's the difficulty virtual
hosting without burning IPs.
>
> It would be nice to store a certificate on a smart card and authenticate
> to a web server using only that certificate.
You can do that now if you want. But the hardware is expensive. Frankly,
I think a local software store with key is fine.
But the important thing is to use SSL and server certs. The client certs
are just a nice-to-have.
>> an "Authorization: GoogleAuth THETOKEN" header.
>
> And this header should be supplied for every successive requests (like
> cookies)?
Yes, avoiding the need for an extra round-trip per request.
>
>> This provides much
>> greater scalability and is similar to MS Passport (which itself is
>> similar to Kerberos).
>>
>> Presumably the token expires. You should note however that the token is
>> NOT used for sessioning. HTTP 302 redirects and URL parameters are used
>> for that.
>
>
> I'm not sure to understand this.
GET /resource
401 unauth
GET /resouce
Authorization: GoogleAuth=foobarbaz
302 Moved
Location: /resource?sessionid=id
GET /resource?sessionid=id
Authorization: GoogleAuth=foobarbaz
200 OK
CONTENT
...then on subsequence requests, you can do:
GET /another_resource?sessionid=id
Authorization: GoogleAuth=foobazbaz
200 OK
CONENT
...which is a single round-trip with authentication and sessioning
>
>> You might ponder that Google separated out auth and sessions
>> even in their engineering compromise.
>>
>> Note that the above refers to the non-browser API. Presumably the
>> browser API will use a passport-alike 302+cookie.
>>
>> For open source examples, see PubCookie.
>>
>
> Thanks for the link.
> I have not read the source, but the "granting cookie" what type of
> informations contains to be sure that the UA is the "right" one?
I haven't used it, I just know it's generally well thought of.
>
>>> By the way:
>>> for user tracking in UDP, why not just use the peer address?
>> Pardon? Are you serious?
>>
>
> Well, let me explain this better.
> Unfortunately there are not examples of UDP servers in twisted.
>
> Since UDP is connection-less, the first thing that come to my mind is:
>
> class MyProtocol(DatagramProtocol):
> def __init__(self):
> self.users = {}
>
> def datagramReceived(self, data, (host, port)):
> context = self.users.setdefault(host, Context())
> response = context.handle(data)
> self.transport.write(data, (host, port))
>
>
> Where the Context class keep an internal state, like IMAP.
That is phenomenally insecure
1. You're using just the IP and not the IP+port, which means 2 users
behind the same NAT will be unable to simultaneously use your service,
or will see each others data.
2. Since it's UDP it's trivially forged, so unless your context.handle
FURTHER authenticates the data (via e.g. HMAC and key agreement) it's
basically open to the world
3. You're creating a new context for the 1st packet from each IP, so I
can trivially send hundreds of thousands of packets to your service with
forged source addresses and exhaust the CPU and memory resources of your
server.
At ABSOLUTE MINIMUM a UDP protocol must force the client to round-trip
the first packet using minimal CPU resources possible to at least ensure
it's not a source-spoofing DDoS.
# WARNING WARNING WARNING DO NOT USE INSECURE IN MANY WAYS
# I strongly suggest the use of TCP or existing secure UDP
# protocols such as Q2Q
class proto(DatagramProtocol):
MAGIC = 'MYPT'
ECHO = open('/dev/random').read(16)
# PDU format: MAGIC(4 bytes)+FLAGS(1 bytes)+PAYLOAD
def datagramReceived(self, data, (host, port)):
if len(data)<28:
# too short
return
if data[:4]!=self.MAGIC:
# not our protocol
return
flags = ord(data[4])
# 1st packet in connection has flags=0
if flags==0:
# note: no state and minimal CPU consumed here
self.transport.write(self.MAGIC+'\0'+self.ECHO, (host, port))
return
# 2nd packet must have flags==1 and payload==ECHO
elif flags==1:
if data[5:]!=self.ECHO:
return
# ok, we've verified there's something on the other
# end, now start e.g. secure diffie-hellman
context = startContext(host, port, self.transport)
else flags==2:
feedContext(host, port, data)
The above is NOT SECURE and would need sequence numbers, authentication
and integrity protection adding. But it should hopefully convince you
that the naive approach is just that - and in fact actively dangerous in
a modern, hostile internet environment.
More information about the Twisted-Python
mailing list