From 3247aa40a7335a0b7a8864dd037ae6bed5ad9367 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Wed, 9 Nov 2022 08:55:57 +0300 Subject: [PATCH] rpcsrv: allow any Origin in WS connections if EnableCORSWorkaround Break origin checks even more. Alternative to #2772. --- docs/node-configuration.md | 11 +++++++++-- pkg/services/rpcsrv/server.go | 12 +++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/node-configuration.md b/docs/node-configuration.md index 453b6fa5b..24a4b8d6a 100644 --- a/docs/node-configuration.md +++ b/docs/node-configuration.md @@ -158,8 +158,15 @@ RPC: where: - `Enabled` denotes whether an RPC server should be started. - `Address` is an RPC server address to be running at. -- `EnableCORSWorkaround` enables Cross-Origin Resource Sharing and is useful if - you're accessing RPC interface from the browser. +- `EnableCORSWorkaround` turns on a set of origin-related behaviors that make + RPC server wide open for connections from any origins. It enables OPTIONS + request handling for pre-flight CORS and makes the server send + `Access-Control-Allow-Origin` and `Access-Control-Allow-Headers` headers for + regular HTTP requests (allowing any origin which effectively makes CORS + useless). It also makes websocket connections work for any `Origin` + specified in the request header. This option is not recommended (reverse + proxy can be used to have proper app-specific CORS settings), but it's an + easy way to make RPC interface accessible from the browser. - `MaxGasInvoke` is the maximum GAS allowed to spend during `invokefunction` and `invokescript` RPC-calls. - `MaxIteratorResultItems` - maximum number of elements extracted from iterator diff --git a/pkg/services/rpcsrv/server.go b/pkg/services/rpcsrv/server.go index 5f8d4af9e..f13303c30 100644 --- a/pkg/services/rpcsrv/server.go +++ b/pkg/services/rpcsrv/server.go @@ -122,6 +122,7 @@ type ( config config.RPC // wsReadLimit represents web-socket message limit for a receiving side. wsReadLimit int64 + upgrader websocket.Upgrader network netmode.Magic stateRootEnabled bool coreServer *network.Server @@ -249,10 +250,6 @@ var invalidBlockHeightError = func(index int, height int) *neorpc.Error { return neorpc.NewRPCError("Invalid block height", fmt.Sprintf("param at index %d should be greater than or equal to 0 and less then or equal to current block height, got: %d", index, height)) } -// upgrader is a no-op websocket.Upgrader that reuses HTTP server buffers and -// doesn't set any Error function. -var upgrader = websocket.Upgrader{} - // New creates a new Server struct. func New(chain Ledger, conf config.RPC, coreServer *network.Server, orc OracleHandler, log *zap.Logger, errChan chan error) Server { @@ -282,11 +279,16 @@ func New(chain Ledger, conf config.RPC, coreServer *network.Server, if orc != nil { oracleWrapped.Store(&orc) } + var wsOriginChecker func(*http.Request) bool + if conf.EnableCORSWorkaround { + wsOriginChecker = func(_ *http.Request) bool { return true } + } return Server{ Server: httpServer, chain: chain, config: conf, wsReadLimit: int64(protoCfg.MaxBlockSize*4)/3 + 1024, // Enough for Base64-encoded content of `submitblock` and `submitp2pnotaryrequest`. + upgrader: websocket.Upgrader{CheckOrigin: wsOriginChecker}, network: protoCfg.Magic, stateRootEnabled: protoCfg.StateRootInHeader, coreServer: coreServer, @@ -431,7 +433,7 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ ) return } - ws, err := upgrader.Upgrade(w, httpRequest, nil) + ws, err := s.upgrader.Upgrade(w, httpRequest, nil) if err != nil { s.log.Info("websocket connection upgrade failed", zap.Error(err)) return