github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/common/protocolstate/headless.go (about) 1 package protocolstate 2 3 import ( 4 "strings" 5 6 "github.com/go-rod/rod" 7 "github.com/go-rod/rod/lib/proto" 8 "github.com/projectdiscovery/networkpolicy" 9 errorutil "github.com/projectdiscovery/utils/errors" 10 stringsutil "github.com/projectdiscovery/utils/strings" 11 urlutil "github.com/projectdiscovery/utils/url" 12 "go.uber.org/multierr" 13 ) 14 15 // initalize state of headless protocol 16 17 var ( 18 ErrURLDenied = errorutil.NewWithFmt("headless: url %v dropped by rule: %v") 19 networkPolicy *networkpolicy.NetworkPolicy 20 allowLocalFileAccess bool 21 ) 22 23 // ValidateNFailRequest validates and fails request 24 // if the request does not respect the rules, it will be canceled with reason 25 func ValidateNFailRequest(page *rod.Page, e *proto.FetchRequestPaused) error { 26 reqURL := e.Request.URL 27 normalized := strings.ToLower(reqURL) // normalize url to lowercase 28 normalized = strings.TrimSpace(normalized) // trim leading & trailing whitespaces 29 if !allowLocalFileAccess && stringsutil.HasPrefixI(normalized, "file:") { 30 return multierr.Combine(FailWithReason(page, e), ErrURLDenied.Msgf(reqURL, "use of file:// protocol disabled use '-lfa' to enable")) 31 } 32 // validate potential invalid schemes 33 // javascript protocol is allowed for xss fuzzing 34 if stringsutil.HasPrefixAnyI(normalized, "ftp:", "externalfile:", "chrome:", "chrome-extension:") { 35 return multierr.Combine(FailWithReason(page, e), ErrURLDenied.Msgf(reqURL, "protocol blocked by network policy")) 36 } 37 if !isValidHost(reqURL) { 38 return multierr.Combine(FailWithReason(page, e), ErrURLDenied.Msgf(reqURL, "address blocked by network policy")) 39 } 40 return nil 41 } 42 43 // FailWithReason fails request with AccessDenied reason 44 func FailWithReason(page *rod.Page, e *proto.FetchRequestPaused) error { 45 m := proto.FetchFailRequest{ 46 RequestID: e.RequestID, 47 ErrorReason: proto.NetworkErrorReasonAccessDenied, 48 } 49 return m.Call(page) 50 } 51 52 // InitHeadless initializes headless protocol state 53 func InitHeadless(RestrictLocalNetworkAccess bool, localFileAccess bool) { 54 allowLocalFileAccess = localFileAccess 55 if !RestrictLocalNetworkAccess { 56 return 57 } 58 networkPolicy, _ = networkpolicy.New(networkpolicy.Options{ 59 DenyList: append(networkpolicy.DefaultIPv4DenylistRanges, networkpolicy.DefaultIPv6DenylistRanges...), 60 }) 61 } 62 63 // isValidHost checks if the host is valid (only limited to http/https protocols) 64 func isValidHost(targetUrl string) bool { 65 if !stringsutil.HasPrefixAny(targetUrl, "http:", "https:") { 66 return true 67 } 68 if networkPolicy == nil { 69 return true 70 } 71 urlx, err := urlutil.Parse(targetUrl) 72 if err != nil { 73 // not a valid url 74 return false 75 } 76 targetUrl = urlx.Hostname() 77 _, ok := networkPolicy.ValidateHost(targetUrl) 78 return ok 79 }