I spent way too long working this out. I'm almost ashamed it took so long.

I've been hacking on a project called murmur-rest, as it's basically a head start on what I was going to do when I rebuilt the old MumbleDog stack to open source it: abstract away the braindeadedness of Ice so that commodity PHP hosts can be used to run admin panels and such. It even uses Flask, just like I was going to! (I really like Flask)

I've committed a few pieces of low-hanging fruit, and then started on a CVP patch (which is in gross need of refactoring, but does work, for the most part). Then I moved on to actual provisioning and such, writing a WHMCS module as I went, and got stuck trying to make it auth. We're using Digest authentication, and despite the fact everything was correct (countless hours of debug printf()s, and nothing to show for it), it wasn't working!

I ended up taking the thing to my Linux VM, and chopping everything down to about 20 lines of Python and using curl from the command line trying to work out where the bug was. Authentication works fine via the browser, what the heck is going on?

curl --digest -u 'admin:password2' http://localhost:5000/stats/
Unauthorized Access

I eventually turned on the -v flag so I could get extra output and noticed that even though we're not actually using any of the session stuff in Flask, it's trying to set a cookie anyway. On a whim I gave it a shot:

curl --digest -u 'admin:password2' -c cookies http://localhost:5000/stats/
{
    "all_servers": 1, 
    "booted_servers": 1, 
    "murmur-rest_version": "0.1", 
    "murmur_version": "1.3.0~970~g888a459~snapshot", 
    "uptime": 5733, 
    "users_online": 0
}

Success! You can even do it with -c /dev/null, as we don't need to keep the cookies around permanently, we just need to send them back for the digest auth to work correctly. I'm not entirely sure why we need to send them back, I'm thinking it might be a bug (or just weird logic) in Flask as from checking StackOverflow and many other websites it looks like digest auth is supposed to work without cookies. Maybe it's the only way Flask can prevent credential re-use or something? No idea.

I'm suspecting that if the client-side session/cookie stuff that Flask uses is the reason it didn't work, that that might be a security concern - maybe it's just the fact that I'm half asleep, but what's to stop someone from simply replaying the entire request, cookie and all? That's not a problem for me, because I'd serve the API stuff over HTTPS, but it seems like an excellent way for other end-users to shoot their own foot off.

Anyway, it even works inside PHP as well:

    curl_setopt($ch, CURLOPT_COOKIEJAR, "/dev/null");

And suddenly the WHMCS module is off and running! Unfortunately, I'm now way too tired to continue. I'll worry about the security implications tomorrow.

Update: It looks like my earlier suspicions were correct, the session cookies are used by Flask in it's default configuration to track nonces - and it's not a great idea, security wise. Since I don't want to run a database to track the sessions, and since HTTPS will basically be required, I'm considering just downgrading to Basic authentication anyway.

Horsham, VIC, Australia fwaggle

Published:


Modified:


Filed under:


Location:

Horsham, VIC, Australia

Navigation: Older Entry Newer Entry