Merge pull request #18 from zoominsoftware/customize
Allow customized whitelists.
This commit is contained in:
commit
be213a84a4
@ -1,5 +1,5 @@
|
|||||||
name: xss-sanitize
|
name: xss-sanitize
|
||||||
version: 0.3.5.7
|
version: 0.3.6
|
||||||
synopsis: sanitize untrusted HTML to prevent XSS attacks
|
synopsis: sanitize untrusted HTML to prevent XSS attacks
|
||||||
description: run untrusted HTML through Text.HTML.SanitizeXSS.sanitizeXSS to prevent
|
description: run untrusted HTML through Text.HTML.SanitizeXSS.sanitizeXSS to prevent
|
||||||
XSS attacks. see README.md <http://github.com/yesodweb/haskell-xss-sanitize> for
|
XSS attacks. see README.md <http://github.com/yesodweb/haskell-xss-sanitize> for
|
||||||
|
|||||||
@ -12,6 +12,7 @@ module Text.HTML.SanitizeXSS
|
|||||||
-- * Custom filtering
|
-- * Custom filtering
|
||||||
, filterTags
|
, filterTags
|
||||||
, safeTags
|
, safeTags
|
||||||
|
, safeTagsCustom
|
||||||
, balanceTags
|
, balanceTags
|
||||||
|
|
||||||
-- * Utilities
|
-- * Utilities
|
||||||
@ -33,7 +34,7 @@ import Network.URI ( parseURIReference, URI (..),
|
|||||||
isAllowedInURI, escapeURIString, uriScheme )
|
isAllowedInURI, escapeURIString, uriScheme )
|
||||||
import Codec.Binary.UTF8.String ( encodeString )
|
import Codec.Binary.UTF8.String ( encodeString )
|
||||||
|
|
||||||
import Data.Maybe (catMaybes)
|
import Data.Maybe (mapMaybe)
|
||||||
|
|
||||||
|
|
||||||
-- | Sanitize HTML to prevent XSS attacks. This is equivalent to @filterTags safeTags@.
|
-- | Sanitize HTML to prevent XSS attacks. This is equivalent to @filterTags safeTags@.
|
||||||
@ -53,8 +54,10 @@ sanitizeBalance = filterTags (balanceTags . safeTags)
|
|||||||
balanceTags :: [Tag Text] -> [Tag Text]
|
balanceTags :: [Tag Text] -> [Tag Text]
|
||||||
balanceTags = balance []
|
balanceTags = balance []
|
||||||
|
|
||||||
-- | Parse the given text to a list of tags, apply the given filtering function, and render back to HTML.
|
-- | Parse the given text to a list of tags, apply the given filtering
|
||||||
-- You can insert your own custom filtering but make sure you compose your filtering function with 'safeTags'!
|
-- function, and render back to HTML. You can insert your own custom
|
||||||
|
-- filtering, but make sure you compose your filtering function with
|
||||||
|
-- 'safeTags' or 'safeTagsCustom'.
|
||||||
filterTags :: ([Tag Text] -> [Tag Text]) -> Text -> Text
|
filterTags :: ([Tag Text] -> [Tag Text]) -> Text -> Text
|
||||||
filterTags f = renderTagsOptions renderOptions {
|
filterTags f = renderTagsOptions renderOptions {
|
||||||
optMinimize = \x -> x `member` voidElems -- <img><img> converts to <img />, <a/> converts to <a></a>
|
optMinimize = \x -> x `member` voidElems -- <img><img> converts to <img />, <a/> converts to <a></a>
|
||||||
@ -74,17 +77,36 @@ balance unclosed (TagOpen name as : tags) =
|
|||||||
TagOpen name as : balance (name : unclosed) tags
|
TagOpen name as : balance (name : unclosed) tags
|
||||||
balance unclosed (t:ts) = t : balance unclosed ts
|
balance unclosed (t:ts) = t : balance unclosed ts
|
||||||
|
|
||||||
-- | Filters out any usafe tags and attributes. Use with filterTags to create a custom filter.
|
-- | Filters out unsafe tags and sanitizes attributes. Use with
|
||||||
|
-- filterTags to create a custom filter.
|
||||||
safeTags :: [Tag Text] -> [Tag Text]
|
safeTags :: [Tag Text] -> [Tag Text]
|
||||||
safeTags [] = []
|
safeTags = safeTagsCustom safeTagName sanitizeAttribute
|
||||||
safeTags (t@(TagClose name):tags)
|
|
||||||
| safeTagName name = t : safeTags tags
|
-- | Filters out unsafe tags and sanitizes attributes, like
|
||||||
| otherwise = safeTags tags
|
-- 'safeTags', but uses custom functions for determining which tags
|
||||||
safeTags (TagOpen name attributes:tags)
|
-- are safe and for sanitizing attributes. This allows you to add or
|
||||||
| safeTagName name = TagOpen name
|
-- remove specific tags or attributes on the white list, or to use
|
||||||
(catMaybes $ map sanitizeAttribute attributes) : safeTags tags
|
-- your own white list.
|
||||||
| otherwise = safeTags tags
|
--
|
||||||
safeTags (t:tags) = t:safeTags tags
|
-- @safeTagsCustom safeTagName sanitizeAttribute@ is equivalent to
|
||||||
|
-- 'safeTags'.
|
||||||
|
--
|
||||||
|
-- @since 0.3.6
|
||||||
|
safeTagsCustom ::
|
||||||
|
(Text -> Bool) -- ^ Select safe tags, like
|
||||||
|
-- 'safeTagName'
|
||||||
|
-> ((Text, Text) -> Maybe (Text, Text)) -- ^ Sanitize attributes,
|
||||||
|
-- like 'sanitizeAttribute'
|
||||||
|
-> [Tag Text] -> [Tag Text]
|
||||||
|
safeTagsCustom _ _ [] = []
|
||||||
|
safeTagsCustom safeName sanitizeAttr (t@(TagClose name):tags)
|
||||||
|
| safeName name = t : safeTagsCustom safeName sanitizeAttr tags
|
||||||
|
| otherwise = safeTagsCustom safeName sanitizeAttr tags
|
||||||
|
safeTagsCustom safeName sanitizeAttr (TagOpen name attributes:tags)
|
||||||
|
| safeName name = TagOpen name (mapMaybe sanitizeAttr attributes) :
|
||||||
|
safeTagsCustom safeName sanitizeAttr tags
|
||||||
|
| otherwise = safeTagsCustom safeName sanitizeAttr tags
|
||||||
|
safeTagsCustom n a (t:tags) = t : safeTagsCustom n a tags
|
||||||
|
|
||||||
safeTagName :: Text -> Bool
|
safeTagName :: Text -> Bool
|
||||||
safeTagName tagname = tagname `member` sanitaryTags
|
safeTagName tagname = tagname `member` sanitaryTags
|
||||||
|
|||||||
24
test/main.hs
24
test/main.hs
@ -11,9 +11,19 @@ test f actual expected = do
|
|||||||
let result = f actual
|
let result = f actual
|
||||||
result @?= expected
|
result @?= expected
|
||||||
|
|
||||||
sanitized :: Text -> Text -> Expectation
|
sanitized, sanitizedB, sanitizedC :: Text -> Text -> Expectation
|
||||||
sanitized = test sanitize
|
sanitized = test sanitize
|
||||||
sanitizedB = test sanitizeBalance
|
sanitizedB = test sanitizeBalance
|
||||||
|
sanitizedC = test sanitizeCustom
|
||||||
|
|
||||||
|
sanitizeCustom :: Text -> Text
|
||||||
|
sanitizeCustom = filterTags $ safeTagsCustom mySafeName mySanitizeAttr
|
||||||
|
where
|
||||||
|
mySafeName t = t `elem` myTags || safeTagName t
|
||||||
|
mySanitizeAttr (key, val) | key `elem` myAttrs = Just (key, val)
|
||||||
|
mySanitizeAttr x = sanitizeAttribute x
|
||||||
|
myTags = ["custtag"]
|
||||||
|
myAttrs = ["custattr"]
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = hspec $ do
|
main = hspec $ do
|
||||||
@ -87,3 +97,15 @@ main = hspec $ do
|
|||||||
sanitizedB "<img></img>" "<img />"
|
sanitizedB "<img></img>" "<img />"
|
||||||
it "interleaved" $
|
it "interleaved" $
|
||||||
sanitizedB "<i>hello<b>world</i>" "<i>hello<b>world<i></i></b></i>"
|
sanitizedB "<i>hello<b>world</i>" "<i>hello<b>world<i></i></b></i>"
|
||||||
|
|
||||||
|
describe "customized white list" $ do
|
||||||
|
it "does not filter custom tags" $ do
|
||||||
|
let custtag = "<p><custtag></custtag></p>"
|
||||||
|
sanitizedC custtag custtag
|
||||||
|
it "filters non-custom tags" $ do
|
||||||
|
sanitizedC "<p><weird></weird></p>" "<p></p>"
|
||||||
|
it "does not filter custom attributes" $ do
|
||||||
|
let custattr = "<p custattr=\"foo\"></p>"
|
||||||
|
sanitizedC custattr custattr
|
||||||
|
it "filters non-custom attributes" $ do
|
||||||
|
sanitizedC "<p weird=\"bar\"></p>" "<p></p>"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user