Skip to content

Commit

Permalink
add xss protection as default (#2421)
Browse files Browse the repository at this point in the history
* * escape output by default for xss protection

* escaping '/' is not needed as of owasp-guide

* format
  • Loading branch information
TomTriple authored Sep 24, 2023
1 parent 6adb972 commit 7e37bb0
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,14 @@ private[http] object OutputEncoder {
private val `>` = ">"
private val `"` = """
private val `'` = "'"
private val `/` = "/"

/**
* Encode HTML characters that can cause XSS, according to OWASP
* specification:
* https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#output-encoding-rules-summary
*
* Specification: Convert & to &amp;, Convert < to &lt;, Convert > to &gt;,
* Convert " to &quot;, Convert ' to &#x27;, Convert / to &#x2F;
* Convert " to &quot;, Convert ' to &#x27;
*
* Only use this function to encode characters inside HTML context:
* <html>output</html
Expand Down Expand Up @@ -61,7 +60,6 @@ private[http] object OutputEncoder {
case '>' => `>`
case '"' => `"`
case '\'' => `'`
case '/' => `/`
case _ @char => char.toString
}

Expand Down
13 changes: 11 additions & 2 deletions zio-http/src/main/scala/zio/http/template/Dom.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package zio.http.template

import zio.http.internal.OutputEncoder

/**
* Light weight DOM implementation that can be rendered as a html string.
*
Expand All @@ -40,6 +42,7 @@ sealed trait Dom { self =>
val elements = children.collect {
case self: Dom.Element => self
case self: Dom.Text => self
case self: Dom.Raw => self
}

val noElements = elements.isEmpty
Expand All @@ -61,9 +64,11 @@ sealed trait Dom { self =>
else
s"<$name ${attributes.mkString(" ")}>$inner</$name>"

case Dom.Text(data) => data
case Dom.Attribute(name, value) => s"""$name="$value""""
case Dom.Text(data) => OutputEncoder.encodeHtml(data.toString)
case Dom.Attribute(name, value) =>
s"""$name="${OutputEncoder.encodeHtml(value.toString)}""""
case Dom.Empty => ""
case Dom.Raw(raw) => raw
}
}

Expand All @@ -76,10 +81,14 @@ object Dom {

def text(data: CharSequence): Dom = Dom.Text(data)

def raw(raw: CharSequence): Dom = Dom.Raw(raw)

private[zio] final case class Element(name: CharSequence, children: Seq[Dom]) extends Dom

private[zio] final case class Text(data: CharSequence) extends Dom

private[zio] final case class Raw(raw: CharSequence) extends Dom

private[zio] final case class Attribute(name: CharSequence, value: CharSequence) extends Dom

private[zio] object Empty extends Dom
Expand Down
30 changes: 30 additions & 0 deletions zio-http/src/test/scala/zio/http/template/DomSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,36 @@ object DomSpec extends ZIOHttpSpec {

assertTrue(dom.encode == """<a href="https://www.zio-http.com">zio-http</a>""")
},
test("xss protection for text nodes") {
val dom = Dom.element(
"a",
Dom.attr("href", "http://www.zio-http.com"),
Dom.text("""<script type="text/javascript">alert("xss")</script>"""),
)
assertTrue(
dom.encode == """<a href="http://www.zio-http.com">&lt;script type=&quot;text/javascript&quot;&gt;alert(&quot;xss&quot;)&lt;/script&gt;</a>""",
)
},
test("xss protection for attributes") {
val dom = Dom.element(
"a",
Dom.attr("href", """<script type="text/javascript">alert("xss")</script>"""),
Dom.text("my link"),
)
assertTrue(
dom.encode == """<a href="&lt;script type=&quot;text/javascript&quot;&gt;alert(&quot;xss&quot;)&lt;/script&gt;">my link</a>""",
)
},
test("raw output") {
val dom = Dom.element(
"a",
Dom.attr("href", "http://www.zio-http.com"),
Dom.raw("""<script type="text/javascript">alert("xss")</script>"""),
)
assertTrue(
dom.encode == """<a href="http://www.zio-http.com"><script type="text/javascript">alert("xss")</script></a>""",
)
},
suite("Self Closing")(
test("void") {
checkAll(voidTagGen) { name =>
Expand Down

0 comments on commit 7e37bb0

Please sign in to comment.