mirror of
https://github.com/gitpod-io/gitpod.git
synced 2025-12-08 17:36:30 +00:00
[proxy] add security headers (#20970)
Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
parent
3145c9dada
commit
7137b3a8ba
@ -25,7 +25,8 @@ func init() {
|
||||
httpcaddyfile.RegisterHandlerDirective(headlessLogDownloadModule, parseCaddyfile)
|
||||
}
|
||||
|
||||
// HeadlessLogDownload implements an HTTP handler that extracts gitpod headers
|
||||
// HeadlessLogDownload implements an HTTP handler that proxies headless log downloads
|
||||
// with security headers to prevent XSS attacks from malicious branch names in logs.
|
||||
type HeadlessLogDownload struct {
|
||||
Service string `json:"service,omitempty"`
|
||||
}
|
||||
@ -93,6 +94,9 @@ func (m HeadlessLogDownload) ServeHTTP(w http.ResponseWriter, r *http.Request, n
|
||||
return caddyhttp.Error(http.StatusInternalServerError, fmt.Errorf("unexpected error downloading prebuild log"))
|
||||
}
|
||||
|
||||
setSecurityHeaders(w)
|
||||
copyResponseHeaders(w, resp)
|
||||
|
||||
brw := newNoBufferResponseWriter(w)
|
||||
_, err = io.Copy(brw, resp.Body)
|
||||
if err != nil {
|
||||
@ -103,6 +107,38 @@ func (m HeadlessLogDownload) ServeHTTP(w http.ResponseWriter, r *http.Request, n
|
||||
return next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func setSecurityHeaders(w http.ResponseWriter) {
|
||||
headers := w.Header()
|
||||
headers.Set("Content-Type", "text/plain; charset=utf-8")
|
||||
headers.Set("X-Content-Type-Options", "nosniff")
|
||||
headers.Set("X-Frame-Options", "DENY")
|
||||
headers.Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'")
|
||||
headers.Set("Referrer-Policy", "strict-origin-when-cross-origin")
|
||||
headers.Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||
}
|
||||
|
||||
// copyResponseHeaders copies safe headers from upstream response, excluding potentially dangerous ones
|
||||
func copyResponseHeaders(w http.ResponseWriter, resp *http.Response) {
|
||||
// List of safe headers to copy from upstream
|
||||
safeHeaders := []string{
|
||||
"Content-Length",
|
||||
"Content-Encoding",
|
||||
"Content-Disposition",
|
||||
"Last-Modified",
|
||||
"ETag",
|
||||
}
|
||||
|
||||
destHeaders := w.Header()
|
||||
for _, header := range safeHeaders {
|
||||
if value := resp.Header.Get(header); value != "" {
|
||||
destHeaders.Set(header, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Note: We intentionally do NOT copy Content-Type from upstream
|
||||
// because we want to enforce text/plain for security
|
||||
}
|
||||
|
||||
// UnmarshalCaddyfile implements Caddyfile.Unmarshaler.
|
||||
func (m *HeadlessLogDownload) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||
if !d.Next() {
|
||||
@ -172,3 +208,11 @@ func (n *noBufferWriter) Write(p []byte) (written int, err error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (n *noBufferWriter) Header() http.Header {
|
||||
return n.w.Header()
|
||||
}
|
||||
|
||||
func (n *noBufferWriter) WriteHeader(statusCode int) {
|
||||
n.w.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user