How Go Templates Can Help With Cross Site Scripting(XSS)

Given the following code:

package main

import (
	"fmt"
	"net/http"

	"github.com/go-chi/chi/v5"
)

func homeHandler(w http.ResponseWriter, r *http.Request) {
	bio := `<script>alert("You have been hacked!! XD") </script>`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, "<h1>Welcome to my site!!!! </h1> <p>Bio:"+bio+"</p>")
}

func contactHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, "<h1>  Contact Page </h1><p> To get in touch, email me at <a href=\"mailto:example@example.test\"> exampke@example.test </a>.")
}

func faqHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, `<h1>  FAG Page </h1><p> Why blah bla bla blah? When yada, yada, yada.. </a>.
	`)
}

func main() {

	r := chi.NewRouter()
	r.Get("/", homeHandler)
	r.Get("/contact", contactHandler)
	r.Get("/faq", faqHandler)
	r.NotFound(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "Page Not Found", http.StatusNotFound)
	})

	fmt.Println("Starting the server on :3000...")
	http.ListenAndServe(":3000", r)

}

Notes

  • If we run the above web server, we will notice that an alert will pop-up in our browser telling us that we were hacked.
  • In other words, the <script>alert("You have been hacked!! XD") </script> was not interpreted as text but rendered as code.
  • To avoid this, we could have scaped it but encoding the string.

Non Scaped version of code

func homeHandler(w http.ResponseWriter, r *http.Request) {
	bio := `<script>alert("You have been hacked!! XD") </script>`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, "<h1>Welcome to my site!!!! </h1> <p>Bio:"+bio+"</p>")
}

Scaped version of code

func homeHandler(w http.ResponseWriter, r *http.Request) {
	bio := `&lt;script&gt;alert("You have been hacked!! XD") &lt;/script&gt;`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, "<h1>Welcome to my site!!!! </h1> <p>Bio:"+bio+"</p>")
}
  • Now, even though we could make it but ourselves, the html library from Go could actually saved us the manual effort.
  • Here is one example:

hello.gohtml

<h1> Hello, {{.Name}} </h1>
<p>Bio: {{.Bio}}</p>

main.go with Go HTML template (Printing to stdout)

package main

import (
	"html/template"
	"os"
)

type User struct {
	Name string
	Bio  string
}

func main() {

	t, err := template.ParseFiles("hello.gohtml")
	if err != nil {
		panic(err)
	}

	user := User{
		Name: "Alex Rabocse",
		Bio:  `<script>alert("You have been hacked!! XD") </script>`,  // Notice that the bio is not scaped.
	}

	t.Execute(os.Stdout, user)
	if err != nil {
		panic(err)
	}
  • Whe we execute the above code, we will see that the HTML library did the scaping for us:
go run main.go
<h1> Hello, Alex Rabocse </h1>
<p>Bio: &lt;script&gt;alert(&#34;You have been hacked!! XD&#34;) &lt;/script&gt;</p> 
  • This does not solve SQL injections, that would be with a different package but the example shows how the library could help us with a basic example for HTML.

 Share!

 
comments powered by Disqus