Golang中net/http包使用问题(已解决)

Golang中net/http包使用问题(已解决) 我发现以下代码按预期工作:

http.HandleFunc("/@",startHandler)

然而,如果我将 @ 替换为 #,我会得到服务器账户的目录列表。

我认为这可能是一个安全问题。

毫无疑问,这对某些人来说非常有用。

14 回复

这不是一个 sscce。

更多关于Golang中net/http包使用问题(已解决)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我可以轻松地自签名用于本地测试。

问题出现在我重定向到HTTPS时,除非您拥有证书和密钥,否则可能无法进行测试…

浏览器不会将 # 及其后的任何内容提交到服务器。之后你的服务器如何处理 / 是你的路由细节。

Go 语言方面不存在安全问题。

请提供一个最小、完整、可验证的示例,我怀疑这是Go语言的问题,而是与你的反向代理设置有关…

将你的处理器设置为 /@ 并发送请求 /,你看到索引了吗?

请同时提供一个我们可以本地编译和运行以验证你观察结果的 sscce

我为此道歉,因为这是在从 HTTP 重定向到 HTTPS 的过程中发生的,而不是在 WebSocket 启动时,所以可能不存在安全漏洞。但这仍然不应该发生。

以下代码片段可能有助于您重现该问题:

func redirectToHttps(w http.ResponseWriter, r *http.Request) {
    http.Redirect(w, r, "https://xxxxxxxxxxxx.com:"+cfg.PortS+"/#", 307) // 临时用于测试
}

如果黑客能够获取基于Go net/http的服务器目录列表,那么这就是一个安全漏洞。

仅仅依赖客户端协议永不发送特定字符串是不够的。黑客发送一个被禁止的字符串,不应从服务器端获得目录列表作为“回报”。维护net/http的人员应该调查此事,因为其他序列可能被以更恶意的方式利用。

我非常清楚HTTP路由的工作原理。我使用/start来启动WebSocket通信,并决定尝试/#。正如我所说,/@完全能满足我的需求。

我认为net/http处理/#的方式并不令人满意。

感谢您的回复。

我的客户端是 Firefox 68.5.0 ESR。网页正常显示后,会像通常的 WebSocket 一样向服务器发送 WebSocket 响应。我碰巧发送了一个 '/'#’,结果惊讶地发现 Firefox 显示了一个目录列表。这是由 net/http 内部处理的,我的处理程序(负责设置 WebSocket 的服务端)根本没有触及它。

这显然是一个后门。黑客可以轻易伪装成浏览器,从而获取我服务器的目录列表,我认为这是不可取的。黑客对我的主机了解得越少越好。

此致, Bill

感谢您的帮助。

您说得对,# 被忽略了,所以一个 '/' 被传递给了处理器。

这是由 http.FileServer 处理的,它从 serverRoot/css 提供 CSS 文件,并从 serverRoot 提供网站图标。最好将它们放在一个公共目录中。

因此,文件服务器应该这样启动:

fileServer:=http.FileServer(http.Dir("./public"))
http.Handle("/",fileServer)

所以 net/http 完全按照我的要求执行了。

感谢您的帮助和耐心。

对我来说,这段代码按预期工作,Go 返回了一个 404 错误:

package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/#", f)
	err := http.ListenAndServe(":8080", nil)
	panic(err)
}

func f(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "http://example.com/", 307)
}
$ curl localhost:8080/#
404 page not found

如果你能基于这段代码复现你的问题,请回复告知。

再次强调,浏览器不会发送 /#,浏览器不会发送“锚点”。浏览器发送的是 /,至于服务器、反向代理以及其他组件如何响应,这取决于它们的配置。

你的 /# 处理器不会被 / 请求触发。

WebSocket 与此无关。

// 代码示例:一个简单的HTTP请求处理器
package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path)
    })

    http.ListenAndServe(":8080", nil)
}

再补充一些代码

func main(){
go func (){
http.HandleFunc("/#",startHandler)
var err error
err=http.ListenAndServeTLS(":"+cfg.PortS,“chain.pem”,“key.pem”,nil)
time.Sleep(75*time.Millisecond)
if err!=nil{ml.LogFail(fmt.Sprint(err)) }
ml.Log(“HTTPS server has shutdown”)
os.Exit(2)
}()

    go func (){
        http.ListenAndServe(":"+cfg.Port, http.HandlerFunc(redirectToHttps))
        ml.Log("MIPS HTTP server has shutdown")}()

}
fune redirectToHttps(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, “https://xxxxxxxxxxxx.com:”+cfg.PortS+"/#", 307)        // temporary for testing
}

希望这些能有所帮助

这是一个正确的观察。在Go的net/http包中,#字符在路由模式中有特殊含义。当使用http.HandleFunc()时,模式中的#会被视为锚点标记,导致路由无法正确匹配,从而回退到文件服务器行为(如果配置了的话)。

问题分析:

  1. @是普通字符,在路由模式中没有特殊含义
  2. #在URL中通常表示片段标识符(fragment),浏览器不会将其发送到服务器
  3. net/http包的路由模式解析对#有特殊处理

示例代码说明:

package main

import (
    "fmt"
    "net/http"
)

func startHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Handler called for path: %s", r.URL.Path)
}

func main() {
    // 这个可以正常工作
    http.HandleFunc("/@", startHandler)
    
    // 这个可能不会按预期工作
    http.HandleFunc("/#", startHandler)  // #会被特殊处理
    
    // 安全建议:避免在路由中使用特殊字符
    // 如果需要处理特殊字符,可以使用更灵活的路由器
    http.HandleFunc("/hash/", func(w http.ResponseWriter, r *http.Request) {
        // 手动解析路径
        if r.URL.Path == "/hash/#" {
            startHandler(w, r)
        }
    })
    
    http.ListenAndServe(":8080", nil)
}

替代方案:

如果确实需要处理包含#的路径,可以考虑以下方法:

// 方法1:使用URL编码
http.HandleFunc("/%23", startHandler)  // %23是#的URL编码

// 方法2:使用第三方路由器(如gorilla/mux)
import "github.com/gorilla/mux"

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/#", startHandler)  // gorilla/mux能正确处理
    http.ListenAndServe(":8080", r)
}

// 方法3:自定义处理器
type customHandler struct{}

func (h *customHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path == "/#" {
        startHandler(w, r)
        return
    }
    http.NotFound(w, r)
}

func main() {
    http.Handle("/", &customHandler{})
    http.ListenAndServe(":8080", nil)
}

安全注意事项:

  1. 避免在路由模式中使用特殊字符
  2. 始终对用户输入进行验证和清理
  3. 考虑使用成熟的第三方路由库来处理复杂路由需求
  4. 确保文件服务器配置正确,避免目录遍历攻击

这个行为不是安全漏洞,而是HTTP规范和路由设计的特性。正确配置服务器和谨慎处理用户输入可以避免相关问题。

回到顶部