1
mirror of https://github.com/jakejarvis/npqueue.git synced 2025-04-26 02:15:23 -04:00

gin secure middleware

This commit is contained in:
Jake Jarvis 2019-07-01 10:45:45 -04:00
parent d048af968e
commit 653974ed42
No known key found for this signature in database
GPG Key ID: D36CB66F4002B25B
10 changed files with 464 additions and 0 deletions

4
Godeps/Godeps.json generated
View File

@ -6,6 +6,10 @@
"./..."
],
"Deps": [
{
"ImportPath": "github.com/gin-contrib/secure",
"Rev": "312887ea6e1f6d9b6dcb5fdd548f8c8dfb62eaca"
},
{
"ImportPath": "github.com/gin-contrib/sse",
"Comment": "v0.1.0",

12
main.go
View File

@ -14,6 +14,7 @@ import (
"time"
"github.com/gin-gonic/contrib/static"
"github.com/gin-contrib/secure"
"github.com/gin-gonic/gin"
_ "github.com/heroku/x/hmetrics/onload"
)
@ -206,6 +207,17 @@ func main() {
port := ":" + os.Getenv("PORT")
router := gin.Default()
router.Use(secure.New(secure.Config{
SSLRedirect: true,
SSLHost: "np.pogge.rs",
STSSeconds: 315360000,
STSIncludeSubdomains: false,
FrameDeny: true,
ContentTypeNosniff: true,
BrowserXssFilter: true,
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
}))
// Serve frontend static files
router.Use(static.Serve("/", static.LocalFile("./public", true)))

1
vendor/github.com/gin-contrib/secure/.gitignore generated vendored Normal file
View File

@ -0,0 +1 @@
coverage.out

37
vendor/github.com/gin-contrib/secure/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,37 @@
language: go
sudo: false
go:
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- 1.12.x
- master
matrix:
fast_finish: true
include:
- go: 1.11.x
env: GO111MODULE=on
- go: 1.12.x
env: GO111MODULE=on
install:
- go get -d -t -v
- go get github.com/campoy/embedmd
script:
- embedmd -d *.md
- go test -v -covermode=atomic -coverprofile=coverage.out .
after_success:
- bash <(curl -s https://codecov.io/bash)
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/acc2c57482e94b44f557
on_success: change
on_failure: always
on_start: false

21
vendor/github.com/gin-contrib/secure/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 gin-contrib
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

68
vendor/github.com/gin-contrib/secure/README.md generated vendored Normal file
View File

@ -0,0 +1,68 @@
# Secure
[![Build Status](https://travis-ci.org/gin-contrib/secure.svg)](https://travis-ci.org/gin-contrib/secure)
[![codecov](https://codecov.io/gh/gin-contrib/secure/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/secure)
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/secure)](https://goreportcard.com/report/github.com/gin-contrib/secure)
[![GoDoc](https://godoc.org/github.com/gin-contrib/secure?status.svg)](https://godoc.org/github.com/gin-contrib/secure)
Secure meddleware for [Gin](https://github.com/gin-gonic/gin/) framework.
## Example
See the [example1](example/code1/example.go), [example2](example/code2/example.go).
DefaultConfig returns a Configuration with strict security settings
[embedmd]:# (secure.go go /func DefaultConfig/ /^}$/)
```go
func DefaultConfig() Config {
return Config{
SSLRedirect: true,
IsDevelopment: false,
STSSeconds: 315360000,
STSIncludeSubdomains: true,
FrameDeny: true,
ContentTypeNosniff: true,
BrowserXssFilter: true,
ContentSecurityPolicy: "default-src 'self'",
IENoOpen: true,
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
}
}
```
[embedmd]:# (example/code1/example.go go)
```go
package main
import (
"github.com/gin-contrib/secure"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.Use(secure.New(secure.Config{
AllowedHosts: []string{"example.com", "ssl.example.com"},
SSLRedirect: true,
SSLHost: "ssl.example.com",
STSSeconds: 315360000,
STSIncludeSubdomains: true,
FrameDeny: true,
ContentTypeNosniff: true,
BrowserXssFilter: true,
ContentSecurityPolicy: "default-src 'self'",
IENoOpen: true,
ReferrerPolicy: "strict-origin-when-cross-origin",
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
}))
router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
// Listen and Server in 0.0.0.0:8080
router.Run()
}
```

7
vendor/github.com/gin-contrib/secure/go.mod generated vendored Normal file
View File

@ -0,0 +1,7 @@
module github.com/gin-contrib/secure
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gin-gonic/gin v1.4.0
github.com/stretchr/testify v1.3.0
)

39
vendor/github.com/gin-contrib/secure/go.sum generated vendored Normal file
View File

@ -0,0 +1,39 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

184
vendor/github.com/gin-contrib/secure/policy.go generated vendored Normal file
View File

@ -0,0 +1,184 @@
package secure
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
type (
// Secure is a middleware that helps setup a few basic security features. A single secure.Options struct can be
// provided to configure which features should be enabled, and the ability to override a few of the default values.
policy struct {
// Customize Secure with an Options struct.
config Config
fixedHeaders []header
}
header struct {
key string
value []string
}
)
// Constructs a new Policy instance with supplied options.
func newPolicy(config Config) *policy {
policy := &policy{}
policy.loadConfig(config)
return policy
}
func (p *policy) loadConfig(config Config) {
p.config = config
p.fixedHeaders = make([]header, 0, 5)
// Frame Options header.
if len(config.CustomFrameOptionsValue) > 0 {
p.addHeader("X-Frame-Options", config.CustomFrameOptionsValue)
} else if config.FrameDeny {
p.addHeader("X-Frame-Options", "DENY")
}
// Content Type Options header.
if config.ContentTypeNosniff {
p.addHeader("X-Content-Type-Options", "nosniff")
}
// XSS Protection header.
if config.BrowserXssFilter {
p.addHeader("X-Xss-Protection", "1; mode=block")
}
// Content Security Policy header.
if len(config.ContentSecurityPolicy) > 0 {
p.addHeader("Content-Security-Policy", config.ContentSecurityPolicy)
}
if len(config.ReferrerPolicy) > 0 {
p.addHeader("Referrer-Policy", config.ReferrerPolicy)
}
// Strict Transport Security header.
if config.STSSeconds != 0 {
stsSub := ""
if config.STSIncludeSubdomains {
stsSub = "; includeSubdomains"
}
// TODO
// "max-age=%d%s" refactor
p.addHeader(
"Strict-Transport-Security",
fmt.Sprintf("max-age=%d%s", config.STSSeconds, stsSub))
}
// X-Download-Options header.
if config.IENoOpen {
p.addHeader("X-Download-Options", "noopen")
}
}
func (p *policy) addHeader(key string, value string) {
p.fixedHeaders = append(p.fixedHeaders, header{
key: key,
value: []string{value},
})
}
func (p *policy) applyToContext(c *gin.Context) bool {
if !p.config.IsDevelopment {
p.writeSecureHeaders(c)
if !p.checkAllowHosts(c) {
return false
}
if !p.checkSSL(c) {
return false
}
}
return true
}
func (p *policy) writeSecureHeaders(c *gin.Context) {
header := c.Writer.Header()
for _, pair := range p.fixedHeaders {
header[pair.key] = pair.value
}
}
func (p *policy) checkAllowHosts(c *gin.Context) bool {
if len(p.config.AllowedHosts) == 0 {
return true
}
host := c.Request.Host
if len(host) == 0 {
host = c.Request.URL.Host
}
for _, allowedHost := range p.config.AllowedHosts {
if strings.EqualFold(allowedHost, host) {
return true
}
}
if p.config.BadHostHandler != nil {
p.config.BadHostHandler(c)
} else {
c.AbortWithStatus(403)
}
return false
}
func (p *policy) isSSLRequest(req *http.Request) bool {
if strings.EqualFold(req.URL.Scheme, "https") || req.TLS != nil {
return true
}
for h, v := range p.config.SSLProxyHeaders {
hv, ok := req.Header[h]
if !ok {
continue
}
if strings.EqualFold(hv[0], v) {
return true
}
}
return false
}
func (p *policy) checkSSL(c *gin.Context) bool {
if !p.config.SSLRedirect {
return true
}
req := c.Request
isSSLRequest := p.isSSLRequest(req)
if isSSLRequest {
return true
}
// TODO
// req.Host vs req.URL.Host
url := req.URL
url.Scheme = "https"
url.Host = req.Host
if len(p.config.SSLHost) > 0 {
url.Host = p.config.SSLHost
}
status := http.StatusMovedPermanently
if p.config.SSLTemporaryRedirect {
status = http.StatusTemporaryRedirect
}
c.Redirect(status, url.String())
c.Abort()
return false
}

91
vendor/github.com/gin-contrib/secure/secure.go generated vendored Normal file
View File

@ -0,0 +1,91 @@
package secure
import "github.com/gin-gonic/gin"
// Config is a struct for specifying configuration options for the secure.
type Config struct {
// AllowedHosts is a list of fully qualified domain names that are allowed.
//Default is empty list, which allows any and all host names.
AllowedHosts []string
// If SSLRedirect is set to true, then only allow https requests.
// Default is false.
SSLRedirect bool
// If SSLTemporaryRedirect is true, the a 302 will be used while redirecting.
// Default is false (301).
SSLTemporaryRedirect bool
// SSLHost is the host name that is used to redirect http requests to https.
// Default is "", which indicates to use the same host.
SSLHost string
// STSSeconds is the max-age of the Strict-Transport-Security header.
// Default is 0, which would NOT include the header.
STSSeconds int64
// If STSIncludeSubdomains is set to true, the `includeSubdomains` will
// be appended to the Strict-Transport-Security header. Default is false.
STSIncludeSubdomains bool
// If FrameDeny is set to true, adds the X-Frame-Options header with
// the value of `DENY`. Default is false.
FrameDeny bool
// CustomFrameOptionsValue allows the X-Frame-Options header value
// to be set with a custom value. This overrides the FrameDeny option.
CustomFrameOptionsValue string
// If ContentTypeNosniff is true, adds the X-Content-Type-Options header
// with the value `nosniff`. Default is false.
ContentTypeNosniff bool
// If BrowserXssFilter is true, adds the X-XSS-Protection header with
// the value `1; mode=block`. Default is false.
BrowserXssFilter bool
// ContentSecurityPolicy allows the Content-Security-Policy header value
// to be set with a custom value. Default is "".
ContentSecurityPolicy string
// HTTP header "Referrer-Policy" governs which referrer information, sent in the Referrer header, should be included with requests made.
ReferrerPolicy string
// When true, the whole secury policy applied by the middleware is disable
// completely.
IsDevelopment bool
// Handlers for when an error occurs (ie bad host).
BadHostHandler gin.HandlerFunc
// Prevent Internet Explorer from executing downloads in your sites context
IENoOpen bool
// If the request is insecure, treat it as secure if any of the headers in this dict are set to their corresponding value
// This is useful when your app is running behind a secure proxy that forwards requests to your app over http (such as on Heroku).
SSLProxyHeaders map[string]string
}
// DefaultConfig returns a Configuration with strict security settings.
// ```
// SSLRedirect: true
// IsDevelopment: false
// STSSeconds: 315360000
// STSIncludeSubdomains: true
// FrameDeny: true
// ContentTypeNosniff: true
// BrowserXssFilter: true
// ContentSecurityPolicy: "default-src 'self'"
// SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
// ```
func DefaultConfig() Config {
return Config{
SSLRedirect: true,
IsDevelopment: false,
STSSeconds: 315360000,
STSIncludeSubdomains: true,
FrameDeny: true,
ContentTypeNosniff: true,
BrowserXssFilter: true,
ContentSecurityPolicy: "default-src 'self'",
IENoOpen: true,
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
}
}
// New creates an instance of the secure middleware using the specified configuration.
// router.Use(secure.N)
func New(config Config) gin.HandlerFunc {
policy := newPolicy(config)
return func(c *gin.Context) {
if !policy.applyToContext(c) {
return
}
}
}