philip.mcgrath
2019-9-15 12:29:18

@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/cookiesweb-server/http/id-cookie should just forward its arguments and let net/cookies do whatever seems best.


soegaard2
2019-9-15 13:10:24

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


soegaard2
2019-9-15 13:13:08

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


popa.bogdanp
2019-9-15 13:33:31

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.


popa.bogdanp
2019-9-15 13:36:13

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.


popa.bogdanp
2019-9-15 13:36:21

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


soegaard2
2019-9-15 13:38:05

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


popa.bogdanp
2019-9-15 13:38:34

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

https://github.com/Bogdanp/koyo/blob/master/koyo-lib/blueprints/standard/app-name-here/components/hash.rkt


soegaard2
2019-9-15 13:40:42

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


soegaard2
2019-9-15 14:40:08

@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?


soegaard2
2019-9-15 14:42:22

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


popa.bogdanp
2019-9-15 15:12:53

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


popa.bogdanp
2019-9-15 15:13:10

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


soegaard2
2019-9-15 15:14:00

popa.bogdanp
2019-9-15 15:14:24

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



soegaard2
2019-9-15 15:17:15

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


popa.bogdanp
2019-9-15 15:17:29

Hah, yes, it would’ve!


popa.bogdanp
2019-9-15 15:17:41

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


soegaard2
2019-9-15 15:18:58

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


popa.bogdanp
2019-9-15 15:20:55

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)


soegaard2
2019-9-15 15:28:06

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


soegaard2
2019-9-15 17:13:48

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


soegaard2
2019-9-15 19:51:07

aymano.osman
2019-9-15 23:52:52

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))]))