fix: gosec enabled, fixed slowloris on the http.Server, no-timeout serve, webui path traversal, overly permissive perms on themes dir
This commit is contained in:
parent
7c4eefa378
commit
d7758a91c4
|
|
@ -10,6 +10,7 @@ linters:
|
|||
- errcheck
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- gosec
|
||||
- ineffassign
|
||||
- misspell
|
||||
- staticcheck
|
||||
|
|
@ -18,6 +19,74 @@ linters:
|
|||
settings:
|
||||
gocyclo:
|
||||
min-complexity: 5
|
||||
gosec:
|
||||
# Full gosec rule set (G101–G6xx), including Slowloris checks G112/G114.
|
||||
enable-all-rules: true
|
||||
exclusions:
|
||||
paths:
|
||||
- gen
|
||||
rules:
|
||||
# Noise / fixtures in tests and local tooling.
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gosec
|
||||
- path: scripts/
|
||||
linters:
|
||||
- gosec
|
||||
- path: cmd/
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# OliveTin's purpose is controlled command execution from config.
|
||||
- path: internal/executor/
|
||||
text: "G204:"
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# Operator-configured filesystem paths (entity files, touch/write helpers, persisted logs).
|
||||
- path: internal/entities/
|
||||
text: "G304:"
|
||||
linters:
|
||||
- gosec
|
||||
- path: internal/filehelper/
|
||||
text: "G304:"
|
||||
linters:
|
||||
- gosec
|
||||
- path: internal/configcheck/
|
||||
text: "G304:"
|
||||
linters:
|
||||
- gosec
|
||||
- path: internal/executor/
|
||||
text: "G304:"
|
||||
linters:
|
||||
- gosec
|
||||
- path: internal/auth/otjwt/
|
||||
text: "G304:"
|
||||
linters:
|
||||
- gosec
|
||||
- path: internal/httpservers/
|
||||
text: "G304:"
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# Legacy GitHub webhook HMAC-SHA1 is still a supported authType.
|
||||
- path: internal/webhooks/auth\.go
|
||||
text: "G505:"
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# InsecureSkipVerify is an explicit OAuth2 provider config option.
|
||||
- path: internal/auth/otoauth2/
|
||||
text: "G402:"
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# Secure is set dynamically from TLS / ForceSecureCookies; gosec wants a literal true.
|
||||
- text: "G124:"
|
||||
linters:
|
||||
- gosec
|
||||
|
||||
# Protobuf / process exit codes mapped into int32 fields.
|
||||
- text: "G115:"
|
||||
linters:
|
||||
- gosec
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import (
|
|||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OliveTin/OliveTin/internal/api"
|
||||
"github.com/OliveTin/OliveTin/internal/auth"
|
||||
|
|
@ -153,8 +154,12 @@ func StartFrontendMux(cfg *config.Config, ex *executor.Executor) {
|
|||
}
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: cfg.ListenAddressSingleHTTPFrontend,
|
||||
Handler: securityHeadersMiddleware(cfg, mux),
|
||||
Addr: cfg.ListenAddressSingleHTTPFrontend,
|
||||
Handler: securityHeadersMiddleware(cfg, mux),
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
IdleTimeout: 120 * time.Second,
|
||||
// WriteTimeout intentionally unset: EventStream and StartActionAndWait need long-lived writes.
|
||||
}
|
||||
|
||||
log.Fatal(srv.ListenAndServe())
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package httpservers
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
config "github.com/OliveTin/OliveTin/internal/config"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
|
@ -19,8 +20,19 @@ func StartPrometheus(cfg *config.Config) {
|
|||
prometheus.Unregister(collectors.NewGoCollector())
|
||||
}
|
||||
|
||||
http.Handle("/", promhttp.Handler())
|
||||
err := http.ListenAndServe(cfg.ListenAddressPrometheus, nil)
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/", promhttp.Handler())
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: cfg.ListenAddressPrometheus,
|
||||
Handler: mux,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
IdleTimeout: 120 * time.Second,
|
||||
}
|
||||
|
||||
err := srv.ListenAndServe()
|
||||
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
|
|
|
|||
|
|
@ -35,18 +35,16 @@ func NewWebUIServer(cfg *config.Config) *webUIServer {
|
|||
}
|
||||
|
||||
func (s *webUIServer) handleWebui(w http.ResponseWriter, r *http.Request) {
|
||||
// dirName := path.Dir(r.URL.Path)
|
||||
|
||||
// Mangle requests for any path like /logs or /config to load the webui index.html
|
||||
if path.Ext(r.URL.Path) == "" && r.URL.Path != "/" {
|
||||
log.Debugf("Mangling request for %s to /index.html", r.URL.Path)
|
||||
|
||||
http.ServeFile(w, r, path.Join(s.webuiDir, "index.html"))
|
||||
} else {
|
||||
log.Tracef("Serving webui from %s for %s", s.webuiDir, r.URL.Path)
|
||||
http.ServeFile(w, r, path.Join(s.webuiDir, r.URL.Path))
|
||||
// http.StripPrefix(dirName, http.FileServer(http.Dir(s.webuiDir))).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
log.Tracef("Serving webui from %s for %s", s.webuiDir, r.URL.Path)
|
||||
// http.Dir rejects path traversal; do not Join raw URL paths into ServeFile.
|
||||
http.FileServer(http.Dir(s.webuiDir)).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (s *webUIServer) findWebuiDir() string {
|
||||
|
|
@ -84,7 +82,7 @@ func (s *webUIServer) findCustomWebuiDir() string {
|
|||
func (s *webUIServer) setupCustomWebuiDir() {
|
||||
dir := s.findCustomWebuiDir()
|
||||
|
||||
err := os.MkdirAll(path.Join(dir, "themes/"), 0775)
|
||||
err := os.MkdirAll(path.Join(dir, "themes/"), 0o750)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("Could not create themes directory: %v", err)
|
||||
|
|
|
|||
Loading…
Reference in New Issue