minio最新源码编译(处理安全扫描中跨域访问、.js.map等不安全问题)

编译前注意事项

  1. 编译基于tag为RELEASE.2024-06-26T01-06-18Z的版本
  2. 处理安全扫描问题。如:敏感信息泄露、.js.map、跨域访问问题
  3. 需要准备两个工程,前端工程console和minio工程, 目录结构处理:

gowork/

└── src/

├── github.com

├── minio/

└── minio/

└── console/

  1. 若想直接使用处理后的源码,可以克隆minio仓库编辑即可
    minio 直接拉取 minio工程进行编译即可,(其中依赖的console已经更换成
    replace github.com/minio/console => gogs.zyjblogs.cn/minio/console v1.6.1-fix
复制代码
git clone -b RELEASE.2024-06-26T01-06-18Z-fix https://gogs.zyjblogs.cn/minio/minio
  1. 若想直接使用修改后的minio二进制文件,详见蓝奏云链接: minio.tar.gz - 蓝奏云 (lanzout.com)
  2. 若想自行修改详见下文。

console编译

拉取minio的前端工程console

前端工程在console工程下web-app目录

复制代码
#github.com上的仓库
git clone https://github.com/minio/console.git
#国内镜像加速仓库 gitcode
https://gitcode.com/gh_mirrors/console/console.git

修改package.json

在build下添加 GENERATE_SOURCEMAP=false关闭sourcemap

json 复制代码
"scripts": {
    "start": "PORT=5005 react-scripts start",
    "build": "GENERATE_SOURCEMAP=false react-scripts build",
    "buildistanbulcoverage": "PORT=9090 USE_BABEL_PLUGIN_ISTANBUL=1 react-app-rewired build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "playwright": "PORT=5005 USE_BABEL_PLUGIN_ISTANBUL=1 react-app-rewired start",
    "find-deadcode": "ts-prune -s consoleApi.ts | sh -c '(! grep -v \"used in module\")'"
  },

编译

安装依赖

bash 复制代码
#安装依赖
yarn install
#若出现证书问题可以忽略证书
## linux
export NODE_TLS_REJECT_UNAUTHORIZED=0 && yarn install
## windows
set NODE_TLS_REJECT_UNAUTHORIZED=0 && yarn install

编译前删除console工程下web-app/build目录

复制代码
yarn build

修改获取不存在文件.js.map时返回文件且内容为index.html内容问题

console中有一个逻辑是访问不存在静态资源时会返回index.html的内容,因为安全漏洞扫描原因访问.js.map文件成功,虽然内容为index.html的内容,但是避免这类问题进行如下处理。
修改文件 api/configure_console.go

  1. 导入os库
go 复制代码
import (
  "os"
   // 其他库
)
  1. 添加环境变量MINIO_HTTP_SERVER_INFO

修改通用的请求头Server显示的信息(默认为MinIO Console),进行自定义防止文件服务信息被泄露

修改方法FileServerMiddleware

go 复制代码
func FileServerMiddleware(next http.Handler) http.Handler {

    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

        serverInfo := os.Getenv("MINIO_HTTP_SERVER_INFO")

        if serverInfo == "" {

            serverInfo = globalAppName

        }

        w.Header().Set("Server", serverInfo) // do not add version information

        switch {

        case strings.HasPrefix(r.URL.Path, "/ws"):

            serveWS(w, r)

        case strings.HasPrefix(r.URL.Path, "/api"):

            next.ServeHTTP(w, r)

        default:

            buildFs, err := fs.Sub(portal_ui.GetStaticAssets(), "build")

            if err != nil {

                panic(err)

            }

            wrapHandlerSinglePageApplication(requestBounce(http.FileServer(http.FS(buildFs)))).ServeHTTP(w, r)

        }

    })

}
  1. 拦截.js.map

访问不存在资源且资源为资源为.js.map资源时返回404

修改方法wrapHandlerSinglePageApplication

go 复制代码
func wrapHandlerSinglePageApplication(h http.Handler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			handleSPA(w, r)
			return
		}

		w.Header().Set("Content-Type", mimedb.TypeByExtension(filepath.Ext(r.URL.Path)))
		nfw := &notFoundRedirectRespWr{ResponseWriter: w}
		h.ServeHTTP(nfw, r)
		if nfw.status == http.StatusNotFound {
			// 拦截 .js.map 文件
			if strings.HasSuffix(r.URL.Path, ".js.map") {
				http.NotFound(w, r)
				return
			}
			handleSPA(w, r)
		}
	}
}

minio编译

拉取minio工程

复制代码
#github.com上的仓库
git clone https://github.com/minio/minio.git
#国内镜像加速仓库 gitcode
https://gitcode.com/gh_mirrors/mi/minio.git

处理go.mod文件

添加替换文件中依赖github.com/minio/console../console

bash 复制代码
# 若为本地源代码执行下面命令进行处理
go mod edit --replace github.com/minio/console=../console
# 若想使用已经修改完成的console则使用
go mod edit --replace github.com/minio/console=gogs.zyjblogs.cn/minio/console@v1.6.1-fix

依赖下载

bash 复制代码
go clean -modcache
go mod download
go mod tidy

修改项目源码

  1. 配置crossdomain.xml

原始minio访问crossdomain.xml可以看到返回xml内容:

xml 复制代码
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd"><cross-domain-policy>
    <allow-access-from domain="*" secure="false" />
</cross-domain-policy>

该配置安全扫描为不安全项,需要设置allow-access-from为具体的域名。

现在把它修改为,读取配置的环境变量,然后设置为具体的域名,让其返回类似下面的xml,不能使用*

xml 复制代码
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
    <allow-access-from domain="*.baidu.com" secure="false" />
    <allow-access-from domain="zyjblogs.cn" secure="false" />
</cross-domain-policy>

修改步骤:

(1)修改项目中的internal/config/constants.go文件,加入需要读取环境的名称,具体看修改后源码

const{}内添加两个环境变量,位置在 86~91行左右。 constants.go

复制代码
const (
    //.....
    
	// 以下是自定的环境变量参数
	// EnvMinIOAllowAccessFromDomain crossdomain.xml cross-domain-policy
	EnvMinIOAllowAccessFromDomain = "MINIO_ALLOW_ACCESS_FROM_DOMAIN"
	// EnvMinIOServerInfo api 通用的请求头Server显示的信息,进行自定义防止文件服务信息被泄露
	EnvMinIOServerInfo = "MINIO_HTTP_SERVER_INFO"
)

(2)然后修改crossdomain.xml对应的处理类cmd/crossdomain-xml-handler.go,修改读取环境变量配置的值,具体查看修改后的文件crossdomain-xml-handler.go(minio/minio @ RELEASE.2024-06-26T01-06-18Z-fix - 逝水无痕の代码仓库 (zyjblogs.cn)

在变量crossDomainXML后添如下代码。代码位置32行位置

go 复制代码
// 自定义crossdomain.xml
const crossDomainXMLPrefix = `<?xml version="1.0"?><!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd"><cross-domain-policy>`
const crossDomainXMLSuffix = `</cross-domain-policy>`
const allowAccessFromTemplate = `<allow-access-from domain="{{.Domain}}" secure="false" />`

替换方法setCrossDomainPolicyMiddleware为如下内容。 位置

go 复制代码
func setCrossDomainPolicyMiddleware(h http.Handler) http.Handler {
	// get env MINIO_ALLOW_ACCESS_FROM_DOMAIN
	allowAccessFromDomain := os.Getenv(config.EnvMinIOAllowAccessFromDomain)
	if allowAccessFromDomain == "" {
		allowAccessFromDomain = "*"
	}
	// logger.Info("MINIO_ALLOW_ACCESS_FROM_DOMAIN=%s", allowAccessFromDomain)

	// 如果配置了多个就需要解析一下
	domains := strings.Split(allowAccessFromDomain, ",")
	allowAccessFrom := crossDomainXMLPrefix
	for _, domain := range domains {
		// fill string template
		buffer := &bytes.Buffer{}
		tmpl, _ := template.New("tmp").Parse(allowAccessFromTemplate)
		data := struct{ Domain string }{Domain: domain}
		_ = tmpl.Execute(buffer, data)
		allowAccessFrom += buffer.String()
	}
	allowAccessFrom += crossDomainXMLSuffix

	// Write to ServeHTTP
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Look for 'crossdomain.xml' in the incoming request.
		if r.URL.Path == crossDomainXMLEntity {
			// Write the standard cross domain policy xml.
			w.Write([]byte(allowAccessFrom))
			// Request completed, no need to serve to other handlers.
			return
		}
		h.ServeHTTP(w, r)
	})
}

然后访问对应的地址,即可使用配置的xml。

http://IP:PORT/crossdomain.xml

(3) 添加功能:自定义响应头Server的信息

请求minio接口时,返回的请求头会返回Server: MinIO ,这样扫描会被针对扫描,需要修改为自定义的信息,例如这样:Server: MyOSS ,这样就可以不会暴露出文件服务器的信息了。
直接修改cmd/api-headers.go文件中的setCommonHeaders方法,读取配置环境变量,修改代码如下。可参考api-headers.go第55~59行

go 复制代码
func setCommonHeaders(w http.ResponseWriter) {
	// Set the "Server" http header.
	// w.Header().Set(xhttp.ServerInfo, MinioStoreName)
	// Set the "Server" http header.
	serverInfo := os.Getenv(config.EnvMinIOServerInfo)
	if serverInfo == "" {
		serverInfo = MinioStoreName
	}
	w.Header().Set(xhttp.ServerInfo, serverInfo)
	// 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())
}

(4)添加功能:追加安全扫描提示的响应头

安全扫描提示需要响应头

ini 复制代码
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Permitted-Cross-Domain-Policies: master-only
X-Xss-Protection: 1; mode=block

修改步骤:修改cmd/generic-handlers.go文件的addCustomHeadersMiddleware方法,把缺少的响应头追加上即可,可参考修改后的源码generic-handlers.go第535~557行。

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

编译项目

在minio工程下执行如下命令

参数介绍 go build -ldflags "-s -w" -o 编译后的二进制文件 项目工程目录

在minio工程执行构建命令时,使用.代表当前目录

bash 复制代码
# window 
go build -ldflags "-s -w" -o E:\minio.exe .
# linux
go build -ldflags "-s -w" -o ~/minio .

运行文件服务

使用环境变量配置启动参数:

sh 复制代码
export MINIO_ROOT_USER=minioadmin
export MINIO_ROOT_PASSWORD=minioadmin
#export MINIO_BROWSER=false
export MINIO_API_CORS_ALLOW_ORIGIN="https://*.zyjblogs.cn,https://*example.com"
#新添加的参数
export MINIO_ALLOW_ACCESS_FROM_DOMAIN=*.zyjblogs.cn,*example.com
export MINIO_HTTP_SERVER_INFO=MyOSS

变量说明:

变量名称 说明
MINIO_ROOT_USER 管理控制台账号
MINIO_ROOT_PASSWORD 管理控制台密码
MINIO_BROWSER off关闭web控制台
MINIO_API_CORS_ALLOW_ORIGIN api可使用域名
MINIO_ALLOW_ACCESS_FROM_DOMAIN new crossdomain.xml文件的域名配置
MINIO_HTTP_SERVER_INFO new 响应头Server的信息

使用9000端口启动文件服务:

sh 复制代码
#!/bin/bash
export MINIO_ROOT_USER=minioadmin
export MINIO_ROOT_PASSWORD=minioadmin
#export MINIO_BROWSER=false
export MINIO_API_CORS_ALLOW_ORIGIN="https://*.zyjblogs.cn,https://*example.com"
export MINIO_ALLOW_ACCESS_FROM_DOMAIN=*.zyjblogs.cn,*example.com
export MINIO_HTTP_SERVER_INFO=MyOSS
nohup ./minio server data > minio.log 2>&1 &

参考:

https://www.cnblogs.com/lixingwu/p/17933091.html

https://blog.csdn.net/LoveTheMost/article/details/138950398

相关推荐
Scott9999HH4 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社5 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海5 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖6 小时前
JDK 26 新特性详解
java·开发语言
马优晨6 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区8 小时前
怎么把C语言学到精通?
c语言·开发语言
九硕智慧建筑一体化厂家9 小时前
直流智能照明|一站式低碳照明解决方案,安全、节能、降本、全场景适配
安全
心平气和量大福大9 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai9 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜9 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript