minio 从头编译(增加web api 跨域安全性 )

遇到个问题安全检查出来minio的9000端口有CORS(跨站资源共享)原始验证失败问题和不安全的crossdomain.xml文件问题,这边找了网上的配置多次尝试无果,找到一个方案,直接编译源码,修改相关逻辑就ok,我这边测试验证没问题。

因为这个项目是go语言写的,顺便学了一下go,目前感觉go确实很简单,但是它的包也不小,跟node.js有一拼了。

直接使用或者参考

直接参考 Success目录。

https://github.com/kesshei/minio_compile  

下载源码

项目主要通过monio.exe 通过命令直接运行,所以,需要打包生成minio.exe 命令。

这边可以通过以下命令

minio.exe --version

来获取 minio的版本信息

然后,到minio的官网上进行下载相关的包

github仓库地址:https://github.com/minio/minio/releases
gitee镜像仓库:https://gitee.com/mirrors/minio/tags

直接找自己的包,我找的是 RELEASE.2022-05-08T23-50-31Z,找到后,下载这个压缩包

下载后,解压完如下所示:

打开 go.mod


可以看到 需要go的版本是 1.17,直接下载指定版本即可。

go 环境搭建

go 环境需要官网下载,找到 我这边是需要 1.17版本

go 下载地址: https://go.dev/dl/

我需要的算是老版本,所以要继续往下拉


我是window 10 64 ,直接下载这个版本就可以了。

下载完后,直接双击安装,直接安装完

安装完就可以在控制台使用go命令了,以下命令可以看go的版本信息.

go version 

go 环境变量配置

go 用的时候,还是需要配置以下,它的大部分资源都是国外资源,国内没法用。

虽然可以命令行输入,但是,系统级的还是需要手动操作一下更为稳妥。

我的电脑->属性->高级系统属性


点击 系统变量

点击新建 (系统变量)

输入内容,key - value 结构,然后,确定即可

以下是需要增加的变量

GO111MODULE=on
GOPROXY=https://goproxy.cn,direct
GOSUMDB=sum.golang.google.cn
GOROOT=C:\Program Files\Go

其中GOROOT为go的安装目录,其中bin目录 安装包已经自己设置过了,所以不需要设置了。

minio 编译

环境变量设置后,就可以进行编译操作了

go 默认下载的包位于当前用户下的go 目录里 ,我用户名为admin 位于 C:\Users\admin\go\pkg\mod

需要以下相关命令

go clean -modcache    // 清理包的缓存信息
go mod download      //   下载全部的包 go.mod 里的

以下是编译命令

go build -ldflags "-s -w" -o C:\Users\admin\Desktop\minio-RELEASE.2022-05-08T23-50-31Z\build\minio.exe github.com/minio/minio

因为我这边编译过了,我就先清理包的缓存信息

go clean -modcache

然后,执行

go mod download  

minio 逻辑更改

主要是解决跨域问题

http 响应头 cros 修改

主要修改 cmd-> generic-handlers.go 的 addCustomHeaders 方法

const rootdir = "minioConfig"
var Origin = "*"
var Origin_path = filepath.Join(rootdir, "Access_Control_Allow_Origin.txt") 
var Methods = "*"
var Methods_path = filepath.Join(rootdir, "AccessControl_Allow_Methods.txt") 
var Headers = "*"
var Headers_path = filepath.Join(rootdir, "Access_Control_Allow_Headers.txt") 
// addCustomHeaders adds various HTTP(S) response headers.
// Security Headers enable various security protections behaviors in the client's browser.
func addCustomHeaders(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		header := w.Header()
		header.Set("X-XSS-Protection", "1; mode=block")                                // Prevents against XSS attacks
		header.Set("Content-Security-Policy", "block-all-mixed-content")               // prevent mixed (HTTP / HTTPS content)
		header.Set("X-Content-Type-Options", "nosniff")                                // Prevent mime-sniff
		header.Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains") // HSTS mitigates variants of MITM attacks

		// 追加其他的请求头(安全漏洞提示处理)
		header.Set("X-Permitted-Cross-Domain-Policies", "master-only")
		header.Set("Referrer-Policy", "strict-origin-when-cross-origin")
		header.Set("X-Frame-Options", "SAMEORIGIN")

		if Origin == "*" {
			// 检查文件是否存在
			if _, err := os.Stat(Origin_path); err == nil {
				// 文件存在,读取内容
				content, err := os.ReadFile(Origin_path)
				if err != nil {
					fmt.Printf("读取文件时出错: %v\n", err)
					return
				}
				
				Origin = string(content)
				fmt.Printf("成功读取 %s 文件\n", Origin_path)
			}
		}

		if Methods == "*" {
			// 检查文件是否存在
			if _, err := os.Stat(Methods_path); err == nil {
				// 文件存在,读取内容
				content, err := os.ReadFile(Methods_path)
				if err != nil {
					fmt.Printf("读取文件时出错: %v\n", err)
					return
				}
				
				Methods = string(content)
				fmt.Printf("成功读取 %s 文件\n", Methods_path)
			}
		}
		if Headers == "*" {
			// 检查文件是否存在
			if _, err := os.Stat(Headers_path); err == nil {
				// 文件存在,读取内容
				content, err := os.ReadFile(Headers_path)
				if err != nil {
					fmt.Printf("读取文件时出错: %v\n", err)
					return
				}
				
				Headers = string(content)
				fmt.Printf("成功读取 %s 文件\n", Headers_path)
			}
		}
		header.Set("Access-Control-Allow-Origin", Origin)
		header.Set("Access-Control-Allow-Methods", Methods)
		header.Set("Access-Control-Allow-Headers", Headers)
		// Previously, this value was set right before a response was sent to
		// the client. So, logger and Error response XML were not using this
		// value. This is set here so that this header can be logged as
		// part of the log entry, Error response XML and auditing.
		// Set custom headers such as x-amz-request-id for each request.
		w.Header().Set(xhttp.AmzRequestID, mustGetRequestID(UTCNow()))
		h.ServeHTTP(logger.NewResponseWriter(w), r)
	})
}

crossdomain.xml文件安全修改

主要修改 cmd -> crossdomain-xml-handler.go 的 setCrossDomainPolicy 方法

var crossdomainPath = filepath.Join("minioConfig", "crossdomain.xml")
var temp = crossDomainXML
// 配置直接读取当前应用下的crossdomain.xml文件,判断文件是否存在,存在则读取文件内容

// A cross-domain policy file is an XML document that grants a web client, such as Adobe Flash Player
// or Adobe Acrobat (though not necessarily limited to these), permission to handle data across domains.
// When clients request content hosted on a particular source domain and that content make requests
// directed towards a domain other than its own, the remote domain needs to host a cross-domain
// policy file that grants access to the source domain, allowing the client to continue the transaction.
func setCrossDomainPolicy(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Look for 'crossdomain.xml' in the incoming request.
		switch r.URL.Path {
		case crossDomainXMLEntity:
			if temp == crossDomainXML {
				// 检查文件是否存在
				if _, err := os.Stat(crossdomainPath); err == nil {
					// 文件存在,读取内容
					content, err := os.ReadFile(crossdomainPath)
					if err != nil {
						fmt.Printf("读取文件时出错: %v\n", err)
						return
					}
					
					temp = string(content)
					fmt.Printf("成功读取 %s 文件\n", crossdomainPath)
				}
			}
			// Write the standard cross domain policy xml.
			w.Write([]byte(temp))
			// Request completed, no need to serve to other handlers.
			return
		}
		h.ServeHTTP(w, r)
	})
}

minio Server 响应 服务名修改

主要修改 cmd -> api-headers.go 的 setCommonHeaders 函数

var ServerName = "MinIO"
var ServerName_path = filepath.Join("minioConfig", "ServerName.txt") 
// Write http common headers
func setCommonHeaders(w http.ResponseWriter) {
	if ServerName == "MinIO" {
		// 检查文件是否存在
		if _, err := os.Stat(ServerName_path); err == nil {
			// 文件存在,读取内容
			content, err := os.ReadFile(ServerName_path)
			if err != nil {
				fmt.Printf("读取文件时出错: %v\n", err)
				return
			}
			
			ServerName = string(content)
			fmt.Printf("成功读取 %s 文件\n", ServerName_path)
		}
	}
	// Set the "Server" http header.
	w.Header().Set(xhttp.ServerInfo, ServerName)

	// Set `x-amz-bucket-region` only if region is set on the server
	// by default minio uses an empty region.
	if region := globalSite.Region; region != "" {
		w.Header().Set(xhttp.AmzBucketRegion, region)
	}
	w.Header().Set(xhttp.AcceptRanges, "bytes")

	// Remove sensitive information
	crypto.RemoveSensitiveHeaders(w.Header())
}

效果预览

最后是以下文件结构

文件夹

配置的内容

执行以下命令后启动服务

.\minio.exe server C:\Users\win\Desktop\minio2\data

当访问下载地址的时候就可以看到,相关的配置文件都被读取了

可以看到,已经增加了相关的文件头信息了

访问http://127.0.0.1:9000/crossdomain.xml 地址,也看到,这个里面的内容也被修改了.

参考博客

https://www.cnblogs.com/lixingwu/p/17933091.html
posted @ 2025-07-23 16:07  蓝创精英团队  阅读(110)  评论(0)    收藏  举报  来源