I've run into an interesting problem with authentication, and I wonder
if I may solicit some advice on how to go about solving it.
My CherryPy application currently presents two separate "interfaces"; an
administrative one intended for consumption by a web browser, and a
separate REST-like messaging interface that exchanges YAML messages with
a GUI app (which is accessing it with httplib2). This is mostly
constructed and working, since I've been building this sort of
interactively and bottom-up.
I've finally made my way to the part where I need authentication.
Authenticating the administrative interface is known territory, since I
have flexiblity there. No problem.
The GUI app, on the other hand, constitutes the interface of a public
terminal, and the requirements have users authenticating to this
terminal using MIFARE contactless smart cards to make the interaction
with it as rapid as possible. When the user presents their smart card,
the reader I have collects a unique, opaque token stored on it that
serves as the credential and sends it to my GUI app.
I figured digest auth would be the simplest to use in this situation,
since, while the system is a relatively low-value target (MIFARE itself
offers only modest security), I certainly don't want blatant replay
vulnerabilities either. Using HTTP auth would help keep the client's
complexity down as well. I find that writing event-driven code is
complex enough, if I can offload this to httplib2 it would be most
helpful :)
The digest_auth tool, however, expects a map of {username: password},
but there is no such logical mapping in my application, except if I use
the token as the username with a blank password. However, unless I'm
mistaken, digest auth protocol appears to send the username portion in
the clear. This has me at a loss. Before I go rolling a whole new digest
auth tool without this in-built assumption, is there an easier way?
Apologies for getting so long winded. :)
-Kyle
I assume your application is not running over SSL right? Otherwise the
fact your data is transmitted as clear text wouldn't be a problem anymore.
You're saying that you don't have a logical map in your application but
how do you map the opaque token to the user's profile/account? In other
words, without even talking about transporting that token, what do you do
with it once received by the GUI application?
- Sylvain
--
Sylvain Hellegouarch
http://www.defuze.org
>
> > The digest_auth tool, however, expects a map of {username:
> > password}, but there is no such logical mapping in my application,
> > except if I use the token as the username with a blank password.
> > However, unless I'm mistaken, digest auth protocol appears to send
> > the username portion in the clear. This has me at a loss. Before I
> > go rolling a whole new digest auth tool without this in-built
> > assumption, is there an easier way?
> >
>
> I assume your application is not running over SSL right? Otherwise the
> fact your data is transmitted as clear text wouldn't be a problem
> anymore.
Correct, SSL is not involved as yet. I did look at the possiblity,
although it appears to me if I use basic over SSL, I still need to do
some fooling around here, since basic_auth's interface is more or less
the same.
On the plus side (which didn't occur to me until just now), using the
token as the username with a blank password would become an option under
SSL. Making the certs work for this might be hairy though, since the
machine IP is not static, nor does it have a traditional DNS entry. (I'm
using mDNS/DNS-SD to locate it at the moment.)
>
> You're saying that you don't have a logical map in your application
> but how do you map the opaque token to the user's profile/account? In
> other words, without even talking about transporting that token, what
> do you do with it once received by the GUI application?
Ah, I guess I should have been more specific. The tokens on each smart
card are unique, and I store the token in a field on the user record at
the server. The association is established externally to the GUI app
when the smart card is issued.
What I should have said, perhaps, is that the GUI doesn't a priori know
which user is authenticating, because that information isn't stored in
the cards as they are currently implemented.[1] It receives the opaque
token from the smart card which it must then use to authenticate the
holder of the card to the server.
The original idea was to expose a resource for the purpose of
responding to a properly authenticated request with a YAML message to
the effect, "that smart card belongs to Fred Foobar", causing the GUI to
then proceed to a "logged in" state. (This is only to provide the user
with feedback that they successfully logged into the system. Strictly
speaking, what actually need authenticating are the POST/PUT/DELETEs
from the GUI associated with the user's interactions. If I can achieve
that, then technically, the GUI doesn't have to ever know whose card it
was to work properly.)
>
> - Sylvain
>
Thanks for your consideration :)
-Kyle
[1] This was a design decision simply to avoid having to write stuff
onto every card for this purpose, the token is actually the card's
factory-burned serial number. They are "unforgable enough" for our
purpose. It has the additional benefit of leaving the cards' tiny
EEPROMs available for other uses.
If I understand you correctly those POST/PUT/DELETE actually happen
between the GUI and the RESTful web service you've set. You also state the
strictly speaking the authentication doesn't happen between the GUI and
the user, in other words it would appear to me that you don't need an
authentication handler at the GUI level. What you need is a way to ensure
the security of the token being sent by the smart card. I assume that the
server keep track of previously received tokens so that it can safely
reject any subsequent requests with a token that has already been used.
Let the WS/GUI do the actual authentication in an environment you have
greater control over.
In such case SSL would appear to be the easiest and safest bet.
> If I understand you correctly those POST/PUT/DELETE actually happen
> between the GUI and the RESTful web service you've set.
Indeed.
> You also state the strictly speaking the authentication doesn't happen
> between the GUI and the user, in other words it would appear to me
> that you don't need an authentication handler at the GUI level.
Right, basically the GUI as currently designed is actually functioning
as an untrusted user agent.
> What you need is a way to ensure the security of the token being sent
> by the smart card. I assume that the server keep track of previously
> received tokens so that it can safely reject any subsequent requests
> with a token that has already been used.
The "token" is basically just a shared secret, but with the extra
guarantee that each user has a unique one, so it doubles as a candidate
key in the database that can uniquely identify the user it was issued
to.
> Let the WS/GUI do the actual authentication in an environment you have
> greater control over.
>
> In such case SSL would appear to be the easiest and safest bet.
I'm not sure I get this part. If the GUI does the authentication, then
the server must then authenticate and trust the GUI itself. Since the
GUI runs on a machine physically accessible to the public, I'm hesitant
to extend trust to it.
Or, do you mean I should instead secure the whole WS<->GUI link with
SSL, and then include the token as part of the POST/PUT/DELETE
"payload", rather than using HTTP's authentication mechanism?
-Kyle
I came back to digest auth. The username transmitted in the auth headers
is the SHA256 of the smartcard token, and the password used in the
challenge is the token itself. I am caching the SHA256 of the token in
my database alongside the token on each user record, so I can look them
up quickly. I'm using the restful_auth tool from the tools wiki since it
allows me to do a database query to find the appropriate password to go
with a username.
I kept dismissing the idea of transmitting a plain old hash out of hand
because normally just transmitting a password as a hash (without using
salt and/or nonces) doesn't help you at all; it's blatantly vulnerable
to replay attacks. But, in my mind I was conflating that with "having
the hash of a password is just as good as having the password".
Of course, it took me until now to realize that you can't calculate the
correct response to a cryptographic challenge for a shared secret if you
only know the hash of the secret.
Gotta love a good old brain fart :)
Thanks for the help,
-Kyle