You don't have javascript enabled. Good luck! :(
記事公開日: 2018/08/04
最終更新日: 2020/03/03

hamlet とインライン Javascript

この問題は Escape single quote in Julius variable interpolation #221 で解決されました。

関連情報

脆弱性を含むコード

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes       #-}
{-# LANGUAGE TemplateHaskell   #-}
{-# LANGUAGE TypeFamilies      #-}
import Data.Maybe
import Yesod

data App = App

mkYesod "App" [parseRoutes|
/ HomeR GET
|]

instance Yesod App

getHomeR :: Handler Html
getHomeR = defaultLayout $ do
  mname <- lookupGetParam "name"

  [whamlet|
    $maybe name <- mname
      <img onload="init('#{name}')" src="https://www.yesodweb.com/static/logo-home2-no-esod-smaller2.png">
  |]

  toWidget [julius|
    function init(text) {
      // Do whatever you want
    }
  |]

main :: IO ()
main = warp 3000 App

例えば http://localhost:3000/?name=%27),alert(1)// にアクセスすると alert が実行されてしまいます。

対策

方法1 インラインをやめる

julius に全部書く。

潜在的にではあるが、脆弱性は存在しているので推奨しません。(実装者によっては知らずに書いてしまうかもしれない)

方法2 Content Security Policy の設定

Content Security Policy を設定してインラインの JavaScript を禁止する。

instance Yesod App where
  yesodMiddleware handler = do
    addHeader "Content-Security-Policy" "default-src 'self'"
    defaultYesodMiddleware handler

方法3 明示的に javascript のエスケープを行う

Rails の escape_javascript を参考に自前でエスケープ処理を実装する。

今のところ、Yesod はそのような関数を提供していない。

ちなみに、以下のようにしても、やはり脆弱性は存在している。(内部関数の string ではエスケープ処理が不十分なため)

[whamlet|
  $maybe name <- mname
    <img onload="init('#{renderJavascript $ toJavascript $ toJSON name}')" src="https://www.yesodweb.com/static/logo-home2-no-esod-smaller2.png">
|]