XSS - Cross Site Scripting Vulnerability

1 min read Tweet this post

Many developers are aware of Cross Site Scripting (XSS), but few have attempted to use it to exploit a web application. Despite being listed as a top 10 security risk by OWASP since 2003, XSS remains a prevalent vulnerability. The OWASP Top 10 security risks version from 2013 provides a comprehensive overview of XSS, including information on attack vectors, vulnerabilities, and the technical and business impacts of a successful XSS attack.

In short

You are vulnerable if you do not ensure that all user supplied input is properly escaped, or you do not verify it to be safe via server-side input validation, before including that input in the output page. source

package main

import (
	"io"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, r.URL.Query().Get("param1"))
}
func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

As Content-Type HTTP response header is not explicitly defined, Go http.DetectContentType default value will be used, which follows the WhatWG spec. So, the Content-Type HTTP response header will depends on param1 values. If the params1 contains plain text it will return text/plain but if user pass it using html markup it will automatically return text/html.

Here the proove:

 curl -i http://localhost:8000/\?param1\="<script>alert(1)</script>"
HTTP/1.1 200 OK
publishedOn: Tue, 24 Jan 2023 07:48:56 GMT
Content-Length: 25
Content-Type: text/html; charset=utf-8

<script>alert(1)</script>%

 curl -i http://localhost:8000/\?param1\=test
HTTP/1.1 200 OK
publishedOn: Tue, 24 Jan 2023 07:49:10 GMT
Content-Length: 4
Content-Type: text/plain; charset=utf-8

test%

Then, how to fix those problem? Fun fact, even using text/template it won’t help to preventing XSS, since it does not sanitize user input. The correct solution is using html/template

package main

import (
	"html/template"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	param1 := r.URL.Query().Get("param1")
	tmpl := template.New("hello")
	tmpl, _ = tmpl.Parse(`{{define "T"}}{{.}}{{end}}`)
	tmpl.ExecuteTemplate(w, "T", param1)
}
func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8000", nil)
}

Let’s try again using script alert and other html sample.

 curl -i http://localhost:8000/\?param1\="<script>alert(1)</script>"
HTTP/1.1 200 OK
publishedOn: Tue, 24 Jan 2023 07:55:21 GMT
Content-Length: 37
Content-Type: text/plain; charset=utf-8

 curl -i http://localhost:8000/\?param1\="<h1>whassup</h1>"
HTTP/1.1 200 OK
publishedOn: Tue, 24 Jan 2023 08:01:56 GMT
Content-Length: 28
Content-Type: text/plain; charset=utf-8

&lt;h1&gt;whassup&lt;/h1&gt;%

Yes, the output properly encoded and sanitized. So using html/template can prevent xss attack, keep in mind when processing input from user please sanitize first and make sure not trigger script execution that lead to XSS attack.

go security