Unverified Commit be8c0bd9 authored by Steven Allen's avatar Steven Allen Committed by GitHub

Merge pull request #193 from ipfs/fix/disallow-agent

Fix: disallow POST without Origin nor Referer from specific user agents
parents f2a4f7be b00bc407
......@@ -3,6 +3,7 @@ package http
import (
"net/http"
"net/url"
"strings"
"sync"
cors "github.com/rs/cors"
......@@ -150,3 +151,34 @@ func allowReferer(r *http.Request, cfg *ServerConfig) bool {
return false
}
// allowUserAgent checks the request's user-agent against the list
// of DisallowUserAgents for requests with no origin nor referer set.
func allowUserAgent(r *http.Request, cfg *ServerConfig) bool {
// This check affects POST as we should never get POST requests from a
// browser without Origin or Referer, but we might:
// https://bugzilla.mozilla.org/show_bug.cgi?id=429594.
if r.Method != http.MethodPost {
return true
}
origin := r.Header.Get("Origin")
referer := r.Referer()
// If these are set, we leave up to CORS and CSRF checks.
if origin != "" || referer != "" {
return true
}
// Allow if the user agent does not start with Mozilla... (i.e. curl)
ua := r.Header.Get("User-agent")
if !strings.HasPrefix(ua, "Mozilla") {
return true
}
// Disallow otherwise.
//
// This means the request probably came from a browser and thus, it
// should have included Origin or referer headers.
return false
}
......@@ -170,3 +170,42 @@ func TestUnhandledMethod(t *testing.T) {
}
tc.test(t)
}
func TestDisallowedUserAgents(t *testing.T) {
tcs := []httpTestCase{
{
// Block Mozilla* browsers that do not provide origins.
Method: "POST",
AllowGet: false,
Code: http.StatusForbidden,
ReqHeaders: map[string]string{
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0",
},
},
{
// Do not block on GETs
Method: "GET",
AllowGet: true,
Code: http.StatusOK,
ReqHeaders: map[string]string{
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0",
},
},
{
// Do not block a Mozilla* browser that provides an
// allowed Origin
Method: "POST",
AllowGet: false,
AllowOrigins: []string{"*"},
Origin: "null",
Code: http.StatusOK,
ReqHeaders: map[string]string{
"User-Agent": "Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; Build/KLP) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30",
},
},
}
for _, tc := range tcs {
tc.test(t)
}
}
......@@ -121,7 +121,7 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
if !allowOrigin(r, h.cfg) || !allowReferer(r, h.cfg) {
if !allowOrigin(r, h.cfg) || !allowReferer(r, h.cfg) || !allowUserAgent(r, h.cfg) {
http.Error(w, "403 - Forbidden", http.StatusForbidden)
log.Warnf("API blocked request to %s. (possible CSRF)", r.URL)
return
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment