Skip to content

Commit

Permalink
Obfuscate WHIP ids.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jech committed Jan 11, 2024
1 parent 9f3bee8 commit 65fa0be
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 4 deletions.
20 changes: 20 additions & 0 deletions webserver/webserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}
68 changes: 64 additions & 4 deletions webserver/whip.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package webserver

import (
"bytes"
"crypto/aes"
"crypto/cipher"
crand "crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -37,12 +40,56 @@ func parseWhip(pth string) (string, string) {
return "", ""
}

var idSecret []byte
var idCipher cipher.Block

func init() {
idSecret = make([]byte, 16)
crand.Read(idSecret)
var err error
idCipher, err = aes.NewCipher(idSecret)
if err != nil {
log.Fatalf("NewCipher: %v", err)
}
}

func newId() string {
b := make([]byte, 16)
b := make([]byte, idCipher.BlockSize())
crand.Read(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 {
for _, p := range perms {
if p == "present" {
Expand Down Expand Up @@ -186,6 +233,13 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
}

id := newId()
obfuscated, err := obfuscate(id)
if err != nil {
http.Error(w, "Internal Server Error",
http.StatusInternalServerError)
return
}

c := rtpconn.NewWhipClient(g, id, token)

_, err = group.AddClient(g.Name(), c, creds)
Expand Down Expand Up @@ -214,7 +268,7 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
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",
"Location, Content-Type, Link")
whipICEServers(w)
Expand All @@ -226,8 +280,14 @@ func whipEndpointHandler(w http.ResponseWriter, r *http.Request) {
}

func whipResourceHandler(w http.ResponseWriter, r *http.Request) {
pth, id := parseWhip(r.URL.Path)
if pth == "" || id == "" {
pth, obfuscated := parseWhip(r.URL.Path)
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.StatusInternalServerError)
return
Expand Down

0 comments on commit 65fa0be

Please sign in to comment.