Haskell Secure Coding

Secure coding practices for Haskell applications.


SQL Injection Prevention

 1-- ❌ Vulnerable
 2import Database.PostgreSQL.Simple
 3getUserBad :: Connection -> String -> IO [User]
 4getUserBad conn username = 
 5    query_ conn $ fromString $ "SELECT * FROM users WHERE username = '" ++ username ++ "'"
 6
 7-- ✅ Secure: Parameterized queries
 8getUserGood :: Connection -> String -> IO [User]
 9getUserGood conn username = 
10    query conn "SELECT * FROM users WHERE username = ?" (Only username)

Command Injection Prevention

 1-- ❌ Vulnerable
 2import System.Process
 3runCommandBad :: String -> IO String
 4runCommandBad filename = 
 5    readProcess "sh" ["-c", "cat " ++ filename] ""
 6
 7-- ✅ Secure
 8import System.Process
 9import Data.Char (isAlphaNum)
10runCommandGood :: String -> IO (Either String String)
11runCommandGood filename 
12    | all (\c -> isAlphaNum c || c `elem` "._-") filename = 
13        Right <$> readProcess "cat" [filename] ""
14    | otherwise = return $ Left "Invalid filename"

XSS Prevention

 1-- ❌ Vulnerable
 2import Text.Blaze.Html5 as H
 3displayMessage :: String -> Html
 4displayMessage msg = H.div $ toHtml msg
 5
 6-- ✅ Secure: Text.Blaze escapes by default
 7import Text.Blaze.Html5 as H
 8import qualified Data.Text as T
 9displayMessage :: T.Text -> Html
10displayMessage msg = H.div $ toHtml msg
11
12-- For raw HTML (use carefully)
13displayTrustedHtml :: T.Text -> Html
14displayTrustedHtml = preEscapedToHtml

Secure Random Generation

 1-- ❌ Insecure
 2import System.Random
 3generateToken :: IO Int
 4generateToken = randomRIO (0, maxBound)
 5
 6-- ✅ Secure
 7import Crypto.Random
 8import qualified Data.ByteString as BS
 9
10generateToken :: IO BS.ByteString
11generateToken = getRandomBytes 32

Timing Attack Prevention

 1-- ❌ Vulnerable to timing attacks
 2comparePasswords :: String -> String -> Bool
 3comparePasswords = (==)
 4
 5-- ✅ Secure: Constant-time comparison
 6import Data.ByteString (ByteString)
 7import qualified Data.ByteString as BS
 8import Crypto.MAC.HMAC
 9
10constantTimeCompare :: ByteString -> ByteString -> Bool
11constantTimeCompare a b = 
12    BS.length a == BS.length b && 
13    BS.foldl' (\acc (x, y) -> acc && x == y) True (BS.zip a b)

Related Snippets