mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
162 lines
4.3 KiB
Go
162 lines
4.3 KiB
Go
package main
|
|
|
|
//go:generate depstubber -vendor github.com/gorilla/websocket Dialer
|
|
//go:generate depstubber -vendor golang.org/x/net/websocket "" Dial,NewConfig,DialConfig
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"net/url"
|
|
"regexp"
|
|
"strings"
|
|
|
|
gorilla "github.com/gorilla/websocket"
|
|
"golang.org/x/net/websocket"
|
|
)
|
|
|
|
func handler(w http.ResponseWriter, req *http.Request) {
|
|
target := req.FormValue("target") // $ Source
|
|
|
|
// BAD: `target` is controlled by the attacker
|
|
_, err := http.Get("https://" + target + ".example.com/data/") // $ Alert
|
|
if err != nil {
|
|
// error handling
|
|
}
|
|
// process request response
|
|
}
|
|
|
|
func handler1(w http.ResponseWriter, req *http.Request) {
|
|
target := req.FormValue("target")
|
|
|
|
var subdomain string
|
|
if target == "EU" {
|
|
subdomain = "europe"
|
|
} else {
|
|
subdomain = "world"
|
|
}
|
|
|
|
// GOOD: `subdomain` is controlled by the server
|
|
_, err := http.Get("https://" + subdomain + ".example.com/data/")
|
|
if err != nil {
|
|
// error handling
|
|
}
|
|
// process request response
|
|
}
|
|
|
|
func test() {
|
|
|
|
http.HandleFunc("/ex0", func(w http.ResponseWriter, r *http.Request) {
|
|
untrustedInput := r.Referer()
|
|
|
|
origin := "http://localhost/"
|
|
|
|
untrustedInputTrimmed := strings.TrimRight(untrustedInput, "\n\r")
|
|
if untrustedInputTrimmed == "ws://localhost:12345/ws" {
|
|
// good as input is checked against fixed set of urls.
|
|
ws, _ := websocket.Dial(untrustedInputTrimmed, "", origin) // OK
|
|
var msg = make([]byte, 512)
|
|
var n int
|
|
n, _ = ws.Read(msg)
|
|
fmt.Printf("Received: %s.\n", msg[:n])
|
|
}
|
|
})
|
|
|
|
// x net websocket DialConfig good
|
|
http.HandleFunc("/ex1", func(w http.ResponseWriter, r *http.Request) {
|
|
untrustedInput := r.Referer()
|
|
|
|
origin := "http://localhost/"
|
|
// good as input is tested against a regex
|
|
if m, _ := regexp.MatchString("ws://localhost:12345/*", untrustedInput); m {
|
|
config, _ := websocket.NewConfig(untrustedInput, origin) // OK? Regex
|
|
ws2, _ := websocket.DialConfig(config)
|
|
var msg = make([]byte, 512)
|
|
var n int
|
|
n, _ = ws2.Read(msg)
|
|
fmt.Printf("Received: %s.\n", msg[:n])
|
|
}
|
|
})
|
|
|
|
// x net websocket dial bad
|
|
http.HandleFunc("/ex2", func(w http.ResponseWriter, r *http.Request) {
|
|
untrustedInput := r.Referer() // $ Source
|
|
|
|
origin := "http://localhost/"
|
|
|
|
// bad as input is directly passed to dial function
|
|
ws, _ := websocket.Dial(untrustedInput, "", origin) // $ Alert
|
|
var msg = make([]byte, 512)
|
|
var n int
|
|
n, _ = ws.Read(msg)
|
|
fmt.Printf("Received: %s.\n", msg[:n])
|
|
})
|
|
|
|
// x net websocket dialConfig bad
|
|
http.HandleFunc("/ex3", func(w http.ResponseWriter, r *http.Request) {
|
|
untrustedInput := r.Referer() // $ Source
|
|
|
|
origin := "http://localhost/"
|
|
// bad as input is directly used
|
|
config, _ := websocket.NewConfig(untrustedInput, origin) // $ Sink
|
|
ws2, _ := websocket.DialConfig(config) // $ Alert
|
|
var msg = make([]byte, 512)
|
|
var n int
|
|
n, _ = ws2.Read(msg)
|
|
fmt.Printf("Received: %s.\n", msg[:n])
|
|
})
|
|
|
|
// gorilla websocket Dialer.Dial bad
|
|
http.HandleFunc("/ex6", func(w http.ResponseWriter, r *http.Request) {
|
|
untrustedInput := r.Referer() // $ Source
|
|
|
|
dialer := gorilla.Dialer{}
|
|
dialer.Dial(untrustedInput, r.Header) // $ Alert
|
|
})
|
|
|
|
// gorilla websocket Dialer.Dial good
|
|
http.HandleFunc("/ex7", func(w http.ResponseWriter, r *http.Request) {
|
|
untrustedInput := r.Referer()
|
|
|
|
if untrustedInput == "localhost" {
|
|
dialer := gorilla.Dialer{}
|
|
dialer.Dial(untrustedInput, r.Header) //OK
|
|
}
|
|
})
|
|
|
|
// gorilla websocket Dialer.DialContext bad
|
|
http.HandleFunc("/ex8", func(w http.ResponseWriter, r *http.Request) {
|
|
untrustedInput := r.Referer() // $ Source
|
|
|
|
dialer := gorilla.Dialer{}
|
|
dialer.DialContext(context.TODO(), untrustedInput, r.Header) // $ Alert
|
|
})
|
|
|
|
// gorilla websocket Dialer.DialContext good
|
|
http.HandleFunc("/ex9", func(w http.ResponseWriter, r *http.Request) {
|
|
untrustedInput := r.Referer()
|
|
|
|
if untrustedInput == "localhost" {
|
|
dialer := gorilla.Dialer{}
|
|
dialer.DialContext(context.TODO(), untrustedInput, r.Header) //OK
|
|
}
|
|
})
|
|
|
|
log.Println(http.ListenAndServe(":80", nil))
|
|
|
|
}
|
|
|
|
func handler2(w http.ResponseWriter, req *http.Request) {
|
|
unsafehost := req.FormValue("host") // $ Source
|
|
|
|
url, _ := url.Parse("http://example.com/data")
|
|
url.Host = unsafehost
|
|
// BAD: `target` is controlled by the attacker
|
|
_, err := http.Get(url.String()) // $ Alert
|
|
if err != nil {
|
|
// error handling
|
|
}
|
|
// process request response
|
|
}
|