Strengthen random state token generation

Previously:

- System.Random, which seeds from system time (possible attack)
- 30 characters, a-z (low entropy)

Now:

- Crypto.Random, accepted as "cryptographically secure"
- 64 random bytes, Base64-encoded

cryptonite was already a transitive dependency, so there is really no
downside to this.

Fixes #132.
This commit is contained in:
patrick brisbin 2020-08-19 11:51:45 -04:00
parent e46da4cafb
commit cd3875b797
2 changed files with 10 additions and 4 deletions

View File

@ -24,13 +24,14 @@ library:
dependencies:
- aeson >=0.6 && <1.6
- bytestring >=0.9.1.4
- cryptonite
- errors
- hoauth2 >=1.7.0 && <1.15
- http-client >=0.4.0 && <0.7
- http-conduit >=2.0 && <3.0
- http-types >=0.8 && <0.13
- memory
- microlens
- random
- safe-exceptions
- text >=0.7 && <2.0
- uri-bytestring

View File

@ -5,6 +5,7 @@
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module Yesod.Auth.OAuth2.Dispatch
( FetchCreds
@ -14,12 +15,14 @@ where
import Control.Exception.Safe
import Control.Monad (unless, (<=<))
import Crypto.Random (getRandomBytes)
import Data.ByteArray.Encoding (Base(Base64), convertToBase)
import Data.ByteString (ByteString)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8)
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
import Network.HTTP.Conduit (Manager)
import Network.OAuth.OAuth2
import System.Random (newStdGen, randomRs)
import URI.ByteString.Extension
import Yesod.Auth hiding (ServerError)
import Yesod.Auth.OAuth2.ErrorResponse
@ -141,7 +144,9 @@ setSessionCSRF :: MonadHandler m => Text -> m Text
setSessionCSRF sessionKey = do
csrfToken <- liftIO randomToken
csrfToken <$ setSession sessionKey csrfToken
where randomToken = T.pack . take 30 . randomRs ('a', 'z') <$> newStdGen
where
randomToken =
decodeUtf8 . convertToBase @ByteString Base64 <$> getRandomBytes 64
-- | Verify the callback provided the same CSRF token as in our session
verifySessionCSRF :: MonadHandler m => Text -> m Text