Add laxSameSiteSessions and strictSameSiteSessions

This commit is contained in:
Bob Long 2016-05-01 16:31:01 +01:00
parent 2cbe60c53d
commit a797c2e5d4
6 changed files with 82 additions and 3 deletions

View File

@ -53,6 +53,8 @@ module Yesod.Core
, envClientSessionBackend , envClientSessionBackend
, clientSessionBackend , clientSessionBackend
, sslOnlySessions , sslOnlySessions
, laxSameSiteSessions
, strictSameSiteSessions
, sslOnlyMiddleware , sslOnlyMiddleware
, clientSessionDateCacher , clientSessionDateCacher
, loadClientSession , loadClientSession

View File

@ -49,7 +49,7 @@ import qualified Text.Blaze.Html5 as TBH
import Text.Hamlet import Text.Hamlet
import Text.Julius import Text.Julius
import qualified Web.ClientSession as CS import qualified Web.ClientSession as CS
import Web.Cookie (parseCookies) import Web.Cookie (parseCookies, sameSiteLax, sameSiteStrict, SameSiteOption)
import Web.Cookie (SetCookie (..)) import Web.Cookie (SetCookie (..))
import Yesod.Core.Types import Yesod.Core.Types
import Yesod.Core.Internal.Session import Yesod.Core.Internal.Session
@ -366,6 +366,22 @@ sslOnlySessions = (fmap . fmap) secureSessionCookies
setSecureBit cookie = cookie { setCookieSecure = True } setSecureBit cookie = cookie { setCookieSecure = True }
secureSessionCookies = customizeSessionCookies setSecureBit secureSessionCookies = customizeSessionCookies setSecureBit
-- | Helps defend against CSRF attacks by setting the SameSite attribute on
-- session cookies to "Lax".
laxSameSiteSessions :: IO (Maybe SessionBackend) -> IO (Maybe SessionBackend)
laxSameSiteSessions = sameSiteSession sameSiteLax
-- | Helps defend against CSRF attacks by setting the SameSite attribute on
-- session cookies to "Strict".
strictSameSiteSessions :: IO (Maybe SessionBackend) -> IO (Maybe SessionBackend)
strictSameSiteSessions = sameSiteSession sameSiteStrict
sameSiteSession :: SameSiteOption -> IO (Maybe SessionBackend) -> IO (Maybe SessionBackend)
sameSiteSession s = (fmap . fmap) secureSessionCookies
where
sameSite cookie = cookie { setCookieSameSite = (pure s) }
secureSessionCookies = customizeSessionCookies sameSite
-- | Apply a Strict-Transport-Security header with the specified timeout to -- | Apply a Strict-Transport-Security header with the specified timeout to
-- all responses so that browsers will rewrite all http links to https -- all responses so that browsers will rewrite all http links to https
-- until the timeout expires. For security, the max-age of the STS header -- until the timeout expires. For security, the max-age of the STS header

View File

@ -1,5 +1,5 @@
{-# LANGUAGE CPP #-} {-# LANGUAGE CPP #-}
module YesodCoreTest (specs) where module YesodCoreTest (specs) where
import YesodCoreTest.CleanPath import YesodCoreTest.CleanPath
import YesodCoreTest.Exceptions import YesodCoreTest.Exceptions
@ -48,4 +48,5 @@ specs = do
LiteApp.specs LiteApp.specs
Ssl.unsecSpec Ssl.unsecSpec
Ssl.sslOnlySpec Ssl.sslOnlySpec
Ssl.sameSiteSpec
Csrf.csrfSpec Csrf.csrfSpec

View File

@ -1,6 +1,8 @@
{-# LANGUAGE TypeFamilies, QuasiQuotes, TemplateHaskell, MultiParamTypeClasses, OverloadedStrings #-} {-# LANGUAGE TypeFamilies, QuasiQuotes, TemplateHaskell, MultiParamTypeClasses, OverloadedStrings #-}
module YesodCoreTest.Ssl ( sslOnlySpec, unsecSpec ) where module YesodCoreTest.Ssl ( sslOnlySpec, unsecSpec, sameSiteSpec ) where
import qualified YesodCoreTest.StubSslOnly as Ssl import qualified YesodCoreTest.StubSslOnly as Ssl
import qualified YesodCoreTest.StubLaxSameSite as LaxSameSite
import qualified YesodCoreTest.StubStrictSameSite as StrictSameSite
import qualified YesodCoreTest.StubUnsecured as Unsecured import qualified YesodCoreTest.StubUnsecured as Unsecured
import Yesod.Core import Yesod.Core
import Test.Hspec import Test.Hspec
@ -62,3 +64,15 @@ unsecSpec = describe "A Yesod application with sslOnly off" $ do
where where
atHome = homeFixtureFor Unsecured.App atHome = homeFixtureFor Unsecured.App
isNotSecure c = not $ Cookie.setCookieSecure c isNotSecure c = not $ Cookie.setCookieSecure c
sameSiteSpec :: Spec
sameSiteSpec = describe "A Yesod application" $ do
it "can set a Lax SameSite option" $
laxHome $ "_SESSION" `cookieShouldSatisfy` isLax
it "can set a Strict SameSite option" $
strictHome $ "_SESSION" `cookieShouldSatisfy` isStrict
where
laxHome = homeFixtureFor LaxSameSite.App
strictHome = homeFixtureFor StrictSameSite.App
isLax = (== Just Cookie.sameSiteLax) . Cookie.setCookieSameSite
isStrict = (== Just Cookie.sameSiteStrict) . Cookie.setCookieSameSite

View File

@ -0,0 +1,23 @@
{-# LANGUAGE TypeFamilies, QuasiQuotes, TemplateHaskell, MultiParamTypeClasses, OverloadedStrings #-}
module YesodCoreTest.StubLaxSameSite ( App ( App ) ) where
import Yesod.Core
import qualified Web.ClientSession as CS
data App = App
mkYesod "App" [parseRoutes|
/ HomeR GET
|]
instance Yesod App where
yesodMiddleware = defaultYesodMiddleware . (sslOnlyMiddleware 120)
makeSessionBackend _ = laxSameSiteSessions $
fmap Just $ defaultClientSessionBackend 120 CS.defaultKeyFile
getHomeR :: Handler Html
getHomeR = defaultLayout
[whamlet|
<p>
Welcome to my test application.
|]

View File

@ -0,0 +1,23 @@
{-# LANGUAGE TypeFamilies, QuasiQuotes, TemplateHaskell, MultiParamTypeClasses, OverloadedStrings #-}
module YesodCoreTest.StubStrictSameSite ( App ( App ) ) where
import Yesod.Core
import qualified Web.ClientSession as CS
data App = App
mkYesod "App" [parseRoutes|
/ HomeR GET
|]
instance Yesod App where
yesodMiddleware = defaultYesodMiddleware . (sslOnlyMiddleware 120)
makeSessionBackend _ = strictSameSiteSessions $
fmap Just $ defaultClientSessionBackend 120 CS.defaultKeyFile
getHomeR :: Handler Html
getHomeR = defaultLayout
[whamlet|
<p>
Welcome to my test application.
|]