mirror of
https://github.com/datarhei/core.git
synced 2025-10-19 22:34:43 +08:00
Fix proper check of allowed remote values in session token
This commit is contained in:
@@ -2,6 +2,7 @@ package session
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -87,45 +88,11 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
|
|||||||
req := c.Request()
|
req := c.Request()
|
||||||
|
|
||||||
path := req.URL.Path
|
path := req.URL.Path
|
||||||
|
referrer := req.Header.Get("Referer")
|
||||||
|
|
||||||
data := map[string]interface{}{}
|
data, err := verifySession(util.DefaultContext[interface{}](c, "session", nil), path, referrer)
|
||||||
|
if err != nil {
|
||||||
e := util.DefaultContext[interface{}](c, "session", nil)
|
return api.Err(http.StatusForbidden, "", "invalid session data")
|
||||||
if e != nil {
|
|
||||||
var ok bool
|
|
||||||
data, ok = e.(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
return api.Err(http.StatusForbidden, "", "invalid session data")
|
|
||||||
}
|
|
||||||
|
|
||||||
if match, ok := data["match"].(string); ok {
|
|
||||||
if ok, err := glob.Match(match, path, '/'); !ok {
|
|
||||||
if err != nil {
|
|
||||||
return api.Err(http.StatusForbidden, "", "no match for '%s' in %s: %s", match, path, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return api.Err(http.StatusForbidden, "", "no match for '%s' in %s", match, path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
referrer := req.Header.Get("Referer")
|
|
||||||
if u, err := url.Parse(referrer); err == nil {
|
|
||||||
referrer = u.Host
|
|
||||||
}
|
|
||||||
|
|
||||||
if remote, ok := data["remote"].([]string); ok && len(remote) != 0 {
|
|
||||||
match := false
|
|
||||||
for _, r := range remote {
|
|
||||||
if ok, _ := glob.Match(r, referrer, '.'); ok {
|
|
||||||
match = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !match {
|
|
||||||
return api.Err(http.StatusForbidden, "", "remote not allowed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data["name"] = ctxuser
|
data["name"] = ctxuser
|
||||||
@@ -148,6 +115,64 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func verifySession(raw interface{}, path, referrer string) (map[string]interface{}, error) {
|
||||||
|
data := map[string]interface{}{}
|
||||||
|
|
||||||
|
if raw == nil {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
data, ok = raw.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return data, fmt.Errorf("invalid session data")
|
||||||
|
}
|
||||||
|
|
||||||
|
if match, ok := data["match"].(string); ok {
|
||||||
|
if ok, err := glob.Match(match, path, '/'); !ok {
|
||||||
|
if err != nil {
|
||||||
|
return data, fmt.Errorf("no match for '%s' in %s: %s", match, path, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, fmt.Errorf("no match for '%s' in %s", match, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if u, err := url.Parse(referrer); err == nil {
|
||||||
|
referrer = u.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
if remote, ok := data["remote"].([]interface{}); ok && len(remote) != 0 {
|
||||||
|
if len(referrer) == 0 {
|
||||||
|
return data, fmt.Errorf("remote not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
remotes := []string{}
|
||||||
|
for _, r := range remote {
|
||||||
|
v, ok := r.(string)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
remotes = append(remotes, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
match := false
|
||||||
|
for _, r := range remotes {
|
||||||
|
if ok, _ := glob.Match(r, referrer, '.'); ok {
|
||||||
|
match = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !match {
|
||||||
|
return data, fmt.Errorf("remote not allowed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
func headerSize(header http.Header) int64 {
|
func headerSize(header http.Header) int64 {
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
135
http/middleware/session/session_test.go
Normal file
135
http/middleware/session/session_test.go
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVerifySession(t *testing.T) {
|
||||||
|
jsondata := []byte(`{
|
||||||
|
"match": "/memfs/6faad99a-c440-4df1-9344-963869718d8d/**",
|
||||||
|
"remote": [
|
||||||
|
"foo.example.com"
|
||||||
|
]
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var rawdata interface{}
|
||||||
|
|
||||||
|
err := json.Unmarshal(jsondata, &rawdata)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://foo.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://bar.example.com")
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-0000-963869718d8d/main.m3u8", "http://foo.example.com")
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "")
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifySessionNoRemote(t *testing.T) {
|
||||||
|
jsondata := []byte(`{
|
||||||
|
"match": "/memfs/6faad99a-c440-4df1-9344-963869718d8d/**",
|
||||||
|
"remote": []
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var rawdata interface{}
|
||||||
|
|
||||||
|
err := json.Unmarshal(jsondata, &rawdata)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://cm.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
jsondata = []byte(`{
|
||||||
|
"match": "/memfs/6faad99a-c440-4df1-9344-963869718d8d/**"
|
||||||
|
}`)
|
||||||
|
|
||||||
|
err = json.Unmarshal(jsondata, &rawdata)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://cm.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifySessionWildcardRemote(t *testing.T) {
|
||||||
|
jsondata := []byte(`{
|
||||||
|
"match": "/memfs/6faad99a-c440-4df1-9344-963869718d8d/**",
|
||||||
|
"remote": [
|
||||||
|
"*.example.com"
|
||||||
|
]
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var rawdata interface{}
|
||||||
|
|
||||||
|
err := json.Unmarshal(jsondata, &rawdata)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://foo.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://bar.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://sub.bar.example.com")
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifySessionSuperWildcardRemote(t *testing.T) {
|
||||||
|
jsondata := []byte(`{
|
||||||
|
"match": "/memfs/6faad99a-c440-4df1-9344-963869718d8d/**",
|
||||||
|
"remote": [
|
||||||
|
"**.example.com"
|
||||||
|
]
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var rawdata interface{}
|
||||||
|
|
||||||
|
err := json.Unmarshal(jsondata, &rawdata)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://foo.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://bar.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://sub.bar.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifySessionMultipleRemote(t *testing.T) {
|
||||||
|
jsondata := []byte(`{
|
||||||
|
"match": "/memfs/6faad99a-c440-4df1-9344-963869718d8d/**",
|
||||||
|
"remote": [
|
||||||
|
"foo.example.com",
|
||||||
|
"bar.otherdomain.com"
|
||||||
|
]
|
||||||
|
}`)
|
||||||
|
|
||||||
|
var rawdata interface{}
|
||||||
|
|
||||||
|
err := json.Unmarshal(jsondata, &rawdata)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://foo.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://bar.otherdomain.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = verifySession(rawdata, "/memfs/6faad99a-c440-4df1-9344-963869718d8d/main.m3u8", "http://bar.example.com")
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
Reference in New Issue
Block a user