mirror of
https://github.com/boringproxy/boringproxy.git
synced 2025-02-25 18:55:29 -06:00
Fix more security holes
This commit is contained in:
parent
3a705cf252
commit
4fd830167f
84
api.go
84
api.go
@ -83,6 +83,18 @@ func (a *Api) CreateTunnel(tokenData TokenData, params url.Values) (*Tunnel, err
|
|||||||
return nil, errors.New("Invalid domain parameter")
|
return nil, errors.New("Invalid domain parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
owner := params.Get("owner")
|
||||||
|
if owner == "" {
|
||||||
|
return nil, errors.New("Invalid owner parameter")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tokenData.Owner != owner {
|
||||||
|
user, _ := a.db.GetUser(tokenData.Owner)
|
||||||
|
if !user.IsAdmin {
|
||||||
|
return nil, errors.New("Unauthorized")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sshKeyId := params.Get("ssh-key-id")
|
sshKeyId := params.Get("ssh-key-id")
|
||||||
|
|
||||||
var sshKey SshKey
|
var sshKey SshKey
|
||||||
@ -263,73 +275,25 @@ func (a *Api) handleTunnels(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Write([]byte(body))
|
w.Write([]byte(body))
|
||||||
case "POST":
|
case "POST":
|
||||||
a.handleCreateTunnel(w, r)
|
r.ParseForm()
|
||||||
|
_, err := a.CreateTunnel(tokenData, r.Form)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
}
|
||||||
case "DELETE":
|
case "DELETE":
|
||||||
a.handleDeleteTunnel(w, r)
|
r.ParseForm()
|
||||||
|
err := a.DeleteTunnel(tokenData, r.Form)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(405)
|
w.WriteHeader(405)
|
||||||
w.Write([]byte("Invalid method for /tunnels"))
|
w.Write([]byte("Invalid method for /tunnels"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Api) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
|
|
||||||
query := r.URL.Query()
|
|
||||||
|
|
||||||
if len(query["domain"]) != 1 {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
w.Write([]byte("Invalid domain parameter"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
domain := query["domain"][0]
|
|
||||||
|
|
||||||
if len(query["owner"]) != 1 {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
w.Write([]byte("Invalid owner parameter"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
owner := query["owner"][0]
|
|
||||||
|
|
||||||
request := Tunnel{
|
|
||||||
Domain: domain,
|
|
||||||
Owner: owner,
|
|
||||||
}
|
|
||||||
|
|
||||||
tunnel, err := a.tunMan.RequestCreateTunnel(request)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
io.WriteString(w, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tunnelJson, err := json.MarshalIndent(tunnel, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(500)
|
|
||||||
io.WriteString(w, "Error encoding tunnel")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write(tunnelJson)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Api) handleDeleteTunnel(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
query := r.URL.Query()
|
|
||||||
|
|
||||||
if len(query["domain"]) != 1 {
|
|
||||||
w.WriteHeader(400)
|
|
||||||
w.Write([]byte("Invalid domain parameter"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
domain := query["domain"][0]
|
|
||||||
|
|
||||||
err := a.tunMan.DeleteTunnel(domain)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(500)
|
|
||||||
io.WriteString(w, "Failed to delete tunnel")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Api) GetSshKeys(tokenData TokenData) map[string]SshKey {
|
func (a *Api) GetSshKeys(tokenData TokenData) map[string]SshKey {
|
||||||
|
|
||||||
user, _ := a.db.GetUser(tokenData.Owner)
|
user, _ := a.db.GetUser(tokenData.Owner)
|
||||||
|
@ -85,6 +85,9 @@ func (c *BoringProxyClient) RunPuppetClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *BoringProxyClient) PollTunnels() error {
|
func (c *BoringProxyClient) PollTunnels() error {
|
||||||
|
|
||||||
|
log.Println("PollTunnels")
|
||||||
|
|
||||||
url := fmt.Sprintf("https://%s/api/tunnels?client-name=%s", c.server, c.clientName)
|
url := fmt.Sprintf("https://%s/api/tunnels?client-name=%s", c.server, c.clientName)
|
||||||
|
|
||||||
listenReq, err := http.NewRequest("GET", url, nil)
|
listenReq, err := http.NewRequest("GET", url, nil)
|
||||||
@ -128,7 +131,7 @@ func (c *BoringProxyClient) PollTunnels() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *BoringProxyClient) SyncTunnels(serverTunnels map[string]Tunnel) {
|
func (c *BoringProxyClient) SyncTunnels(serverTunnels map[string]Tunnel) {
|
||||||
fmt.Println("SyncTunnels")
|
log.Println("SyncTunnels")
|
||||||
|
|
||||||
// update tunnels to match server
|
// update tunnels to match server
|
||||||
for k, newTun := range serverTunnels {
|
for k, newTun := range serverTunnels {
|
||||||
@ -174,6 +177,8 @@ func (c *BoringProxyClient) SyncTunnels(serverTunnels map[string]Tunnel) {
|
|||||||
|
|
||||||
func (c *BoringProxyClient) BoreTunnel(tunnel Tunnel) context.CancelFunc {
|
func (c *BoringProxyClient) BoreTunnel(tunnel Tunnel) context.CancelFunc {
|
||||||
|
|
||||||
|
log.Println("BoreTunnel", tunnel.Domain)
|
||||||
|
|
||||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
5
todo.md
5
todo.md
@ -1,6 +1,5 @@
|
|||||||
# 31 Oct 2020 Launch List
|
# 31 Oct 2020 Launch List
|
||||||
|
|
||||||
- [ ] General security review.
|
|
||||||
- [ ] Invalid database is wiping out tunnels
|
- [ ] Invalid database is wiping out tunnels
|
||||||
- [ ] Improve SSH key download UI.
|
- [ ] Improve SSH key download UI.
|
||||||
- [ ] Improve token list UI.
|
- [ ] Improve token list UI.
|
||||||
@ -12,6 +11,10 @@
|
|||||||
- [x] Head can be rendered before h.headHtml is ever set, ie if login page is visited before any other page
|
- [x] Head can be rendered before h.headHtml is ever set, ie if login page is visited before any other page
|
||||||
- [x] Responses to unauthorized requests are leaking information about the current tunnels through the generated CSS.
|
- [x] Responses to unauthorized requests are leaking information about the current tunnels through the generated CSS.
|
||||||
- [x] I think it's possible to create tokens for arbitrary user, even if you're not that user.
|
- [x] I think it's possible to create tokens for arbitrary user, even if you're not that user.
|
||||||
|
- [x] Anyone can delete tunnels
|
||||||
|
- [x] Anyone can delete tokens
|
||||||
|
- [x] QR codes for admin are broken
|
||||||
|
- [x] General security review.
|
||||||
|
|
||||||
|
|
||||||
# Eventually
|
# Eventually
|
||||||
|
@ -212,6 +212,7 @@ func (h *WebUiHandler) handleWebUiRequest(w http.ResponseWriter, r *http.Request
|
|||||||
var tokens map[string]TokenData
|
var tokens map[string]TokenData
|
||||||
var users map[string]User
|
var users map[string]User
|
||||||
|
|
||||||
|
// TODO: handle security checks in api
|
||||||
if user.IsAdmin {
|
if user.IsAdmin {
|
||||||
tokens = h.db.GetTokens()
|
tokens = h.db.GetTokens()
|
||||||
users = h.db.GetUsers()
|
users = h.db.GetUsers()
|
||||||
|
@ -87,6 +87,7 @@
|
|||||||
<div class='input'>
|
<div class='input'>
|
||||||
<label for="domain">Domain:</label>
|
<label for="domain">Domain:</label>
|
||||||
<input type="text" id="domain" name="domain" required>
|
<input type="text" id="domain" name="domain" required>
|
||||||
|
<input type="hidden" id="tunnel-owner" name="owner" value="{{$.UserId}}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
Loading…
Reference in New Issue
Block a user