@@ -12,43 +12,31 @@ import (
1212 "golang.org/x/xerrors"
1313)
1414
15- // AcceptOption is an option that can be passed to Accept.
16- // The implementations of this interface are printable.
17- type AcceptOption interface {
18- acceptOption ()
19- }
20-
21- type acceptSubprotocols []string
22-
23- func (o acceptSubprotocols ) acceptOption () {}
24-
25- // AcceptSubprotocols lists the websocket subprotocols that Accept will negotiate with a client.
26- // The empty subprotocol will always be negotiated as per RFC 6455. If you would like to
27- // reject it, close the connection if c.Subprotocol() == "".
28- func AcceptSubprotocols (protocols ... string ) AcceptOption {
29- return acceptSubprotocols (protocols )
30- }
31-
32- type acceptInsecureOrigin struct {}
33-
34- func (o acceptInsecureOrigin ) acceptOption () {}
35-
36- // AcceptInsecureOrigin disables Accept's origin verification
37- // behaviour. By default Accept only allows the handshake to
38- // succeed if the javascript that is initiating the handshake
39- // is on the same domain as the server. This is to prevent CSRF
40- // when secure data is stored in cookies.
41- //
42- // See https://stackoverflow.com/a/37837709/4283659
43- //
44- // Use this if you want a WebSocket server any javascript can
45- // connect to or you want to perform Origin verification yourself
46- // and allow some whitelist of domains.
47- //
48- // Ensure you understand exactly what the above means before you use
49- // this option in conjugation with cookies containing secure data.
50- func AcceptInsecureOrigin () AcceptOption {
51- return acceptInsecureOrigin {}
15+ // AcceptOptions represents the options available to pass to Accept.
16+ type AcceptOptions struct {
17+ // Subprotocols lists the websocket subprotocols that Accept will negotiate with a client.
18+ // The empty subprotocol will always be negotiated as per RFC 6455. If you would like to
19+ // reject it, close the connection if c.Subprotocol() == "".
20+ Subprotocols []string
21+
22+ // InsecureSkipVerify disables Accept's origin verification
23+ // behaviour. By default Accept only allows the handshake to
24+ // succeed if the javascript that is initiating the handshake
25+ // is on the same domain as the server. This is to prevent CSRF
26+ // when secure data is stored in a cookie as there is no same
27+ // origin policy for WebSockets. In other words, javascript from
28+ // any domain can perform a WebSocket dial on an arbitrary server.
29+ // This dial will include cookies which means the arbitrary javascript
30+ // can perform actions as the authenticated user.
31+ //
32+ // See https://stackoverflow.com/a/37837709/4283659
33+ //
34+ // The only time you need this is if your javascript is running on a different domain
35+ // than your WebSocket server.
36+ // Please think carefully about whether you really need this option before you use it.
37+ // If you do, remember if you store secure data in cookies, you wil need to verify the
38+ // Origin header.
39+ InsecureSkipVerify bool
5240}
5341
5442func verifyClientRequest (w http.ResponseWriter , r * http.Request ) error {
@@ -88,26 +76,14 @@ func verifyClientRequest(w http.ResponseWriter, r *http.Request) error {
8876// Accept accepts a WebSocket handshake from a client and upgrades the
8977// the connection to WebSocket.
9078// Accept will reject the handshake if the Origin is not the same as the Host unless
91- // the AcceptInsecureOrigin option is passed.
92- // Accept uses w to write the handshake response so the timeouts on the http.Server apply.
93- func Accept (w http.ResponseWriter , r * http.Request , opts ... AcceptOption ) (* Conn , error ) {
94- var subprotocols []string
95- verifyOrigin := true
96- for _ , opt := range opts {
97- switch opt := opt .(type ) {
98- case acceptInsecureOrigin :
99- verifyOrigin = false
100- case acceptSubprotocols :
101- subprotocols = []string (opt )
102- }
103- }
104-
79+ // the InsecureSkipVerify option is set.
80+ func Accept (w http.ResponseWriter , r * http.Request , opts AcceptOptions ) (* Conn , error ) {
10581 err := verifyClientRequest (w , r )
10682 if err != nil {
10783 return nil , err
10884 }
10985
110- if verifyOrigin {
86+ if ! opts . InsecureSkipVerify {
11187 err = authenticateOrigin (r )
11288 if err != nil {
11389 http .Error (w , err .Error (), http .StatusForbidden )
@@ -127,7 +103,7 @@ func Accept(w http.ResponseWriter, r *http.Request, opts ...AcceptOption) (*Conn
127103
128104 handleKey (w , r )
129105
130- subproto := selectSubprotocol (r , subprotocols )
106+ subproto := selectSubprotocol (r , opts . Subprotocols )
131107 if subproto != "" {
132108 w .Header ().Set ("Sec-WebSocket-Protocol" , subproto )
133109 }
@@ -190,5 +166,5 @@ func authenticateOrigin(r *http.Request) error {
190166 if strings .EqualFold (u .Host , r .Host ) {
191167 return nil
192168 }
193- return xerrors .Errorf ("request origin %q is not authorized" , origin )
169+ return xerrors .Errorf ("request origin %q is not authorized for host %v " , origin , r . Host )
194170}
0 commit comments