Commit 03038eaf authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Obfuscate WHIP ids.

If the WHIP session is not authenticated, then the only thing
preventing an attacker from DELETEing the session is the session
URL.  Since client ids are known, obfuscate the id before using
it in the session URL.
parent 9f3bee8e
...@@ -136,3 +136,23 @@ func TestFormatICEServer(t *testing.T) { ...@@ -136,3 +136,23 @@ func TestFormatICEServer(t *testing.T) {
}) })
} }
} }
func TestObfuscate(t *testing.T) {
id := newId()
obfuscated, err := obfuscate(id)
if err != nil {
t.Fatalf("obfuscate: %v", err)
}
id2, err := deobfuscate(obfuscated)
if err != nil {
t.Fatalf("deobfuscate: %v", err)
}
if id != id2 {
t.Errorf("not equal: %v, %v", id, id2)
}
_, err = obfuscate("toto")
if err == nil {
t.Errorf("obfuscate: no errror")
}
}
...@@ -2,8 +2,11 @@ package webserver ...@@ -2,8 +2,11 @@ package webserver
import ( import (
"bytes" "bytes"
"crypto/aes"
"crypto/cipher"
crand "crypto/rand" crand "crypto/rand"
"encoding/base64" "encoding/base64"
"errors"
"fmt" "fmt"
"io" "io"
"log" "log"
...@@ -37,12 +40,58 @@ func parseWhip(pth string) (string, string) { ...@@ -37,12 +40,58 @@ func parseWhip(pth string) (string, string) {
return "", "" return "", ""
} }
var idSecret []byte
var idCipher cipher.Block
func init() {
idSecret = make([]byte, 16)
_, err := crand.Read(idSecret)
if err != nil {
log.Fatalf("crand.Read: %v", err)
}
idCipher, err = aes.NewCipher(idSecret)
if err != nil {
log.Fatalf("NewCipher: %v", err)
}
}
func newId() string { func newId() string {
b := make([]byte, 16) b := make([]byte, idCipher.BlockSize())
crand.Read(b) crand.Read(b)
return base64.RawURLEncoding.EncodeToString(b) return base64.RawURLEncoding.EncodeToString(b)
} }
// we obfuscate ids to avoid exposing the WHIP session URL
func obfuscate(id string) (string, error) {
v, err := base64.RawURLEncoding.DecodeString(id)
if err != nil {
return "", err
}
if len(v) != idCipher.BlockSize() {
return "", errors.New("bad length")
}
idCipher.Encrypt(v, v)
return base64.RawURLEncoding.EncodeToString(v), nil
}
func deobfuscate(id string) (string, error) {
v, err := base64.RawURLEncoding.DecodeString(id)
if err != nil {
return "", err
}
if len(v) != idCipher.BlockSize() {
return "", errors.New("bad length")
}
idCipher.Decrypt(v, v)
return base64.RawURLEncoding.EncodeToString(v), nil
}
func canPresent(perms []string) bool { func canPresent(perms []string) bool {
for _, p := range perms { for _, p := range perms {
if p == "present" { if p == "present" {
...@@ -186,6 +235,13 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) { ...@@ -186,6 +235,13 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
} }
id := newId() id := newId()
obfuscated, err := obfuscate(id)
if err != nil {
http.Error(w, "Internal Server Error",
http.StatusInternalServerError)
return
}
c := rtpconn.NewWhipClient(g, id, token) c := rtpconn.NewWhipClient(g, id, token)
_, err = group.AddClient(g.Name(), c, creds) _, err = group.AddClient(g.Name(), c, creds)
...@@ -214,7 +270,7 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) { ...@@ -214,7 +270,7 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
http.StatusInternalServerError) http.StatusInternalServerError)
} }
w.Header().Set("Location", path.Join(r.URL.Path, id)) w.Header().Set("Location", path.Join(r.URL.Path, obfuscated))
w.Header().Set("Access-Control-Expose-Headers", w.Header().Set("Access-Control-Expose-Headers",
"Location, Content-Type, Link") "Location, Content-Type, Link")
whipICEServers(w) whipICEServers(w)
...@@ -226,8 +282,14 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) { ...@@ -226,8 +282,14 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
} }
func whipResourceHandler(w http.ResponseWriter, r *http.Request) { func whipResourceHandler(w http.ResponseWriter, r *http.Request) {
pth, id := parseWhip(r.URL.Path) pth, obfuscated := parseWhip(r.URL.Path)
if pth == "" || id == "" { if pth == "" || obfuscated == "" {
http.Error(w, "Internal server error",
http.StatusInternalServerError)
return
}
id, err := deobfuscate(obfuscated)
if err != nil {
http.Error(w, "Internal server error", http.Error(w, "Internal server error",
http.StatusInternalServerError) http.StatusInternalServerError)
return 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