mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	Merge pull request #823 from kradalby/sanitise-machine-key-url
Protect against user injection for registration CLI page
This commit is contained in:
		
						commit
						d575dac73a
					
				@ -15,6 +15,7 @@
 | 
				
			|||||||
- Give a warning when running Headscale with reverse proxy improperly configured for WebSockets [#788](https://github.com/juanfont/headscale/pull/788)
 | 
					- Give a warning when running Headscale with reverse proxy improperly configured for WebSockets [#788](https://github.com/juanfont/headscale/pull/788)
 | 
				
			||||||
- Fix subnet routers with Primary Routes [#811](https://github.com/juanfont/headscale/pull/811)
 | 
					- Fix subnet routers with Primary Routes [#811](https://github.com/juanfont/headscale/pull/811)
 | 
				
			||||||
- Added support for JSON logs [#653](https://github.com/juanfont/headscale/issues/653)
 | 
					- Added support for JSON logs [#653](https://github.com/juanfont/headscale/issues/653)
 | 
				
			||||||
 | 
					- Sanitise the node key passed to registration url [#823](https://github.com/juanfont/headscale/pull/823)
 | 
				
			||||||
- Add support for generating pre-auth keys with tags [#767](https://github.com/juanfont/headscale/pull/767)
 | 
					- Add support for generating pre-auth keys with tags [#767](https://github.com/juanfont/headscale/pull/767)
 | 
				
			||||||
- Add support for evaluating `autoApprovers` ACL entries when a machine is registered [#763](https://github.com/juanfont/headscale/pull/763)
 | 
					- Add support for evaluating `autoApprovers` ACL entries when a machine is registered [#763](https://github.com/juanfont/headscale/pull/763)
 | 
				
			||||||
- Add config flag to allow Headscale to start if OIDC provider is down [#829](https://github.com/juanfont/headscale/pull/829)
 | 
					- Add config flag to allow Headscale to start if OIDC provider is down [#829](https://github.com/juanfont/headscale/pull/829)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										32
									
								
								api.go
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								api.go
									
									
									
									
									
								
							@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/gorilla/mux"
 | 
						"github.com/gorilla/mux"
 | 
				
			||||||
	"github.com/rs/zerolog/log"
 | 
						"github.com/rs/zerolog/log"
 | 
				
			||||||
 | 
						"tailscale.com/types/key"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
@ -93,7 +94,34 @@ func (h *Headscale) RegisterWebAPI(
 | 
				
			|||||||
) {
 | 
					) {
 | 
				
			||||||
	vars := mux.Vars(req)
 | 
						vars := mux.Vars(req)
 | 
				
			||||||
	nodeKeyStr, ok := vars["nkey"]
 | 
						nodeKeyStr, ok := vars["nkey"]
 | 
				
			||||||
	if !ok || nodeKeyStr == "" {
 | 
					
 | 
				
			||||||
 | 
						if !NodePublicKeyRegex.Match([]byte(nodeKeyStr)) {
 | 
				
			||||||
 | 
							log.Warn().Str("node_key", nodeKeyStr).Msg("Invalid node key passed to registration url")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
 | 
				
			||||||
 | 
							writer.WriteHeader(http.StatusUnauthorized)
 | 
				
			||||||
 | 
							_, err := writer.Write([]byte("Unauthorized"))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Error().
 | 
				
			||||||
 | 
									Caller().
 | 
				
			||||||
 | 
									Err(err).
 | 
				
			||||||
 | 
									Msg("Failed to write response")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// We need to make sure we dont open for XSS style injections, if the parameter that
 | 
				
			||||||
 | 
						// is passed as a key is not parsable/validated as a NodePublic key, then fail to render
 | 
				
			||||||
 | 
						// the template and log an error.
 | 
				
			||||||
 | 
						var nodeKey key.NodePublic
 | 
				
			||||||
 | 
						err := nodeKey.UnmarshalText(
 | 
				
			||||||
 | 
							[]byte(NodePublicKeyEnsurePrefix(nodeKeyStr)),
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !ok || nodeKeyStr == "" || err != nil {
 | 
				
			||||||
 | 
							log.Warn().Err(err).Msg("Failed to parse incoming nodekey")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
 | 
							writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
 | 
				
			||||||
		writer.WriteHeader(http.StatusBadRequest)
 | 
							writer.WriteHeader(http.StatusBadRequest)
 | 
				
			||||||
		_, err := writer.Write([]byte("Wrong params"))
 | 
							_, err := writer.Write([]byte("Wrong params"))
 | 
				
			||||||
@ -130,7 +158,7 @@ func (h *Headscale) RegisterWebAPI(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	writer.Header().Set("Content-Type", "text/html; charset=utf-8")
 | 
						writer.Header().Set("Content-Type", "text/html; charset=utf-8")
 | 
				
			||||||
	writer.WriteHeader(http.StatusOK)
 | 
						writer.WriteHeader(http.StatusOK)
 | 
				
			||||||
	_, err := writer.Write(content.Bytes())
 | 
						_, err = writer.Write(content.Bytes())
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Error().
 | 
							log.Error().
 | 
				
			||||||
			Caller().
 | 
								Caller().
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								utils.go
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								utils.go
									
									
									
									
									
								
							@ -17,6 +17,7 @@ import (
 | 
				
			|||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -64,6 +65,8 @@ const (
 | 
				
			|||||||
	ZstdCompression = "zstd"
 | 
						ZstdCompression = "zstd"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var NodePublicKeyRegex = regexp.MustCompile("nodekey:[a-fA-F0-9]+")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func MachinePublicKeyStripPrefix(machineKey key.MachinePublic) string {
 | 
					func MachinePublicKeyStripPrefix(machineKey key.MachinePublic) string {
 | 
				
			||||||
	return strings.TrimPrefix(machineKey.String(), machinePublicHexPrefix)
 | 
						return strings.TrimPrefix(machineKey.String(), machinePublicHexPrefix)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -325,7 +328,9 @@ func GenerateRandomStringDNSSafe(size int) (string, error) {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return "", err
 | 
								return "", err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		str = strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(str, "_", ""), "-", ""))
 | 
							str = strings.ToLower(
 | 
				
			||||||
 | 
								strings.ReplaceAll(strings.ReplaceAll(str, "_", ""), "-", ""),
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return str[:size], nil
 | 
						return str[:size], nil
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user