fix(lib): block XSS attacks via nonstandard URLs (#904)
* fix(lib): block XSS attacks via nonstandard URLs This could allow an attacker to craft an Anubis pass-challenge URL that forces a redirect to nonstandard URLs, such as the `javascript:` scheme which executes arbitrary JavaScript code in a browser context when the user clicks the "Try again" button. Release-status: cut Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: spelling Signed-off-by: Xe Iaso <me@xeiaso.net> --------- Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
parent
21f570962c
commit
d40e9056bc
5 changed files with 98 additions and 1 deletions
|
|
@ -801,3 +801,79 @@ func TestChallengeFor_ErrNotFound(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPassChallengeXSS(t *testing.T) {
|
||||
pol := loadPolicies(t, "", anubis.DefaultDifficulty)
|
||||
|
||||
srv := spawnAnubis(t, Options{
|
||||
Next: http.NewServeMux(),
|
||||
Policy: pol,
|
||||
})
|
||||
|
||||
ts := httptest.NewServer(internal.RemoteXRealIP(true, "tcp", srv))
|
||||
defer ts.Close()
|
||||
|
||||
cli := httpClient(t)
|
||||
chall := makeChallenge(t, ts, cli)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
redir string
|
||||
}{
|
||||
{
|
||||
name: "javascript alert",
|
||||
redir: "javascript:alert('xss')",
|
||||
},
|
||||
{
|
||||
name: "vbscript",
|
||||
redir: "vbscript:msgbox(\"XSS\")",
|
||||
},
|
||||
{
|
||||
name: "data url",
|
||||
redir: "data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
nonce := 0
|
||||
elapsedTime := 420
|
||||
calculated := ""
|
||||
calcString := fmt.Sprintf("%s%d", chall.Challenge, nonce)
|
||||
calculated = internal.SHA256sum(calcString)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, ts.URL+"/.within.website/x/cmd/anubis/api/pass-challenge", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("can't make request: %v", err)
|
||||
}
|
||||
|
||||
q := req.URL.Query()
|
||||
q.Set("response", calculated)
|
||||
q.Set("nonce", fmt.Sprint(nonce))
|
||||
q.Set("redir", tc.redir)
|
||||
q.Set("elapsedTime", fmt.Sprint(elapsedTime))
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
u, err := url.Parse(ts.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, ckie := range cli.Jar.Cookies(u) {
|
||||
if ckie.Name == anubis.TestCookieName {
|
||||
req.AddCookie(ckie)
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := cli.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("can't do request: %v", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusBadRequest {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
t.Errorf("wanted status %d, got %d. body: %s", http.StatusBadRequest, resp.StatusCode, body)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue