Compare commits

...

2 Commits

6 changed files with 99 additions and 394 deletions

View File

@ -17,6 +17,7 @@ import (
"github.com/dcarrillo/whatismyip/router" "github.com/dcarrillo/whatismyip/router"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/unrolled/secure"
) )
var ( var (
@ -138,6 +139,28 @@ func setupEngine() {
engine = gin.New() engine = gin.New()
engine.Use(gin.LoggerWithFormatter(httputils.GetLogFormatter)) engine.Use(gin.LoggerWithFormatter(httputils.GetLogFormatter))
engine.Use(gin.Recovery()) engine.Use(gin.Recovery())
if setting.App.EnableSecureHeaders {
engine.Use(addSecureHeaders())
}
_ = engine.SetTrustedProxies(nil) _ = engine.SetTrustedProxies(nil)
engine.TrustedPlatform = setting.App.TrustedHeader engine.TrustedPlatform = setting.App.TrustedHeader
} }
func addSecureHeaders() gin.HandlerFunc {
return func(c *gin.Context) {
err := secure.New(secure.Options{
BrowserXssFilter: true,
ContentTypeNosniff: true,
FrameDeny: true,
}).Process(c.Writer, c.Request)
if err != nil {
c.Abort()
return
}
// Avoid header rewrite if response is a redirection.
if status := c.Writer.Status(); status > 300 && status < 399 {
c.Abort()
}
}
}

19
go.mod
View File

@ -4,9 +4,10 @@ go 1.18
require ( require (
github.com/gin-gonic/gin v1.7.7 github.com/gin-gonic/gin v1.7.7
github.com/oschwald/maxminddb-golang v1.8.0 github.com/oschwald/maxminddb-golang v1.9.0
github.com/stretchr/testify v1.7.1 github.com/stretchr/testify v1.7.1
github.com/testcontainers/testcontainers-go v0.12.0 github.com/testcontainers/testcontainers-go v0.12.0
github.com/unrolled/secure v1.10.0
) )
require ( require (
@ -15,10 +16,10 @@ require (
github.com/Microsoft/hcsshim v0.9.2 // indirect github.com/Microsoft/hcsshim v0.9.2 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/containerd/cgroups v1.0.3 // indirect github.com/containerd/cgroups v1.0.3 // indirect
github.com/containerd/containerd v1.6.1 // indirect github.com/containerd/containerd v1.6.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v20.10.13+incompatible // indirect github.com/docker/docker v20.10.14+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
@ -41,19 +42,19 @@ require (
github.com/morikuni/aec v1.0.0 // indirect github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.0 // indirect github.com/opencontainers/runc v1.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.8.1 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect github.com/ugorji/go/codec v1.2.7 // indirect
go.opencensus.io v0.23.0 // indirect go.opencensus.io v0.23.0 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/net v0.0.0-20220401154927-543a649e0bdd // indirect
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e // indirect google.golang.org/genproto v0.0.0-20220401170504-314d38edb7de // indirect
google.golang.org/grpc v1.45.0 // indirect google.golang.org/grpc v1.45.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
) )

371
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@ func buildContainer() testcontainers.ContainerRequest {
"-tls-crt", "/tmp/server.pem", "-tls-crt", "/tmp/server.pem",
"-tls-key", "/tmp/server.key", "-tls-key", "/tmp/server.key",
"-trusted-header", "X-Real-IP", "-trusted-header", "X-Real-IP",
"-enable-secure-headers",
}, },
ExposedPorts: []string{"8000:8000", "8001:8001"}, ExposedPorts: []string{"8000:8000", "8001:8001"},
WaitingFor: wait.ForLog("Starting TLS server listening on :8001"), WaitingFor: wait.ForLog("Starting TLS server listening on :8001"),

View File

@ -20,15 +20,16 @@ type serverSettings struct {
WriteTimeout time.Duration WriteTimeout time.Duration
} }
type settings struct { type settings struct {
GeodbPath geodbPath GeodbPath geodbPath
TemplatePath string TemplatePath string
BindAddress string BindAddress string
TLSAddress string TLSAddress string
TLSCrtPath string TLSCrtPath string
TLSKeyPath string TLSKeyPath string
TrustedHeader string TrustedHeader string
Server serverSettings EnableSecureHeaders bool
version bool Server serverSettings
version bool
} }
const defaultAddress = ":8080" const defaultAddress = ":8080"
@ -74,6 +75,12 @@ func Setup(args []string) (output string, err error) {
"Trusted request header for remote IP (e.g. X-Real-IP)", "Trusted request header for remote IP (e.g. X-Real-IP)",
) )
flags.BoolVar(&App.version, "version", false, "Output version information and exit") flags.BoolVar(&App.version, "version", false, "Output version information and exit")
flags.BoolVar(
&App.EnableSecureHeaders,
"enable-secure-headers",
false,
"Add sane security-related headers to every response",
)
err = flags.Parse(args) err = flags.Parse(args)
if err != nil { if err != nil {

View File

@ -70,12 +70,13 @@ func TestParseFlags(t *testing.T) {
City: "/city-path", City: "/city-path",
ASN: "/asn-path", ASN: "/asn-path",
}, },
TemplatePath: "", TemplatePath: "",
BindAddress: ":8080", BindAddress: ":8080",
TLSAddress: "", TLSAddress: "",
TLSCrtPath: "", TLSCrtPath: "",
TLSKeyPath: "", TLSKeyPath: "",
TrustedHeader: "", TrustedHeader: "",
EnableSecureHeaders: false,
Server: serverSettings{ Server: serverSettings{
ReadTimeout: 10 * time.Second, ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second,
@ -89,12 +90,13 @@ func TestParseFlags(t *testing.T) {
City: "/city-path", City: "/city-path",
ASN: "/asn-path", ASN: "/asn-path",
}, },
TemplatePath: "", TemplatePath: "",
BindAddress: ":8001", BindAddress: ":8001",
TLSAddress: "", TLSAddress: "",
TLSCrtPath: "", TLSCrtPath: "",
TLSKeyPath: "", TLSKeyPath: "",
TrustedHeader: "", TrustedHeader: "",
EnableSecureHeaders: false,
Server: serverSettings{ Server: serverSettings{
ReadTimeout: 10 * time.Second, ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second,
@ -111,12 +113,13 @@ func TestParseFlags(t *testing.T) {
City: "/city-path", City: "/city-path",
ASN: "/asn-path", ASN: "/asn-path",
}, },
TemplatePath: "", TemplatePath: "",
BindAddress: ":8080", BindAddress: ":8080",
TLSAddress: ":9000", TLSAddress: ":9000",
TLSCrtPath: "/crt-path", TLSCrtPath: "/crt-path",
TLSKeyPath: "/key-path", TLSKeyPath: "/key-path",
TrustedHeader: "", TrustedHeader: "",
EnableSecureHeaders: false,
Server: serverSettings{ Server: serverSettings{
ReadTimeout: 10 * time.Second, ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second,
@ -126,19 +129,20 @@ func TestParseFlags(t *testing.T) {
{ {
[]string{ []string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path",
"-trusted-header", "header", "-trusted-header", "header", "-enable-secure-headers",
}, },
settings{ settings{
GeodbPath: geodbPath{ GeodbPath: geodbPath{
City: "/city-path", City: "/city-path",
ASN: "/asn-path", ASN: "/asn-path",
}, },
TemplatePath: "", TemplatePath: "",
BindAddress: ":8080", BindAddress: ":8080",
TLSAddress: "", TLSAddress: "",
TLSCrtPath: "", TLSCrtPath: "",
TLSKeyPath: "", TLSKeyPath: "",
TrustedHeader: "header", TrustedHeader: "header",
EnableSecureHeaders: true,
Server: serverSettings{ Server: serverSettings{
ReadTimeout: 10 * time.Second, ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second,