XSS - Cross Site Scripting Vulnerability
January 24, 2023
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 (opens in a new tab)
package mainimport ( "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 (opens in a new tab) 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 OKDate: Tue, 24 Jan 2023 07:48:56 GMTContent-Length: 25Content-Type: text/html; charset=utf-8<script>alert(1)</script>% ❯ curl -i http://localhost:8000/\?param1\=test HTTP/1.1 200 OKDate: Tue, 24 Jan 2023 07:49:10 GMTContent-Length: 4Content-Type: text/plain; charset=utf-8test%
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 mainimport ( "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 OKDate: Tue, 24 Jan 2023 07:55:21 GMTContent-Length: 37Content-Type: text/plain; charset=utf-8❯ curl -i http://localhost:8000/\?param1\="<h1>whassup</h1>" HTTP/1.1 200 OKDate: Tue, 24 Jan 2023 08:01:56 GMTContent-Length: 28Content-Type: text/plain; charset=utf-8<h1>whassup</h1>%
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.