10 ms·
Review requested for Django string signing
- tptacek 17y agoThis appears to be timeable. Rack and Rails just fixed a similar bug. Over LANs, attackers can figure out the correct MAC for any message. Also, what the heck is a "salt" on an HMAC-SHA1 signature? If you lose the secret key, you've lost the verifier. You shouldn't be using HMAC signatures in so many places that keying them individually is a problem.
- simonw 17y agoThanks - this kind of feedback is exactly why we're putting this out for review. Can you provide pointers or a bit more information as to how the timeable issue works, and what the workaround is? Is there a more technically correct term we should be using instead of 'salt'? And is that feature a total waste of time? Remember, we're building a framework for other developers to use - so saying "you shouldn't be using HMAC signatures in so many places that keying them individually is a problem" assumes that developers using Django (who may have no crypto / security knowledge at all) will understand that. Is this something we should cover in the documentation?
- tptacek 17y agoYou appear to have the same vulnerability as Google Keyczar had: http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/ http://rdist.root.org/2009/05/28/timing-attack-in-google-key... Which leads to the question: why aren't you simply using Keyczar?
- simonw 17y agoWe try to keep Django's dependencies down to the Python standard library + a database adapter, so I'm pretty limited on which underlying crypto libraries I can use. How big a deal is that timing attack? Would it be appropriate to ignore it by default, but provide people who are concerned about it the option to swap out the sha1 signing for something using an external library that isn't affected by it. Or even just drop an optional "time.sleep(random.random() * 0.01)" line in to the code that generates the signatures?
- tptacek 17y agoIt's a big enough deal that if I'm right (I looked at your code for about 15 seconds) and you ship it, you will look ridiculous when someone blogs the exploit code.
- patio11 17y agoThomas is the security consultant, I sell bingo cards to 60 year old women, take with appropriate grains of salt: the timing attack is impractical against almost all Django installations, and is difficult to exploit Internet-wide in an automated fashion (like, e.g., you can do for Wordpress vulnerabilities). However, the impact is probably severe if your installation is vulnerable (i.e. if the bad guy can get sufficiently local access to your site over the network, and if you allow him sufficient rejected attempts). This can happen in plausible circumstances. For example, if you host on Slicehost and the bad guy is sufficiently motivated to pay $20 a month and buy himself a slice in your data center, congratulations, it is highly likely you are vulnerable to timing attacks in this manner. (This vulnerability is by no means unique to Slicehost, I'm just using this as a practical example of how a dedicated adversary can plausibly exploit a common deployment scenario.) If you're vulnerable, the bad guy can compromise signatures given a long enough time. I am not a Django guy but I am a Rails guy, and one common pattern we have is to store things in the session where the session is serialized into the cookie. For example, we might store the authenticated user_id there. (I do.) The signing is what keeps someone from swapping out user_id = 12387 (their freebie account) for user_id = 1 (my all-powerful admin account) and convincing the system that the user logged into their browser is me. If you can forge a signature, free admin for you. Given that this vulnerability has catastrophic consequences for vulnerable users and you probably encourage coding practices which make users vulnerable to it, I'd put it pretty high on my list of things to fix prior to release. But again, I am not the security guy.
- brown9-2 17y agoI think that the issue is compounded here by the fact that Django is a framework which will be used in hundreds or thousands (or more) of applications deployed all over the world. Any security issue with the framework itself instantly puts thousands of apps at risk. If you have a single app then you can discount this kind of attack, but when you are producing code that will be used in thousands of other apps, it would be irresponsible to do so.
- simonw 17y agoI just had a more detailed look at Keyczar and it's pretty awesome. Unfortunately it depends on pycrypto which is a tough dependency for Django as a whole. We already have a mechanism for allowing you to "swap out" the hashing backend used for Django's get_signed_cookie and set_signed_cookie functions. It wouldn't be at all hard to write an optional keyczar backend for that. I think I'll do that. I'll need to extend the configurable backend aspect to cover other things within Django that use signing as well.
- illumen 17y agoI just tested the python fix there, and it was easy to find the difference with the python function given. The solution is to rate limit, and add random small sleeps. A tiny random sleep stops the variance from a string compare showing up. Rate limiting and blocking slow down an attacker from trying out lots of attempts anyway. If you have decent signal processing skills you should be able to show another keyczar exploit.
- tptacek 17y agoThat's a terrible fix. Adding noise degrades the signal without eliminating it. To defeat that countermeasure, you just take more measurements. The random sleeps, which are by nature random, get filtered out. The Keyczar Python fix --- if we're talking about Nate Lawson's code --- has no data-dependent timing. It invariably does the same ALU ops on every byte of the string, and fails if the strings aren't of the same length. That's the right solution to side channel vulnerabilities: eliminate the side channel.
- deleted 17y ago[deleted]
- deleted 17y ago[deleted]
- euroclydon 17y agoAnyone know the status of OWASP for Python? Here is a link to their unimplemented encryptor.py class: http://code.google.com/p/owasp-esapi-python/source/browse/esapi/encryptor.py http://code.google.com/p/owasp-esapi-python/source/browse/es...
- simonw 17y agoThere's some really good discussion of this going on on programming.reddit: http://www.reddit.com/r/programming/comments/ald1m/calling_crypto_security_experts_help_review_the/ http://www.reddit.com/r/programming/comments/ald1m/calling_c...
- tptacek 17y agoOW MY BRAIN. No, don't truncate SHA256 to SHA1 sizes. No, don't use MD5 to make your URLs shorter. No, DO NOT clear all of a user's signed cookies when an HMAC fails --- these aren't passwords, they're crypto secrets.
- brown9-2 17y agoI just want to say that it is really refreshing and awesome to see a framework developer/author/team reaching out to the community as a whole for this kind of review, rather than requesting feedback from a small group of committed contributors.
- cstone 17y agoI can tell you're pushing for terseness in the signed text (every character does count), but I'd definitely consider explicitly describing the cryptosystem and version you're using in each cookie. Also, is there some code elsewhere ensuring that the separator character is always escaped during signing? I don't see anything explicit, but I could definitely be missing something; I haven't messed with Django internals much..
- cstone 17y agoTo expand on the first part: with something up front saying "this key is signed using system FOO", you'll be able to support multiple systems in the future. This means that you'll be able to handle multiple systems (and upgrades) easily.
- sethg 17y agoIf the server can handle keys that are signed by either system FOO or system BAR, and the keys themselves don’t provide any clue about how they were signed, the server can just try to verify the signature using FOO and, if that system doesn’t return a “signature valid” response, fall back to BAR. Obviously if you’re permitting ten different signature-verification algorithms then this technique starts putting a significant load on the server, but if your protocol allows for ten different signature-verification algorithms, then you have bigger problems, right?
- tptacek 17y agoThis is a pointless feature and Django shouldn't implement it. If Django-signed messages are being persisted long-term in something other than an HTTP cookie, Django developers are abusing the feature. The sliver of code that's been published is not sufficient to protect long-term persisted data. If Django-signed messages are simply being used for cookies and token URLs, then it doesn't matter whether they're forward/backward compatible. They have no long-term value. Applications should fail gracefully when unintelligible messages are presented. In 99.999% of proper cases, this simply means bouncing the user back to the login prompt to get a new cookie. This isn't just pedantry. A fair subset of all cryptosystems have failed in later revisions because of negotiation vulnerabilities. Along with the "automatic key rotation" misfeature, this idea is as likely to burn you as it is to protect you.