-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WAMP-SCRAM specification #135
Comments
FWIW, I am +1 on this, and want to come up with a proof-of-concept implementation "soon". That means: AutobahnJS, AutobahnPython and Crossbar.io. Once we have it, WAMP-SCRAM should always be chosen over WAMP-CRA, as the former is expected to provide more security than the latter. @Paranaix The most important point is the mapping to WAMP messages. You mentioned in the other thread that reusing existing message exchange would be "misuse", because in |
In the case additional fields are allowed for |
You might also want to consider the Secure Remote Password protocol. |
If my interpretation of the SCRAM RFC is correct, it should be possible to strengthen standard SCRAM-SHA-1 or SCRAM-SHA-256 by pre-hashing the password client-side with a stronger algorithm such as bcrypt, scrypt, or Argon2. With SCRAM, the hashing work factor is limited by the client's computing power. This is nice for reducing server workload, but has the downside that the password hash strength is limited by the client. These benchmarks published on browser-computed scrypt and Argon2 hashes (using asm.js code compiled for the browser) tell us that the Javascript implementations are roughly an order of magnitude slower than their native counterparts. What would normally take 100ms on a native implementation would seem to take on the order of 1-2 seconds on an asm.js implementation for an equivalent password hash strength. SCRAM requires that Unicode username/password strings be normalized via the SASLprep profile (RFC4013) of the stringprep framework (RFC3454). I managed to find the reklatsmasters/saslprep Javascript library, and the author confirmed that it works on modern browsers. I also found eloquent/precis-js, a JavaScript implementation of the PRECIS framework RFC7564 + RFC7613, where PRECIS supersedes stringprep. Alas, RFC7564+RFC7613 have been recently superseded by RFC8264+RFC8265. SASLprep preserves the case of usernames, whereas PRECIS has an optional profile for mapping the username to lowercase. In the case of SASLprep, it's not clear if the server can still choose to do a case-insensitive comparison of the username in the database. One way to sidestep normalization would be to require that usernames/passwords can only be 7-bit ASCII. This seems to be permitted under SCRAM RFC 5802, section 2.2, Normalize:
Another approach might be to adopt only NFKC Unicode normalization for username/password, which is supported on the browser by String.prototype.normalize(), with unorm as a polyfill. However, this approach would ignore characters prohibited by SASLprep, such as non-ASCII spaces, or control characters. |
I've started working on a WAMP-SCRAM spec Markdown document on my personal fork. I'll let you folks know when there is enough meat in it for review. |
Here is an initial WAMP-SCRAM draft on my personal fork. I'd like to get some initial feedback before submitting a pull request. |
Thanks for your offer of feedback, @konsultaner . Someone needs to review the algorithms in my draft and compare it with RFC5802. RFC7677 has test vectors that you can use to check your implementation if you use the same test nonces. If a client allows you to send arbitrary HELLO.Options, lets you receive arbitrary CHALLENGE.Details, and lets you send arbitrary AUTHENTICATE.Details, you should be able to use that client. If your client is a web browser, the WebCryptoAPI provides native implementations of PBKDF2, SHA-256 and HMAC if you're in a secure context (i.e. HTTPS). |
While writing the WAMP-SCRAM spec, I was also studying SRP, and I believe it to have fewer vulnerabilities, especially when used over an unsecure transport. I'd like to write a WAMP-SRP draft, but I cannot give any estimate as to when that will happen. |
@ecorm I went through the RFCs to dig deeper into the topic. I found channel binding to be a quite useful feature, but I seem to not find a detailed description on how to implement it. You have a very detailed step by step description on how to generate hashes and messages for SCRAM. It would help people like me (that are not familiar with that topic) a lot if you could add what to use from the underlying TLS handshake in what step. Something like Is channel binding even possible in a browser? No, right? The RFC for SCRAM has a sample for sha-1. It would be nice to have this for WAMP-SCRAM and its variants as well to have something to unit test on. |
@konsultaner I did not dig deeper into channel binding because it's not a feature we were planning to use for our product. RFC5929 section 4.1 describes exactly how to hash the certificate data for the
Note that the "SCRAM Algorithms" section is marked as non-normative, because the algorithms are already specified in the SCRAM RFC document.
RFC7677 has an example for PBKDF2+SHA256. I'll add a "Test Vectors" non-normative section that uses the example from RFC7677. |
@ecorm Thank you! |
Shouldn't they be optional too and be handled like
because
|
When I wrote that, I though that for an unrecognized authid, the server wouldn't even bother checking bullet points 3 & 4. But upon further thought, an attacker could very be a low-privilege user with a recognized authid that is trying to learn who the admin users are. I'll make those two conditions optional. Good catch. 👍 |
@konsultaner Wait, now I remember why I did it that way.
I think it's acceptable for a user to know if his/her own
In that case, if the server |
Lets say the router will send mock I know this scenario is not very likely to happen, but it could.
I'm not an security expert. Since the |
The |
rgd WAMP-CRA renaming of attributes (eg |
If you're referring to hashing algorithm parameters, it's not feasible to "hard-code" them because they are intended to be re-tuned in the future as hardware performance advances. The exceptions to this might be the "p" parameter of Argon2 and the "r" parameter of scrypt. WAMP router implementations can certainly choose to provide default algorithm parameters, but that is an implementation detail that is outside the scope of the WAMP spec, IMO. I'd love for there to be only one "golden" hashing algorithm, but there is no agreement in the industry as to which is the best one. Some prefer older algorithms such as bcrypt or scrypt, because they have been battle-tested for longer. Others prefer bleeding edge such as Argon2. And others prefer the NIST-approved PBKDF2. Even if WAMP-SCRAM covers four different hashing algorithms, nothing prevents a WAMP implementation from only implementing one or two among them. A WAMP-based application would likely only adopt one hashing algorithm.
Since user impersonation can done with other authmethods, I tend to agree that it should not be exposed in WAMP-SCRAM for now. I can lift all the impersonation stuff out of the WAMP spec and place it in a separate document for now, pending discussion/decision in issue #297. I could do the same for the channel binding feature - lift it out of the "basic" WAMP-SCRAM spec.
The suggestion was not to rename WAMP-CRA attributes, but to rename WAMP-SCRAM's |
Regarding naming: I think it makes sense to keep familiar names for whatever standard (so, e.g. keep "cost" if that's the most-used term). I don't see any gain trying to make the attributes match (especially because they aren't the same -- just a similar concept). @ecorm I think what @oberstet is getting at is: we should pick our favourite algorithm (for now?) to narrow the choices for users/implementors who don't want to learn about all of them and weigh the tradeoffs. We can always add more later. We can also choose to add algorithm support but still "bless" a best one (i.e. wording in the spec, like "if you don't know how to choose a hash algorithm, use X"). Similar for "cost" etc parameters: we probably should include them as knobs (because they're expected to get bigger), but we should definitely also include sensible defaults. Like "in 2018, cost parameter X is the default and is recommended [because ...]". The point here, from my perspective, is: someone who knows little about hash algorithms (etc) should be able to turn on "WAMP-SCRAM" and still be provided with secure, sensible defaults and a working system. They definitely should NOT have to read a bunch of stuff and try to choose between pbkdf2, bcrypt, scrypt, argon2, etc etc. even if "advanced" users can go and do that. Any choices that are "definitely bad" should be removed (or not added). I think we should choose "argon2" as the default, blessed password-hashing algorithm. |
At the very least, we should keep PBKDF2-SHA256, because that's the algorithm already specified in the standard SCRAM-SHA-256 (RFC7677), and some applications may be contractually bound to only using crypto functions approved by NIST. PBKDF2 is also implemented natively in the Javascript Web Crypto API (in secure contexts). Don't forget that there are three "flavors" or Argon2: Perhaps PBKDF2 and Argon2id as the two possible choices, and we forget about bcrypt and scrypt? I personally wouldn't mind getting rid of bcrypt because of its password/key length restrictions. I'm also not fond of scrypt because it's difficult to tune the CPU cost independently of the memory cost.
I'm not at all comfortable doing this within the WAMP spec, unless we can cite recommendations from authoritative sources. The general approach is to choose an acceptable run time (say 100ms), and tune the cost parameter on actual hardware until that run time is reached. This will be vastly different between mobile browsers and native desktop clients. The tunable memory parameter of Argon2 will also be vastly different among between hardware platforms. RFC7677 recommends at least 4096 iterations of PBKDF2-SHA-256 as of November 2015, so we could simply quote that in the WAMP-SCRAM spec. Perhaps there's a similar recommendation in the Argon2 spec? If the WAMP community wants to provide suggestions for parameters, perhaps it would be best done on a web page or "living document" outside of the WAMP specification (or even a StackOverflow community wiki). It would be even better if benchmark timing results were to accompany those recommendations. Of course WAMP implementors would be free to provide whatever recommendations they want. |
Okay that's a fair point; if we can't find authoritative sources then I guess this should be dropped. Still, giving someone a bunch of parameters without recommendations sounds .. "bad". From what I've read Argon2id basically rolls up all the same features as both bcrypt and scrypt combined -- leading to a conclusion of "keep PBKDF2 for 'older/wider-support' use-cases and use argon2id as the recommended approach". If we wanted to keep one of bcrypt or scrypt I'd also rather keep scrypt (but also happy to drop both in favour of argon2id) I see "the WAMP specification" as a "living document" -- couldn't the WAMP community recommend upgrades/changes to the recommendations via pull-requests (for example)? But perhaps you're right that the spec should just leave it up to implementors to make recommendations for their users, as they see fit? |
It's currently a living document now while it's hosted on GitHub, but that will no longer be the case if/when it becomes an RFC. I picture GitHub as the "develop branch" for the WAMP spec, while the RFC is going to be a "master branch" release. |
@ecorm re "living doc": okay I see what you mean. I would still be in favour of putting recommendations in the spec (with dates and assumptions stated). Ideally these could just be references to already-published recommendations. For comparison: the scrypt paper includes particular parameters (with a date, and the processor used) but the RFC for scrypt does not. The argon2 RFC draft includes a rule-based method of selecting the parameters, and includes example parameters for different use-cases (with processor speeds and memory specified). |
Folks, can I get a thumbs up or down on this comment about restricting the WAMP-SCRAM hashing algorithms to only PBKDF2 and Argon2? The rationale for this restriction is to not overwhelm WAMP users/implementors with four different possible hashing algorithms. If thumbs down, please explain why. Reason for PBKDF2: Approved by NIST and is a well known mature algorithm. Native implementation available in the Javascript Web Crypto API in secure contexts (i.e. HTTPS websites). Reason for Argon2: Winner of the Password Hashing Competition and positioned to be the successor to scrypt and bcrypt. It's the default password hashing algorithm in libsodium and is now also supported in PHP. Used by KeePass. |
+1 for PBKDF2-SHA256, because implementers have used it for WAMP-CRA and are familiar with it It was not hard to find libs to implement all suggested KDFs, but having no idea how to choose the best one, makes me feel like having to study all of them. Implementers shouldn't have to do it.
@oberstet I'm totally with you that renaming is not a good idea. Whats with extra/details in |
Going through the spec more closely, some notes/questions/comments:
|
@meejah Thanks for the detailed critique! 👍
There's already a mechanism for the client announcing its supported authmethods in the Let's say a client announces One could ask if the client should even bother announcing its supported wamp-scram variants? If not, is it acceptable for the client to I we want to place the burden on the server to check that the client supports the required algorithm+version, then I think the authmethod string should be something like
I wanted to avoid a single I've seen an Argon2 API (libsodium, I believe) that takes a version argument as an integer. I thought that having the version in its own attribute would alleviate the burden of parsing the version number out of a more complex string. I now think that the version suffix should be part of the authmethod string.
Yes, I think it would simplify things, since base64 output is guaranteed not to contain the illegal
I almost went with the more readable
Yes, that's correct. Good catch!
None of the authmethods that are currently in the WAMP spec make use of I agree that it would be better for WAMP-SCRAM to follow the same convention for using |
IMO, in general, this is exposing way to many knobs, and letting client-server negotiate details is also an invitation for trouble. Also, @ecorm could you pls file a PR so we can look at the proposed text?
If that is supposed to work like for WAMP-cryptosign, then this isn't flag, and the attribute should be name
As mentioned, I am -1 on exposing this |
If you're referring to the number of possible algorithms, there seems to be consensus here to reducing the set of algorithms to only PBKDF2 and Argon2id. I've described the rationale for those two in #135 (comment). We could recommend Argon2id as the default, with PBKDF2 also available for those applications that are restricted to NIST-approved crypto functions. Most crypto libraries providing SHA-256 and HMAC also provide PBKDF2, so it wouldn't be that much more work to provide PBKDF2 in addition to Argon2. As for the The other "knobs", We can take a cue from the libsodium library, and hide the
There is no negotiation involved. Once a password has been hashed using a certain algorithm/version, the client MUST support that same algorithm/version to authenticate the user. If your concern is with the algorithm and version number being appended to the
I'll do so for the next iteration of my proposal. I wanted to get some initial feedback before submitting a PR. The current proposed text is here.
I don't know about WAMP-cryptosign, but I can assure you that the SCRAM RFC calls it "channel binding flag". I need to investigate how WAMP-cryptosign uses its
I already said that I'd take it out of my proposal, pending a resolution to #297. |
For the "algorithm" vs. auth-method name things, I think we should do this:
Thus: there is no negotiation, the authmethod string is straightforward and it's more-obvious what to choose. |
As for the other knobs, the situation is:
It's tempting to try and get rid of the argon2 params (or roll them up; e.g. "memory is always |
Probably worth noting that in any case it's only "the person running Crossbar" that has to think about the parameters, and they could have "sensible defaults" (decided by the router authors). |
Hmm, |
I agree
I agree in principal, but prefer to name it the
I agree about both being mandatory to avoid the need to "negotiate". I'm not comfortable with
Now that bcrypt is out of the picture, we can go back to naming the CPU cost
I'm going to research why libsodium locks the parallelization factor to 1. libsodium is a widely-used crypto library, with bindings to several languages, and it would be a shame to force WAMP-SCRAM implementors to not be able to use it.
19 is the decimal representation of hexadecimal 0x13. 1.3 is the actual, current version number. |
Okay, I've figured out Argon2's parallelization parameter. On crypto libraries that support multithreading, this will make the library use multiple threads to compute the hash. With The On crypto libraries that don't support multi-threading, if the p parameter is greater than 1, the library will have to perform the parallel work sequentially. On such mono-threaded libraries, the p parameter effectively becomes a multiplier on Given that WAMP-SCRAM requires the password hash to be computed by the client, I think it's reasonable to restrict the Argon2 parallellization parameter to 1 for the WAMP-SCRAM authentication method. We can explain this rationale in the spec so that security-savvy folks aren't scratching their heads about why the parallelization parameter is not tunable. |
Something we need to achieve consensus on, is if we want to stick with the SASLprep username/password normalization algorithm mandated by the SCRAM spec, or just go with simple NFKC normalization, which is supported natively in browser-land Javascript via String.prototype.normalize(). SASLprep goes further than NFKC by dealing with various space characters, control characters, private characters, etc. I did find the reklatsmasters/saslprep Javascript library (MIT license), and the author confirmed that it works on modern browsers. For those who are unfamiliar with Unicode normalization, it's to deal with multiple code points that are visually rendered the same way. For example, there are code points for accented letters and there are also accent code points that combine with letter code points to be rendered as an accented character. Without any normalization, it would be possible for an imposter to choose a username that appears identical to another user, yet the unicode bytes are different and the system treats it as a different user. |
Can I get a thumb's up/down to lock the Argon2 parallelization parameter to 1? The rationale to lock at 1 is due to the hash being computed client-side. See my comment above for more details. |
Can I get a thumb's up to keep "saslprep" string normalization, as mandated by the SCRAM RFC, or thumb's down to use simple NFKC normalization? See my comment above for more details. |
requiring saslprep seems safer, and implementation then may or may not catch up with this tighter set -- I seem to remember there is even a slight gap in the Python Autobahn libs rgd treatment of regular expressions for URIs .. Perl having it right;) practically, I think these are really obscure, exotic cases - I don't care much as long as the implementations don't get fuzzed when being exposed to all the flavors. Eg technically requiring UTF8 encoding totally makes sense (there is a state machine to check exactly), but checking for some specific form of Unicode normalization seems crazy to me. Until the Unicode consortium can come up with a well defined, formally complete algorithm to check for some form, it is academic ... |
Link to WAMP-SCRAM spec here for convenience: https://github.com/wamp-proto/wamp-proto/blob/master/rfc/text/advanced/ap_authentication_scram.md |
As discussed in #128 WAMP-CRA is unsafe in regards to database thefts. A new and better authentication method is required. SCRAM turned out to be very promising.
oberstet already gave a summary (#128 (comment)):
The text was updated successfully, but these errors were encountered: