I am using SignalR in a mobile application. It will connect to my server. Since there is no specific origin as far as I understand from which request will be originated, I can't allow any specific origin and allow all origins gives problem since credentials mode is on in the library when sending negotiation request.
You can further check my stackoverflow issue here:
https://stackoverflow.com/questions/56854263/cors-policy-making-problems-even-after-all-headers-and-origins-are-allowed
If I allow all origin I get this error:
... from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight
request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
I can allow my local environment for testing purpose but then again, how do I allow all mobile apps after this application is deployed? Is there a way to modify origin before sending negotiation request?
I get "Failed to start the transport 'WebSockets': null" error as well. But I doubt its that issue because I have a .NET (not core) application running with SignalR and its working fine. I am hosting it on IIS server.
Should be able to use the override for all origins.
I think it would be preferable to hold a whitelist.
@DAllanCarr How do you maintain a whitelist if you're working with mobile apps?
This didn't work:
Func<string, bool> IsOriginAllowed = x => true;
services.AddCors(o => o.AddPolicy("MyCORSPolicy", builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.DisallowCredentials()
.AllowAnyHeader();
builder.SetIsOriginAllowed(IsOriginAllowed);
}));
If you don't mind feeling dirty, then you can do this... but I really don't recommend it unless it's absolutely necessary, and you have some additional security and checks in place. It basically just breaks CORS. Use at your own risk!
public void Configure(IApplicationBuilder app)
{
app.UseMiddleware<CorsOverride>();
}
public class CorsOverride
{
private readonly RequestDelegate _next;
public CorsOverride(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
const string allowOriginHeaderName = "Access-Control-Allow-Origin";
if (httpContext.Response.Headers.ContainsKey(allowOriginHeaderName))
{
httpContext.Response.Headers.Remove(allowOriginHeaderName);
}
httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
httpContext.Response.Headers.Add("Access-Control-Allow-Headers", "x-requested-with");
if (httpContext.Request.Headers["Access-Control-Request-Method"].Count > 0)
{
foreach (var header in httpContext.Request.Headers["Access-Control-Request-Method"])
{
httpContext.Response.Headers.Add("Access-Control-Allow-Methods", header);
}
}
else
{
httpContext.Response.Headers.Add("Access-Control-Allow-Methods", httpContext.Request.Method);
}
foreach (var origin in httpContext.Request.Headers.Where(h => h.Key == "Origin"))
{
httpContext.Response.Headers.Add(allowOriginHeaderName, origin.Value);
}
if (httpContext.Request.Method == "OPTIONS")
{
httpContext.Response.StatusCode = 200;
await httpContext.Response.WriteAsync("");
}
else
{
await _next.Invoke(httpContext);
}
}
}
@NichUK Its working but some issues. First it gave me this error:
"Error during WebSocket handshake: Incorrect 'Sec-WebSocket-Accept' header value"
So I enabled websockets with this: app.UseWebSockets();
Now its giving me this error: Error: Failed to start the transport 'WebSockets': null
Its falling back to Server Sent Events, I am receiving updates from server now but not through websockets.
@devWaleed With difficulty I imagine 馃槥. Looks like you got over the CORS issue. Nice going.
I actually thought this would work for your exact reason rather than resorting to custom code.
services.AddCors(options
=>
options.AddPolicy("CorsPolicy",
builder =>
builder .SetIsOriginAllowed((host) => true) .
AllowAnyMethod() .
AllowAnyHeader() .
AllowCredentials());
});
@DAllanCarr @NichUK
I have been searching for answer for about 2 days to be honest. Thank you for the help.
I think this is not exactly a 100% right answer. A right way would be to allow specific origin. But then again my question is, how do you set static origin values for mobile apps?
Further more on ASP.NET website they clearly say that CORS is not a security feature but a standard and response can still be processed using FIddler or something else.
https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.2#how-cors-works
So my question is again, how does it affect my security if I disable CORS and how do I allow it for mobile apps?
Thanks for the answer. Its working right now. I had to enable Websocket Protocol on IIS.
But this raises more questions, I have 2 other .NET (not dotnet core) apps running on same IIS server and they use SignalR as well. I didn't see any websockets error there. Why do I need to enable Websocket protocol here?
Edit: I did some deep research and looks like its alright to disable CORS policy in this scenario. Read more here: ASP.NET Core 2 Cross Origin Request Handling
CORS is not a security feature and should not be considered such. Its actually an opt in and relaxes incoming requests for same site policy restrictions enforced on the client.
The fact you need to opt in will vary depending on what clients you are wanting to support.
If you can disable CORS and it works for your scenario then do it.
If you have no way of knowing who is connecting to your service then you are at a slight disadvantage anyway. And CORS is not going to help you. Restrictions only makes sense if you know the domain from which a client will be connecting.
Alright, thank you so much.
Edit: I did some research and looks like its alright to disable CORS policy in this scenario. I wrote an article about, read more here: ASP.NET Core 2 Cross Origin Request Handling