
@soegaard2 The implementation is here: https://github.com/RenaissanceBug/racket-cookies/blob/master/net-cookies-lib/net/cookies/server.rkt I can imagine it might be possible to do a more efficient implementation working with bytes internally (or certainly avoiding format
), though I don’t know how noticeable the improvement might be. OTOH, maybe working with strings helps to ensure valid Unicode. (I didn’t write this; I haven’t thought through these tradeoffs.) But all of this is in net/cookies
—web-server/http/id-cookie
should just forward its arguments and let net/cookies
do whatever seems best.

@philip.mcgrath Thanks for info. Good point about unicode.

Hi All. I have made a new version of the “submit links and vote” example. The new “feature” is users. The tricky parts to get right are securely storing ~passwords~ password-derived keys in the database and (again) securely storing login-status on the clients as cookies. If you spot any mistakes or oddities let me know.
https://github.com/soegaard/web-tutorial/tree/master/listit2

The way you’re verifying password hashes is susceptible to timing attacks in https://github.com/soegaard/web-tutorial/blob/274bcabd4bbb61098f8b78b72d789f1e78f343b7/listit2/model.rkt#L269 . Instead of comparing the keys using equal?
(which, I believe, compares the byte strings byte-by-byte and short circuits as soon as a difference is found (the timing attack vector)), you should use pwhash
to generate the hash and pwhash-verify
to verify it. Both are provided by crypto-lib
.

Another subtle attack vector lies in the fact that all the crypto factories rely on the FFI
so that means that each key hashing step suspends execution of the Racket runtime in favor of the calls to the FFI, which, necessarily, are slow.

So someone spamming login requests to your server can take it down. Or at least severily impact the performance for other users.

Thanks for the review. I’ll switch to pwhash and pwhash-verify.

To work around this problem in koyo, I run a separate place specifically for password hashing.

Sounds like an elegant solution. Need to think more about the problem though.

@popa.bogdanp When I use kdf
directly I can give the salt as an argument. The pwhash
on the other hand has no salt argument. So how do I pass the salt?

Nevermind - I just concatenate the salt and password before calling pwhash.

@soegaard2 I believe pwhash
already generates a random salt for you and stores it in the resulting string.

So you don’t need to store the salt separately from the password hash.

That could be it. Was looking at: https://github.com/rmculpepper/crypto/blob/master/crypto-lib/main.rkt#L460

For example:
> (pwhash (get-kdf (list 'pbkdf2 'hmac 'sha256)) #"foo" '((iterations 256)))
"$pbkdf2-sha256$256$3oFJpTRpEHCJwJsuxw556g$yAsr9zcpXsPfL/zdsynsz.WfvyWCSjgJkkrve3R9xSI"
> (pwhash 'argon2id #"foo" '((t 2) (p 2) (m 256)))
"$argon2id$v=19$m=256,t=2,p=2$ocD8hiNQ2OJCllP3aLzpnw$NITdNfMXvpT1bJ1+MOmDAu2xRIM8n6O6+Fyl8X2Tiuc"
sections of the result are separated by $, the first section is the name of the kdf, followed by params, followed by the salt and finally the digest


Thanks. Automatic salting. A line in the docs of pwhash
would have helped.

Hah, yes, it would’ve!

I remember having to dig into this code for the same reason a few months ago.

I looked at your forms
library, and I have decided to try it out. I like that it is independent of the presentation.

Sweet. Let me know how that goes. I really wanted to use formlets
early on, but error reporting and code reuse is hindered by the way that library works (iirc)

I submitted a PR with a change to the docs of pwhash.

The code has now been updated to use pwhash. At the same time I changed it to use Argon if available.

This example in the the web-server docs uses a request-number
. Any idea what it is? https://docs.racket-lang.org/web-server/http.html?q=request-bindings#%28def._%28%28lib._web-server%2Fhttp%2Frequest-structs..rkt%29._request-bindings%2Fraw%29%29

looks like it assumes it is defined for the purpose of the example. Looking at it I assume a definitions that looks like this
#lang web-server/insta
(define (start _)
(response/xexpr
(format "Sum: ~a" (+ (get-number (request-number)) (get-number (request-number))))))
(define (request-number)
(send/suspend
(lambda (k-url)
(response/xexpr
`(form ([action ,k-url])
"Enter a number: "
(input ([type "text"] [name "number"])))))))
(define (get-number req)
(match
(bindings-assq
#"number"
(request-bindings/raw req))
[(? binding:form? b)
(string->number
(bytes->string/utf-8
(binding:form-value b)))]
[_
(get-number (request-number))]))