Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CORS works even if it is not enabled #5148

Open
alexandrmucha opened this issue Jul 25, 2024 · 10 comments
Open

CORS works even if it is not enabled #5148

alexandrmucha opened this issue Jul 25, 2024 · 10 comments
Labels
question Further information is requested

Comments

@alexandrmucha
Copy link

Describe the bug
I am using socket.io in nuxt. Even though I didn't enable cors, it is possible to connect from a different origin than the one nuxt is running on. E.g. it runs on localhost:3000 and I can connect from localhost:8000. Is this a bug or is it my fault?

To Reproduce

Please fill the following code example:

Socket.IO server version: ^4.7.5

Server

import type { NitroApp } from "nitropack";
import { Server as Engine } from "engine.io";
import { Server } from "socket.io";
import { defineEventHandler } from "h3";
import { registerSocketHandlers } from "../sockets";

export default defineNitroPlugin((nitroApp: NitroApp) => {
  const engine = new Engine();
  const io = new Server();

  io.bind(engine);

  registerSocketHandlers(io);

  nitroApp.router.use("/socket.io/", defineEventHandler({
    handler(event) {
      engine.handleRequest(event.node.req, event.node.res);
      event._handled = true;
    },
    websocket: {
      open(peer) {
        const nodeContext = peer.ctx.node;
        const req = nodeContext.req;

        // @ts-expect-error private method
        engine.prepare(req);

        const rawSocket = nodeContext.req.socket;
        const websocket = nodeContext.ws;

        // @ts-expect-error private method
        engine.onWebSocket(req, rawSocket, websocket);
      }
    }
  }));
});

Socket.IO client version: ^4.7.5

Client

socket: io('http://localhost:3000', { transports: ['websocket', 'polling', 'flashsocket'] }),

Expected behavior
It will not be possible to connect from an origin other than the one defined or on which nuxt is running.

Platform:

  • Device: PC
  • OS: Windows 10

Additional context
Add any other context about the problem here.

@alexandrmucha alexandrmucha added the to triage Waiting to be triaged by a member of the team label Jul 25, 2024
@darrachequesne
Copy link
Member

Hi!

CORS only applies to HTTP long-polling, but you use WebSocket first: ['websocket', 'polling', 'flashsocket']. If you switch back to ['polling', 'websocket'], it should fail as expected.

Note: the "flashsocket" transport does not exist anymore.

@darrachequesne darrachequesne added question Further information is requested and removed to triage Waiting to be triaged by a member of the team labels Jul 25, 2024
@alexandrmucha
Copy link
Author

Hi, thank you for your answer.

When I used the default transport method, the connection failed even though I defined the origin correctly. From what I read, it was caused by "the default transportation method is not always allowed by all servers": Stackoverflow

Can you confirm that the error was caused by an unsupported transport method and not an error with the cors configuration?

@darrachequesne
Copy link
Member

darrachequesne commented Jul 26, 2024

The Stackoverflow post uses an old version of the socket.io package (2.2), you need to configure the cors option:

const io = new Server({
  cors: {
    origin: ["http://localhost:8000"]
  }
});

Reference: https://socket.io/docs/v4/handling-cors/

@alexandrmucha
Copy link
Author

Thats the problem. It doesnt work even though I set this origin correctly.

Access` to XMLHttpRequest at 'http://localhost:3000/socket.io/?EIO=4&transport=polling&t=P3kAbNS' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
websocket.ts:6

const io = new Server({
cors: {
origin: ["http://localhost:8000"]
}
});

i tried it also without http

@darrachequesne
Copy link
Member

Hmm, that's weird... Could you please check if you are able to reach the Socket.IO server with:

$ curl -v -H "origin: http://localhost:3000" "http://localhost:8080/socket.io/?EIO=4&transport=polling"

It should return something like:

*   Trying 127.0.0.1:3000...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /socket.io/?EIO=4&transport=polling HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.81.0
> Accept: */*
> origin: http://localhost:3000
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: http://localhost:3000
< Vary: Origin
< Content-Type: text/plain; charset=UTF-8
< Content-Length: 118
< cache-control: no-store
< Date: Fri, 26 Jul 2024 10:34:04 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< 
* Connection #0 to host localhost left intact
0{"sid":"IMkIs3bah6ZNcXwVAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":20000,"maxPayload":1000000}

Reference: https://socket.io/docs/v4/troubleshooting-connection-issues/

@alexandrmucha
Copy link
Author

My server is running on port 3000 and I'm trying to connect from 8000, so I modified the command to include those addresses.

curl -v -H "origin: http://localhost:8000" "http://localhost:3000/socket.io/?EIO=4&transport=polling"

it returned me this:

* Host localhost:3000 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:3000...
* Connected to localhost (::1) port 3000
> GET /socket.io/?EIO=4&transport=polling HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/8.7.1
> Accept: */*
> origin: http://localhost:8000
>
* Request completely sent off
< HTTP/1.1 200 OK
< content-type: text/plain; charset=UTF-8
< content-length: 118
< cache-control: no-store
< date: Fri, 26 Jul 2024 13:52:46 GMT
< connection: close
<
0{"sid":"iEWn6snaZTIUWBrqAAAA","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":20000,"maxPayload":1000000}* Closing connection

@alexandrmucha
Copy link
Author

and it returns the same thing when I try to set the origin to not allowed in the command

@alexandrmucha
Copy link
Author

Also I dont see any cors header in network tab in devtools

@alexandrmucha
Copy link
Author

@darrachequesne I tried adding the cors header manually and it works then, could there be a problem with adding the headers? Can you please check my nuxt socket.io plugin code to see if I have a misconfigured server? Or is it possible that there is a bug in socket.io itself?

import type { NitroApp } from "nitropack";
import { Server as Engine } from "engine.io";
import { Server } from "socket.io";
import { defineEventHandler } from "h3";
import { registerSocketHandlers } from "../sockets";

export default defineNitroPlugin((nitroApp: NitroApp) => {
  const engine = new Engine();
  
  const io = new Server({
    cors: {
      origin: "http://localhost:8000",
    }
  });

  io.bind(engine);

  registerSocketHandlers(io);

  nitroApp.router.use("/socket.io/", defineEventHandler({
    handler(event) {
      
      // Here I manually added the cors origin header
      event.node.res.setHeader("Access-Control-Allow-Origin", "http://localhost:8000");

      engine.handleRequest(event.node.req, event.node.res);
      event._handled = true;
    },
    websocket: {
      open(peer) {
        const nodeContext = peer.ctx.node;
        const req = nodeContext.req;

        // @ts-expect-error private method
        engine.prepare(req);

        const rawSocket = nodeContext.req.socket;
        const websocket = nodeContext.ws;

        // @ts-expect-error private method
        engine.onWebSocket(req, rawSocket, websocket);
      }
    }
  }));
});

@semiharslanait
Copy link

To summarize, while both configurations handle CORS, they do so at different stages and for different purposes. The origin option in the Server constructor controls whether the server will accept connections from a given origin, and the Access-Control-Allow-Origin header in the response ensures that the browser will accept the response from the server.

So they are not same things and socket.io initaly not offering to send header to browser when you give origin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants