1
Fork 0
mirror of https://github.com/jech/galene.git synced 2024-11-09 18:25:58 +01:00

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.
This commit is contained in:
Juliusz Chroboczek 2024-01-11 21:13:25 +01:00
parent 9f3bee8e37
commit 03038eaf45
2 changed files with 86 additions and 4 deletions

View file

@ -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")
}
}

View file

@ -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) {
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) {
} }
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) {
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) {
} }
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