Go net/http configurable handler to handle CORS requests

Go CORS handler godoc license build Coverage

CORS is a net/http handler implementing Cross Origin Resource Sharing W3 specification in Golang.

Getting Started

After installing Go and setting up your GOPATH, create your first .go file. We'll call it server.go.

package main

import (
    "net/http"

    "github.com/rs/cors"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        w.Write([]byte("{\"hello\": \"world\"}"))
    })

    // cors.Default() setup the middleware with default options being
    // all origins accepted with simple methods (GET, POST). See
    // documentation below for more options.
    handler := cors.Default().Handler(mux)
    http.ListenAndServe(":8080", handler)
}

Install cors:

go get github.com/rs/cors

Then run your server:

go run server.go

The server now runs on localhost:8080:

$ curl -D - -H 'Origin: http://foo.com' http://localhost:8080/
HTTP/1.1 200 OK
Access-Control-Allow-Origin: foo.com
Content-Type: application/json
Date: Sat, 25 Oct 2014 03:43:57 GMT
Content-Length: 18

{"hello": "world"}

Allow * With Credentials Security Protection

This library has been modified to avoid a well known security issue when configured with AllowedOrigins to * and AllowCredentials to true. Such setup used to make the library reflects the request Origin header value, working around a security protection embedded into the standard that makes clients to refuse such configuration. This behavior has been removed with #55 and #57.

If you depend on this behavior and understand the implications, you can restore it using the AllowOriginFunc with func(origin string) {return true}.

Please refer to #55 for more information about the security implications.

More Examples

Parameters

Parameters are passed to the middleware thru the cors.New method as follow:

c := cors.New(cors.Options{
    AllowedOrigins: []string{"http://foo.com", "http://foo.com:8080"},
    AllowCredentials: true,
    // Enable Debugging for testing, consider disabling in production
    Debug: true,
})

// Insert the middleware
handler = c.Handler(handler)
  • AllowedOrigins []string: A list of origins a cross-domain request can be executed from. If the special * value is present in the list, all origins will be allowed. An origin may contain a wildcard (*) to replace 0 or more characters (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penality. Only one wildcard can be used per origin. The default value is *.
  • AllowOriginFunc func (origin string) bool: A custom function to validate the origin. It takes the origin as an argument and returns true if allowed, or false otherwise. If this option is set, the content of AllowedOrigins is ignored.
  • AllowOriginRequestFunc func (r *http.Request origin string) bool: A custom function to validate the origin. It takes the HTTP Request object and the origin as argument and returns true if allowed or false otherwise. If this option is set, the content of AllowedOrigins and AllowOriginFunc is ignored
  • AllowedMethods []string: A list of methods the client is allowed to use with cross-domain requests. Default value is simple methods (GET and POST).
  • AllowedHeaders []string: A list of non simple headers the client is allowed to use with cross-domain requests.
  • ExposedHeaders []string: Indicates which headers are safe to expose to the API of a CORS API specification
  • AllowCredentials bool: Indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates. The default is false.
  • MaxAge int: Indicates how long (in seconds) the results of a preflight request can be cached. The default is 0 which stands for no max age.
  • OptionsPassthrough bool: Instructs preflight to let other potential next handlers to process the OPTIONS method. Turn this on if your application handles OPTIONS.
  • Debug bool: Debugging flag adds additional output to debug server side CORS issues.

See API documentation for more info.

Benchmarks

BenchmarkWithout          20000000    64.6 ns/op      8 B/op    1 allocs/op
BenchmarkDefault          3000000      469 ns/op    114 B/op    2 allocs/op
BenchmarkAllowedOrigin    3000000      608 ns/op    114 B/op    2 allocs/op
BenchmarkPreflight        20000000    73.2 ns/op      0 B/op    0 allocs/op
BenchmarkPreflightHeader  20000000    73.6 ns/op      0 B/op    0 allocs/op
BenchmarkParseHeaderList  2000000      847 ns/op    184 B/op    6 allocs/op
BenchmarkParse…Single     5000000      290 ns/op     32 B/op    3 allocs/op
BenchmarkParse…Normalized 2000000      776 ns/op    160 B/op    6 allocs/op

Licenses

All source code is licensed under the MIT License.

Owner
Olivier Poitrey
Director of Engineering at Netflix Co-Founder & ex-CTO of Dailymotion Co-Founder of NextDNS
Olivier Poitrey
Comments
  • Fix * behavior to be standards compliant.

    Fix * behavior to be standards compliant.

    In section 6.1 of the CORS standard is talks about this exact situation. Even though you have built in a guard-rail in to the library which will print a nice warning, it is preferred to rely on the security already built in to the standard.

    When ACAO: * and ACAC: true are both specified the browser will refuse to make the credentialed request.

    Refer to the standard: https://www.w3.org/TR/cors/

  • Add CORS headers to non-preflight OPTIONS too

    Add CORS headers to non-preflight OPTIONS too

    Non preflight OPTIONS requests should work with CORS too. This change is removing abort in actual request CORS handler for OPTIONS request, so the client can receive the necessary headers on such request.

  • The dot character as part of header keys is broking the preflighted requests

    The dot character as part of header keys is broking the preflighted requests

    If you run a preflighted request containing the character "." as part of a header key, it is not working. I made a quick fix, it was just replacing: reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers")) by reqHeaders := strings.Split(r.Header.Get("Access-Control-Request-Headers"), ",") in "cors.go" file: https://github.com/rs/cors/blob/d4dacab0671f9aedbf3924d3df2a4a95c8c11a87/cors.go#L286.

    Then all works as usual, maybe it would be needed a header processing for special characters of naming conventions.

  • Do not duplicate headers

    Do not duplicate headers

    Seems this middleware happily add the headers even if they're present on the response.

    I'm getting this from Chrome: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8085, http://localhost:8085', but only one is allowed. Origin 'http://localhost:8085' is therefore not allowed access.

  • CORS security: reflecting any origin header value when configured to * is dangerous

    CORS security: reflecting any origin header value when configured to * is dangerous

    When CORS policy is configured to origin:"*", current go CORS handler will actively convert it to reflect any Origin header value. This kind of behavior is dangerous and has caused many security problems in the past.

    Some similar security issues: https://github.com/cyu/rack-cors/issues/126 https://nodesecurity.io/advisories/148

    Some related blog posts: http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html https://ejj.io/misconfigured-cors/

  • Should OPTIONS response include Access-Control-Allow-Origin?

    Should OPTIONS response include Access-Control-Allow-Origin?

    I've setup cors with default server. When running:

    curl -D - -X OPTIONS -H 'Origin: http://www.plot-my-trip.local.com:8080' http://www.plot-my-trip.local.com:4000/api/auth/get-user

    Vary: Origin
    Vary: Access-Control-Request-Method
    Vary: Access-Control-Request-Headers
    Date: Thu, 20 Aug 2015 00:05:01 GMT
    Content-Length: 0
    Content-Type: text/plain; charset=utf-8
    

    Notice there's no Access-Control-Allow-Origin header.

    When trying to access the above API using Javascript in Chrome, I see the error in the console:

    http://www.plot-my-trip.local.com:4000/api/auth/get-user. No 'Access-Control-Allow-Origin' header 
    is present on the requested resource. Origin 'http://www.plot-my-trip.local.com:8080' is 
    therefore not allowed access.
    
  • 404 for OPTIONS requests when using `HandlerFunc` even when `OptionsPassthrough` is `false`

    404 for OPTIONS requests when using `HandlerFunc` even when `OptionsPassthrough` is `false`

    I'm not sure how general this is, but in the framework I'm using (gin, which is very similar to martini), when I use c.HandlerFunc I get 404s for OPTIONS requests, even with OptionsPassthrough set to false.

    I was able to fix this in the short term by always setting the status code to 200 for valid OPTIONS requests.

    Here's what I had before that failed with a 404

    # Fails with 404 on OPTIONS request
    r := gin.Default()
    r.Use(gin.WrapF(c.HandlerFunc))
    

    Here's what works for OPTIONS requests

    makeCorsHandler := func(c *cors.Cors) func(http.ResponseWriter, *http.Request) {
        return func(w http.ResponseWriter, r *http.Request) {
            c.HandlerFunc(w, r)
            // Allow it to return to avoid a 404
            if r.Method == "OPTIONS" && w.Header().Get("Access-Control-Allow-Origin") == r.Header.Get("Origin") {
                w.WriteHeader(http.StatusOK)
            }
        }
    }
    

    Really I should be checking if optionPassthrough is false, but I don't have access to that property here. Also, checking that Access-Control-Allow-Origin is set to the correct value is kind of a hack that just works because that header value isn't set until the request has made it past all the relevant cross domain checks.

    However you want to handle it, making the OptionsPassthrough option make more sense when using HandlerFunc would be helpful. That may mean just documenting this case, or providing an option to handle this automatically by always returning 200s. I couldn't think of a very clean way to do it, hence the bug report and no PR. :)

    Please let me know if there is any testing I can do to help. I certainly appreciate your work on this library!

  • fix: :art: updated gin to 1.7.4 to fix CVE-2020-28483

    fix: :art: updated gin to 1.7.4 to fix CVE-2020-28483

    Update Gin to 1.7.4 to fix CVE-2020-28483

    Details from Dependency Check:

    This affects all versions of package github.com/gin-gonic/gin. When gin is exposed directly to the internet, a client's IP can be spoofed by setting the X-Forwarded-For header. CWE-444 Inconsistent Interpretation of HTTP Requests ('HTTP Request Smuggling')

    CVSSv2: Base Score: MEDIUM (5.8) Vector: /AV:N/AC:M/Au:N/C:P/I:P/A:N CVSSv3: Base Score: HIGH (7.1) Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N

    References: MISC - https://github.com/gin-gonic/gin/pull/2474%23issuecomment-729696437 MISC - https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMGINGONICGIN-1041736 Vulnerable Software & Versions:

    cpe:2.3:a:gin-gonic:gin:::::::: versions up to (excluding) 1.7.0

  • [help] Access-Control-Allow-Credentials: true, Access-Control-Allow-Origin cannot be *, but I did not find the corresponding implementation

    [help] Access-Control-Allow-Credentials: true, Access-Control-Allow-Origin cannot be *, but I did not find the corresponding implementation

    If ajax wants to carry cookies when sending cross-domain requests, the withcredentials attribute of the request object must be set to true.

    At this time, the server response header Access-Control-Allow-Origin cannot be * (asterisk), it must be a whitelist style, that is, which URLs must be allowed to access, except for the response header Access-Control-Allow-Origin Setting, you must also set another response header: Access-Control-Allow-Credentials: true.

    	if c.allowCredentials {
                     // TODO:Missing settings for Access-Control-Allow-Origin, when AllowedOrigins=*
    		headers.Set("Access-Control-Allow-Credentials", "true")
    	}
    
  • Are all these dependencies actually required in the root package?

    Are all these dependencies actually required in the root package?

    I found in go.mod a bunch of dependencies that are declared for the root package, but these dependencies are only indeed used in the examples folder packages:

    https://github.com/rs/cors/blob/master/go.mod#L6-L17

    Is there a reason why these non-production dependencies are declared in the root package go.mod?

  • GoBuffalo support

    GoBuffalo support

    Hi!

    I'm trying to use CORS middleware with Buffalo. I saw code snippet in the issue #609.

    It works, but after OPTIONS call log prints warning "multiple response.WriteHeader calls":

    [cors] 2018/01/17 15:35:08 Handler: Preflight request
    [cors] 2018/01/17 15:35:08   Preflight response headers: map[Vary:[Origin Access-Control-Request-Method Access-Control-Request-Headers] Access-Control-Allow-Origin:[http://localhost:4200] Access-Control-Allow-Methods:[POST] Access-Control-Allow-Headers:[Content-Type] Access-Control-Allow-Credentials:[true]]
    2018/01/17 15:35:08 http: multiple response.WriteHeader calls
    [cors] 2018/01/17 15:35:08 Handler: Actual request
    [cors] 2018/01/17 15:35:08   Actual response added headers: map[Access-Control-Allow-Credentials:[true] Vary:[Origin] Access-Control-Allow-Origin:[http://localhost:4200]]
    

    Could you suggest me, how to fix this warning?

    My code:

    func App() *buffalo.App {
    	if app == nil {
    		app = buffalo.New(buffalo.Options{
    			Env:          ENV,
    			SessionStore: sessions.NewCookieStore([]byte(SECRET)),
    			SessionName:  "sessionid",
    		})
    
    		// Set the request content type to JSON
    		app.Use(middleware.SetContentType("application/json"))
    
    		if ENV == "development" {
    			app.Use(middleware.ParameterLogger)
    			app.PreWares = []buffalo.PreWare{cors.New(cors.Options{
    				AllowedOrigins:   []string{"*"},
    				AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE"},
    				AllowedHeaders:   []string{"Content-Type", "Cookie"},
    				AllowCredentials: true,
    				Debug:            true,
    			}).Handler}
    		}
    
    		// Set custom error response
    		// SOME STAFF
    
    		app.GET("/", HomeHandler)
    
    		app.POST("/session", AuthLogin)
    
    		auth := app.Group("/")
    		auth.Use(AuthRequired)
    		auth.DELETE("/session", AuthLogout)
    		auth.GET("/session", AuthSession)
    	}
    
    	return app
    }
    
  • Optmize allow-headers check by removing duplicate values

    Optmize allow-headers check by removing duplicate values

    Prevents having an Allowed list with repeated values to iterate over.

    Example: When configuring "Origin" as an Allowed header, the list would be comprised of: []string{"Origin","Origin"}, lead to an unnecessary additional loop.

  • Unexpected response when requesting with multiple comma separated origins and wildcard AllowedOrigins

    Unexpected response when requesting with multiple comma separated origins and wildcard AllowedOrigins

    If an origin https://*.example.com is allowed and a client sends a request with a header Origin: https://github.com,https://test.example.com the wildcard match is performed against the comma separated origin header value and succeeds. This leads to an unexpected and according to the specification invalid response header Access-Control-Allow-Origin: https://github.com,https://test.example.com. Also it was never intended that https://github.com should be allowed.

    As far as I know current Browser implementations never send comma separated values in origin headers (and never multiple headers) and I'm not even sure if the specification would allow this. However, I think it would make sense to validate the origin header's format and reject requests with an unexpected format (not sure on how to do this backward compatible?).

  • security issue: should not allow rejected requests to go forward

    security issue: should not allow rejected requests to go forward

    The below example is a minor revised version of the one in the README:

    package main
    
    import (
        "net/http"
    
        "github.com/rs/cors"
    )
    
    func main() {
        mux := http.NewServeMux()
        mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            w.Header().Set("Content-Type", "application/json")
            w.Write([]byte("{\"hello\": \"world\"}"))
        })
    
        // cors.Default() setup the middleware with default options being
        // all origins accepted with simple methods (GET, POST). See
        // documentation below for more options.
        handler := cors.New(cors.Options{AllowedOrigins: []string{"http://foo.com"}}).Handler(mux)
        http.ListenAndServe(":8080", handler)
    }
    

    And from the below CURL output, we can see that the response does not have the Access-Control-Allow-Origin header, this is correct. But the problem is the actual request handler was called (the response body is {"hello": "world"}), that is, though an attacker cannot get the result from the browser, he/she can execute a request successfully.

    $ curl -X POST -H 'Origin:http://bar.com' http://localhost:8080/ -D -
    HTTP/1.1 200 OK
    Content-Type: application/json
    Vary: Origin
    Date: Thu, 28 Jul 2022 01:07:27 GMT
    Content-Length: 18
    
    {"hello": "world"}
    
  • Problem with .local url

    Problem with .local url

    Hello, I have a problem with CORS when I am trying to call my api from .local address Screenshot 2021-11-26 185850 (2)

    I use mux and my setup for CORS is, `c := cors.New(cors.Options{ AllowedOrigins: []string{"*"}, AllowCredentials: true, AllowedMethods: []string{"GET", "POST", "DELETE"},

    	// Enable Debugging for testing, consider disabling in production
    	Debug: true,
    })
    

    ` Do I need any special set up for this? I find out that I need to set up the header 'Access-Control-Allow-Private-Network' as true, how can I set up this one? Thanks

  • add option to allow all methods

    add option to allow all methods

    This PR add a wildcard option * to allow all methods specified in Access-Control-Request-Method. I was trying to access webdav files from organice. My preflight request is like this curl -vvvvvv -H 'Access-Control-Request-Method: PROPFIND' -H 'Access-Control-Request-Headers: authorization,depth' -H 'Origin: https://organice.200ok.ch' -X OPTIONS http://example.com. There is a few custom http verbs for webdav. I think it makes sense to allow all the http methods, so I added an option to allow all methods, just like the option to allow all http headers.

  • CORS request not applying correct on backend

    CORS request not applying correct on backend

    Using the package and can not figure out why corsConfig is not applying to my localhost frontend. Any help will be much appreciated.

    func main() {
    	router := gin.Default()
    
    	corsConfig := cors.New(cors.Options{
    		AllowedOrigins: []string{"*"},
    		AllowedMethods:     []string{"PUT", "PATCH", "GET", "POST", "DELETE", "OPTIONS"},
    		AllowedHeaders: []string{"*"},
    		AllowCredentials: false,
    		MaxAge: int(12 * time.Hour),
    	})
    	
    	router.Use(corsConfig)
    
    	connDB, err := postgres.InitDB()     
    	if err != nil {
    		log.Fatal(err)
    		return
    	}
    
    	defer connDB.Close()
    	// Our server will live in the routes package
    	routes.Run()
    }
    
    
    import (
    	"github.com/gin-gonic/gin"
    )
    
    var (
    	router = gin.Default()
    )
    
    // Run will start the server
    func Run() {
    
    	getRoutes()
    	router.Run(":8000")
    }
    
    // getRoutes will create our routes of our entire application
    // this way every group of routes can be defined in their own file
    // so this one won't be so messy
    func getRoutes() {
    	v1 := router.Group("/v1")
    	addUserRoutes(v1)
    	addPingRoutes(v1)
    
    	v2 := router.Group("/v2")
    	addPingRoutes(v2)
    
    	router.GET("/testing", func(c *gin.Context) {
    		c.JSON(200, "hello")
    	})
    }
    ![Screenshot (2)](https://user-images.githubusercontent.com/16749587/93007572-325ab300-f538-11ea-9361-8f272c8e4ea7.png)
    
    
    
A Golang Middleware to handle X-Forwarded-For Header

X-Forwarded-For middleware fo Go Package xff is a net/http middleware/handler to parse Forwarded HTTP Extension in Golang. Example usage Install xff:

Nov 3, 2022
Simple middleware to rate-limit HTTP requests.

Tollbooth This is a generic middleware to rate-limit HTTP requests. NOTE 1: This library is considered finished. NOTE 2: Major version changes are bac

Jan 4, 2023
An HTTP client for go-server-timing middleware. Enables automatic timing propagation through HTTP calls between servers.

client-timing An HTTP client for go-server-timing middleware. Features: An HTTP Client or RoundTripper, fully compatible with Go's standard library. A

Dec 24, 2022
Fault injection library in Go using standard http middleware

Fault The fault package provides go http middleware that makes it easy to inject faults into your service. Use the fault package to reject incoming re

Dec 25, 2022
Go (golang) library for creating and consuming HTTP Server-Timing headers
Go (golang) library for creating and consuming HTTP Server-Timing headers

HTTP Server-Timing for Go This is a library including middleware for using HTTP Server-Timing with Go. This header allows a server to send timing info

Dec 8, 2022
哪吒监控 一站式轻监控轻运维系统。支持系统状态、HTTP、TCP、Ping 监控报警,命令批量执行和计划任务
哪吒监控 一站式轻监控轻运维系统。支持系统状态、HTTP、TCP、Ping 监控报警,命令批量执行和计划任务

哪吒监控 一站式轻监控轻运维系统。支持系统状态、HTTP、TCP、Ping 监控报警,命令批量执行和计划任务

Jan 8, 2023
Restish is a CLI for interacting with REST-ish HTTP APIs with some nice features built-in
Restish is a CLI for interacting with REST-ish HTTP APIs with some nice features built-in

Restish is a CLI for interacting with REST-ish HTTP APIs with some nice features built-in, like always having the latest API resources, fields, and operations available when they go live on the API without needing to install or update anything.

Jan 5, 2023
⚡ Rux is an simple and fast web framework. support middleware, compatible http.Handler interface. 简单且快速的 Go web 框架,支持中间件,兼容 http.Handler 接口

Rux Simple and fast web framework for build golang HTTP applications. NOTICE: v1.3.x is not fully compatible with v1.2.x version Fast route match, sup

Dec 8, 2022
Gin middleware/handler to enable CORS support.

wcors Gin middleware/handler to enable CORS support. Usage Start using it Download and install it: go get github.com/wyy-go/wcors Import it in your co

Jan 8, 2022
Timeout wraps a handler and aborts the process of the handler if the timeout is reached.

Timeout Timeout wraps a handler and aborts the process of the handler if the timeout is reached. Example package main import ( "context" "fmt" "gi

Jan 8, 2022
Go net/http handler to transparently manage posted JSON

Go JSON handler FormJSON is a net/http handler implementing content negotiation for posted data in order to transparently expose posted JSON as if it

Sep 27, 2022
A net.http.Handler similar to FileServer that serves gzipped content

net.http.handler.gzip: a FileServer that serves gzipped content. Usage: import "net/http/handler/gzip" base := "/path/to/website/static/files" http

Mar 14, 2022
Lightweight Router for Golang using net/http standard library with custom route parsing, handler and context.

Go-Lightweight-Router Lightweight Router for Golang using net/http standard library with custom route parsing, handler and context. Further developmen

Nov 3, 2021
httpreq is an http request library written with Golang to make requests and handle responses easily.

httpreq is an http request library written with Golang to make requests and handle responses easily. Install go get github.com/binalyze/http

Feb 10, 2022
go http api to handle phishing resources requests

go http api to handle phishing resources requests (auth check, prometheus metrics, pushing to rabbit, logging to elasticsearch)

Oct 8, 2021
TCP proxy, highjacks HTTP to allow CORS

portproxy A shitty TCP proxy that relays all requests to a local port to a remote server. portproxy -port 8080 -raddr google.com:80 Will proxy all TC

Jan 1, 2023
Opinionated boilerplate Golang HTTP server with CORS, OPA, Prometheus, rate-limiter for API and static website.
Opinionated boilerplate Golang HTTP server with CORS, OPA, Prometheus, rate-limiter for API and static website.

Teal.Finance/Server Opinionated boilerplate HTTP server with CORS, OPA, Prometheus, rate-limiter… for API and static website. Origin This library was

Nov 3, 2022
Opinionated boilerplate Golang HTTP server with CORS, OPA, Prometheus, rate-limiter for API and static website.
Opinionated boilerplate Golang HTTP server with CORS, OPA, Prometheus, rate-limiter for API and static website.

Teal.Finance/Garcon Opinionated boilerplate HTTP server with CORS, OPA, Prometheus, rate-limiter… for API and static website. Origin This library was

Nov 3, 2022
A minimal framework to build web apps; with handler chaining, middleware support; and most of all standard library compliant HTTP handlers(i.e. http.HandlerFunc).
A minimal framework to build web apps; with handler chaining, middleware support; and most of all standard library compliant HTTP handlers(i.e. http.HandlerFunc).

WebGo v4.1.3 WebGo is a minimalistic framework for Go to build web applications (server side) with zero 3rd party dependencies. Unlike full-fledged fr

Jan 1, 2023
Muxie is a modern, fast and light HTTP multiplexer for Go. Fully compatible with the http.Handler interface. Written for everyone.
Muxie is a modern, fast and light HTTP multiplexer for Go. Fully compatible with the http.Handler interface. Written for everyone.

Muxie ?? ?? ?? ?? ?? ?? Fast trie implementation designed from scratch specifically for HTTP A small and light router for creating sturdy backend Go a

Dec 8, 2022