0

以下代码在 localhost:3000 启动一个 Web 服务器。

#!/usr/bin/env stack
-- stack script --resolver=lts-12.16

{-# LANGUAGE EmptyDataDecls             #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GADTs                      #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE QuasiQuotes                #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE TypeFamilies               #-}
{-# LANGUAGE ViewPatterns               #-}
import Yesod
import Database.Persist.Sqlite
import Control.Monad.Trans.Resource (runResourceT)
import Control.Monad.Logger (runStderrLoggingT)
import Data.Text

-- Define our entities as usual
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Book
    title Text
    author Text
    publisher Text
    date Text
    price Int
    deriving Show
|]

-- We keep our connection pool in the foundation. At program initialization, we
-- create our initial pool, and each time we need to perform an action we check
-- out a single connection from the pool.
data SQLi = SQLi ConnectionPool

-- We'll create a single route, to access a person. It's a very common
-- occurrence to use an Id type in routes.
mkYesod "SQLi" [parseRoutes|
/ HomeR GET
/book/#BookId BookR GET
|]

-- Nothing special here
instance Yesod SQLi

-- Now we need to define a YesodPersist instance, which will keep track of
-- which backend we're using and how to run an action.
instance YesodPersist SQLi where
    type YesodPersistBackend SQLi = SqlBackend

    runDB action = do
        SQLi pool <- getYesod
        runSqlPool action pool

searchFrame :: [Entity Book] -> Widget
searchFrame books = 
  [whamlet|
    <table border=1>
      <tr>
        <th>ID
        <th>Title
        <th>Author
        <th>Publisher
        <th>Publication date
        <th>Price
      $forall Entity bookid book <- books
        <tr>
          <td>
            <a href=@{BookR bookid}>#{show bookid}
          <td>
            #{bookTitle book}
          <td>
            #{bookAuthor book}
          <td>
            #{bookPublisher book}
          <td>
            #{bookDate book}
          <td>
            #{bookPrice book}
  |]

-- List all people in the database
getHomeR :: Handler Html
getHomeR = do
  mBookAuthor <- lookupGetParam "author"
  maybe (do
    books <- runDB $ selectList [] [Asc BookId]
    defaultLayout $ searchFrame books)
    (¥author -> do
       books <- runDB $ selectList [BookAuthor ==. author] [Asc BookId]

       defaultLayout $ [whamlet|
         <h1>Search books manually
         ^{searchFrame books}
       |]) $ mBookAuthor

-- We'll just return the show value of a person, or a 404 if the Person doesn't
-- exist.
getBookR :: BookId -> Handler String
getBookR bookId = do
    book <- runDB $ get404 bookId
    return $ show book

openConnectionCount :: Int
openConnectionCount = 10

main :: IO ()
main = runStderrLoggingT $ withSqlitePool ":memory:" openConnectionCount $ ¥pool -> liftIO $ do
    runResourceT $ flip runSqlPool pool $ do
        runMigration migrateAll
        insert $ Book "A Midsummer Night's Dream" "Shakespeare" "A bookstore"   "1979/01" 600
        insert $ Book "Hamlet"    "Shakespeare" "B bookstore"   "1997/04" 1260
        insert $ Book "Macbeth"   "Shakespeare" "C bookstore"   "2001/05" 1530
        insert $ Book "King Lear"     "Shakespeare" "D bookstore" "2004/07" 1890
    warp 3000 $ SQLi pool

然后,加载http://localhost:3000/?author=' AND EXTRACTVALUE(0, (SELECT CONCAT('$', id, ':', pwd) FROM users LIMIT 0, 1)) #有时会导致 500 Internal Server错误,即使我们加载正常页面,例如http://localhost:3000/也会发出此错误消息

实际上,这可能是 SQL 注入的攻击媒介。所以,我对天气感到困惑,这是由攻击或其他原因引起的。有人可以解释这种行为吗?

4

1 回答 1

0

哎呀。我错过了withSqlitePool不应该与 :memory: 一起使用的内容。通过给它一个文件名,问题就解决了。

于 2018-11-03T07:48:17.750 回答