CSRF:Yesod runFormPost 总是 FormFailure
CSRF: Yesod runFormPost always FormFailure
提前为代码转储道歉。我对 Yesod 和 Haskell 都很陌生,我正在为 CSRF 问题而苦苦挣扎。据我了解,问题是表单的 _token
与环境令牌不匹配(运行 runFormPostNoToken 工作得很好)。我有一对路线:
/ HomeR GET
/upload UploadR POST
HomeR 的处理程序定义如下:
getHomeR :: Handler Html
getHomeR = do
((res, uploadWidget), enctype) <- runFormPost imgForm
setTitle "Title"
$(widgetFile "homepage")
表单本身和上传处理程序是:
imgForm :: Html -> MForm (HandlerT App IO) (FormResult Img, Widget)
imgForm hiddenInput = do
(titleRes, titleView) <- mreq textField uploadFormTitleSettings Nothing
(descRes, descView) <- mopt textareaField uploadFormDescriptionSettings Nothing
(fileRes, fileView) <- mreq fileField uploadFormAttachmentSettings Nothing
let imgRes = Img
<$> titleRes
<*> descRes
<*> fileRes
<*> pure (Likes 0)
<*> pure (Dislikes 0)
<*> pure (UserID 1)
<*> pure (Community 1)
let imgUploadWidget = do
toWidget
[whamlet|
^{ fvInput titleView }
^{ fvInput descView }
^{ fvInput fileView }
#{ hiddenInput }
<button type="submit">Submit
|]
return (imgRes, imgUploadWidget)
postImgUploadR :: HandlerT App IO Html
postImgUploadR = do
((imgRes, imgUploadWidget), enctype) <- runFormPost imgForm
let submission :: HandlerT App IO Html
submission = case imgRes of
FormSuccess upload -> defaultLayout [whamlet|The form was uploaded|]
FormMissing -> defaultLayout [whamlet|The form is missing|]
FormFailure upload -> defaultLayout [whamlet|The form failed.|]
submission
不幸的是,我什至不确定在这里要问什么问题——希望我的代码有明显的错误,并且有人可以指出正确的方向。我花了一些时间阅读函数的源代码,我 认为 我理解它,但我不确定第二个错误的 CSRF 令牌来自哪里(我假设它会被设置在会话变量中,因此不会改变)。已经好几个小时了,我想解决这个问题的所有尝试都失败了。
好吧,事实证明这是最耗时的错误之一,也是我处理过的最平凡的答案之一。
前段时间我在 sslOnlySessions
中添加了 makeSessionBackend
然后忘记了。在尝试了所有可能做错事的方法后,我退后一步,试图想出一个不同的角度来解决问题,它像一堆砖头一样击中了我。
我发布这个答案是为了防止 10 年后有人会犯我犯过的同样愚蠢的错误,在搜索他们的代码以找出错误后,最终启动 Google 并找到一个简单的答案.
Godspeed,未来的 Haskeller。
提前为代码转储道歉。我对 Yesod 和 Haskell 都很陌生,我正在为 CSRF 问题而苦苦挣扎。据我了解,问题是表单的 _token
与环境令牌不匹配(运行 runFormPostNoToken 工作得很好)。我有一对路线:
/ HomeR GET
/upload UploadR POST
HomeR 的处理程序定义如下:
getHomeR :: Handler Html
getHomeR = do
((res, uploadWidget), enctype) <- runFormPost imgForm
setTitle "Title"
$(widgetFile "homepage")
表单本身和上传处理程序是:
imgForm :: Html -> MForm (HandlerT App IO) (FormResult Img, Widget)
imgForm hiddenInput = do
(titleRes, titleView) <- mreq textField uploadFormTitleSettings Nothing
(descRes, descView) <- mopt textareaField uploadFormDescriptionSettings Nothing
(fileRes, fileView) <- mreq fileField uploadFormAttachmentSettings Nothing
let imgRes = Img
<$> titleRes
<*> descRes
<*> fileRes
<*> pure (Likes 0)
<*> pure (Dislikes 0)
<*> pure (UserID 1)
<*> pure (Community 1)
let imgUploadWidget = do
toWidget
[whamlet|
^{ fvInput titleView }
^{ fvInput descView }
^{ fvInput fileView }
#{ hiddenInput }
<button type="submit">Submit
|]
return (imgRes, imgUploadWidget)
postImgUploadR :: HandlerT App IO Html
postImgUploadR = do
((imgRes, imgUploadWidget), enctype) <- runFormPost imgForm
let submission :: HandlerT App IO Html
submission = case imgRes of
FormSuccess upload -> defaultLayout [whamlet|The form was uploaded|]
FormMissing -> defaultLayout [whamlet|The form is missing|]
FormFailure upload -> defaultLayout [whamlet|The form failed.|]
submission
不幸的是,我什至不确定在这里要问什么问题——希望我的代码有明显的错误,并且有人可以指出正确的方向。我花了一些时间阅读函数的源代码,我 认为 我理解它,但我不确定第二个错误的 CSRF 令牌来自哪里(我假设它会被设置在会话变量中,因此不会改变)。已经好几个小时了,我想解决这个问题的所有尝试都失败了。
好吧,事实证明这是最耗时的错误之一,也是我处理过的最平凡的答案之一。
前段时间我在 sslOnlySessions
中添加了 makeSessionBackend
然后忘记了。在尝试了所有可能做错事的方法后,我退后一步,试图想出一个不同的角度来解决问题,它像一堆砖头一样击中了我。
我发布这个答案是为了防止 10 年后有人会犯我犯过的同样愚蠢的错误,在搜索他们的代码以找出错误后,最终启动 Google 并找到一个简单的答案.
Godspeed,未来的 Haskeller。