mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
fix: harden address parsing edge cases
This commit is contained in:
@@ -374,15 +374,17 @@ func optimizeCookies(rawCookie string) string {
|
||||
var output strings.Builder
|
||||
|
||||
// 解析Cookie键值对
|
||||
pairs := strings.Split(rawCookie, "; ")
|
||||
pairs := strings.Split(rawCookie, ";")
|
||||
for _, pair := range pairs {
|
||||
pair = strings.TrimSpace(pair)
|
||||
nameVal := strings.SplitN(pair, "=", 2)
|
||||
if len(nameVal) < 2 {
|
||||
continue
|
||||
}
|
||||
name := strings.TrimSpace(nameVal[0])
|
||||
|
||||
// 跳过Cookie属性
|
||||
switch strings.ToLower(nameVal[0]) {
|
||||
switch strings.ToLower(name) {
|
||||
case "expires", "max-age", "path", "domain",
|
||||
"version", "comment", "secure", "samesite", "httponly":
|
||||
continue
|
||||
@@ -392,9 +394,9 @@ func optimizeCookies(rawCookie string) string {
|
||||
if output.Len() > 0 {
|
||||
output.WriteString("; ")
|
||||
}
|
||||
output.WriteString(nameVal[0])
|
||||
output.WriteString(name)
|
||||
output.WriteString("=")
|
||||
output.WriteString(strings.Join(nameVal[1:], "="))
|
||||
output.WriteString(nameVal[1])
|
||||
}
|
||||
|
||||
return output.String()
|
||||
|
||||
@@ -181,6 +181,16 @@ func TestOptimizeCookies(t *testing.T) {
|
||||
raw: "sid=simple",
|
||||
want: "sid=simple",
|
||||
},
|
||||
{
|
||||
name: "分号后无空格",
|
||||
raw: "token=xyz;user=admin;Path=/app;HttpOnly",
|
||||
want: "token=xyz; user=admin",
|
||||
},
|
||||
{
|
||||
name: "键名周围空格",
|
||||
raw: " token =xyz; user =admin; Path =/",
|
||||
want: "token=xyz; user=admin",
|
||||
},
|
||||
{
|
||||
name: "空字符串",
|
||||
raw: "",
|
||||
|
||||
+3
-1
@@ -5,6 +5,7 @@ import (
|
||||
"embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -104,7 +105,7 @@ func WebScan(ctx context.Context, info *common.HostInfo, cfg *common.Config) {
|
||||
func buildTargetURL(info *common.HostInfo) (string, error) {
|
||||
// 自动构建URL
|
||||
if info.URL == "" {
|
||||
info.URL = fmt.Sprintf("%s%s:%d", protocolHTTP, info.Host, info.Port)
|
||||
info.URL = protocolHTTP + net.JoinHostPort(info.Host, fmt.Sprint(info.Port))
|
||||
} else if !hasProtocolPrefix(info.URL) {
|
||||
info.URL = protocolHTTP + info.URL
|
||||
}
|
||||
@@ -120,6 +121,7 @@ func buildTargetURL(info *common.HostInfo) (string, error) {
|
||||
|
||||
// hasProtocolPrefix 检查URL是否包含协议前缀
|
||||
func hasProtocolPrefix(urlStr string) bool {
|
||||
urlStr = strings.ToLower(urlStr)
|
||||
return strings.HasPrefix(urlStr, protocolHTTP) || strings.HasPrefix(urlStr, protocolHTTPS)
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +114,26 @@ func TestBuildTargetURL(t *testing.T) {
|
||||
expected: "http://test.example.com:9090",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "ipv6 builds bracketed host and port",
|
||||
hostInfo: &common.HostInfo{
|
||||
Host: "2001:db8::1",
|
||||
Port: 8080,
|
||||
URL: "",
|
||||
},
|
||||
expected: "http://[2001:db8::1]:8080",
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "ipv6 url without protocol keeps brackets",
|
||||
hostInfo: &common.HostInfo{
|
||||
Host: "2001:db8::1",
|
||||
Port: 443,
|
||||
URL: "[2001:db8::1]:443/admin",
|
||||
},
|
||||
expected: "http://[2001:db8::1]:443",
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -190,8 +210,8 @@ func TestHasProtocolPrefix(t *testing.T) {
|
||||
{"only http", "http://", true},
|
||||
{"only https", "https://", true},
|
||||
{"http in middle", "example.http://com", false},
|
||||
{"uppercase HTTP", "HTTP://example.com", false}, // 区分大小写
|
||||
{"uppercase HTTPS", "HTTPS://example.com", false},
|
||||
{"uppercase HTTP", "HTTP://example.com", true},
|
||||
{"uppercase HTTPS", "HTTPS://example.com", true},
|
||||
{"ftp protocol", "ftp://example.com", false},
|
||||
{"http no slashes", "http:example.com", false},
|
||||
{"partial prefix", "http:/example.com", false},
|
||||
|
||||
Reference in New Issue
Block a user