Do I really need CORS here with Swagger? - c#

I developed an API to give public access to some company data, which is of no value to hackers. It's public data that can be sourced from other websites.
I developed the project using default Visual Studio ASP.Net Core API templates. One thing I noticed it's using CORS and I don't know how it got in here to be honest.
However, the default Policy is set as any domain, any method and any header:
builder.Services.AddCors(p =>
p.AddPolicy("corsapp", builder =>
{
builder.WithOrigins("*").AllowAnyMethod().AllowAnyHeader();
}));
Do I even need CORS, if I am only allowing the API to run from a single origin, which already has HTTPS?
What benefit, when the API works as is?
Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//do I really need this!?!
builder.Services.AddCors(p => p.AddPolicy("corsapp", builder =>
{
builder.WithOrigins("*").AllowAnyMethod().AllowAnyHeader();
}));
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
startup.Configure(app);
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
//why!?!
app.UseCors("corsapp");
app.UseAuthorization();
app.MapControllers();
app.Run();
UPDATE
I've re-worded my OP based on Rahul's excellent video about CORS from Chen's answer below. However, I am still confused if I should configure CORS here to give a specific single origin as I am more worried someone after me may not configure this Policy correctly if the API is required in more than two places.
Thanks

You would need to know if your program provides API responses to client applications loaded from other domains to determine if you need to enable CORS.
For example, there are two cases where no action is needed for CORS support:
Swagger UI is hosted on the same server as the application itself (same host and port).
The application is located behind a proxy that enables the required CORS headers. This may already be covered within your organization.
You can get a better understanding and use of CORS through this link and this official documentation.

Related

C# .NET Web API CORS-Errors

I've tried for days now and I can't get it to work.
I have a local web app and a local, separately running .NET 6.0 WebAPI which is supposed to accept post requests.
The web app which sends the fetch requests runs on localhost:3000
and the WebAPI runs on localhost:44379
My CORS-Policy is setup in the Program.cs file as follows:
appsettings.json:
"AllowedHosts": "*",
"cors": {
"rules": [
{
"origin": "*",
"allow": true
}
]
}
Program.cs:
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowMyOrigin",
builder => builder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowAnyOrigin()
);
});
And then I use them before running the app, I also made sure to call the cors policy after the routing calls and before the Authorization calls:
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("AllowMyOrigin");
app.UseAuthorization();
app.UseMiddleware<ApiKeyMiddleware>();
app.MapControllers();
app.Run();
I still get the cors error, also with enabled browser addons which should disable the issues on the browser.
I can't seem to figure out what is missing and would appreciate help
So it turned out my CORS-Configurations were already properly set up.
As jdweng noted in the comments, the 400 response with the type: "cors" might have just been a false error in order to confuse hackers as some servers may do that.
This meant I switched focus on checking back on my Request-Headers and Payload and was able to identify an issue with the DateTime conversion of one of the Attributes of the JSON-Payload.
After fixing this, the requests came through and I also didn't get any CORS-Errors.
So in case you run into a similar issue and are already very sure about the proper setup for the CORS-options, be sure to debug your Fetch/Axios Request and implement proper error handling on the backend to see if the input model is valid and catch the errors to send back more detailed errors.

Howto implement ASP.NET Core Blazor Server app and a Web API app in the same procress?

I want to implement both
a ASP.NET Core Blazor Server
and a ASP.NET Core Web API (the server part, not the consumer/client)
in the same process using .NET 6 and run it self-hosted with Kestrel, i.e. without IIS.
I assume the key is the service and middleware pipeline configuration as found in the according Program.cs templates. Here are the two templates that VS 2022 (17.1.5) creates for me:
For the Blazor Server App:
using BlazorApp1.Data;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
For the ASP.NET Core Web API App:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
So the question is how can I combine these two into one?
I want to:
Have my program listening to a single port
Host the Blazor web pages
But process the API when the URL myhost:port/api/.. is being accessed (without interfering with the Blazor part)
Have the SwaggerUI, preferably under myhost:port/api/swagger/index.html (again without interfering with the Blazor part)
Use the same security mechanism based on a client certificate for both
You should be able to combine these without any issues:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.UseRouting();
app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
The service configuration supports registring all dependencies anyway. And between AddRazorPages() and AddController(), there are quite a lot of shared ones anyway.
The only thing that can be tricky is the pipeline configuration since you need to make sure that both API requests and Blazor requests are handled by the correct handlers.
The good thing is that MapControllers is usually means a fixed set of routes. Since your controller actions have specific routes, having the MapControllers first will make sure that those specific routes will be handled properly by your controllers.
All other requests, those that don’t match any controller action, will then go to the next route handler in the pipeline. So MapBlazorHub is next which will host the SignalR hub for Blazor. That’s also a very specific route which is provided here.
So finally, all remaining requests will land at MapFallbackToPage(). This is a fallback-handler which means that it will handle any route. This allows Blazor to have a single entry-point for which it will then use client-side routing. As long as this fallback call is the last in the pipeline, it should not be able to interfere with any other route handler.
With that combined configuration, both your API and your Blazor should work just fine.
If you do have a situation which is more complicated, then you can use app.MapWhen to branch off the pipeline. There is an example in the documentation if you are interested in this functionality. But as I said, for your situation, you shouldn’t need it.

How to solve "Failed to bind to address http://127.0.0.1:5000: address already in use."

I created a Asp.Net Core app with Visual Studio and used the publish option of VS to publish my app on my Azure account.
After publishing it, I used the link to access my website but I get a "HTTP Error 500.30 - ASP.NET Core app failed to start"
I went to the console in Azure to manually start my app and have more detail about the issue and I got this.
Not really sure how to solve this issue with my port
Below is the code from program.cs
var connectionString = builder.Configuration.GetConnectionString("LocalConnection");
builder.Services.AddDbContext<LotharDataBaseContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddControllersWithViews();
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Through your screenshot, I saw Kestrel, so I think, the webapp you created should be on linux platform. The port occupancy on your screenshot is expected behavior, it shouldn't be the root cause. Since the site is already running, and you manually command it to start again, this error should appear.
I suggest you provide your Program.cs file first, we need to look at UseUrls, or the code for UseKestrel.
How to check the logs when start webapp:
open you kudu site, url should be https://your_app_name.scm.azurewebsites.net
open newui, https://your_app_name.scm.azurewebsites.net/newui
steps:
In this default_docker.log file, we will get useful message.
Steps you can try:
Try to add .UseIIS, and we know your platform is linux.
Kestrel address binding errors in azure app service
Remove .UseUrls(), and re-deploy your webapp.
In my case, i was using the azure sql database so changing the connection string of database to use tcp protocol and 1433 as port, resolved this problem.
e-g
Server=tcp:<ServerName>.database.windows.net,1433;Initial Catalog=<DatabaseName>

Why do I get CORS errors even though I'm allowing all origins?

So I 've made a web app using Vue, and I'm using ASP.NET Web App (.NET 5) for the backend.
When I run the Web API locally on localhost:44393 it works just great making POST & GET requests from the client that's running locally.
I then go to click "Publish" to send the files over to where I'm hosting.
At this point I change the URL that the client uses to make requests to https://api.mywebsite.com which is the same website as the one that was running locally since I published it now.
(it makes these requests using fetch so it would be fetch("https://api.mywebsite.com/TheController/AddServer" for instance)
This is where it gets weird because when I make a post request to register or sign in, it works just fine, but as soon as I go to "Add post" which is a form that posts to a different endpoint on the API, I get this error.
Access to fetch at 'https://api.mywebsite.com/TheController/AddPost'
from origin 'https://mywebsite.com' has been blocked by CORS
policy: No 'Access-Control-Allow-Origin' header is present on the
requested resource. If an opaque response serves your needs, set the
request's mode to 'no-cors' to fetch the resource with CORS disabled.
And that doesn't happen when I run the web API locally. Why is it that it only occurs after I publish the files to my host and use the actual domain?
(I tried making the same request from the client when it's running locally too but it gives the exact same exception)
I switched out the domain name in the question to mywebsite.com because I don't want to share it.
Here is my ConfigurationServices
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("https://mywebsite.com",
"http://localhost:8080",
"https://mywebsite.com/add")
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
...
And the Configure
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "mcraftserverapi v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
});
}
you have to remove
builder.WithOrigins("https://mywebsite.com",
"http://localhost:8080"
)
or
.AllowAnyOrigin()
you can't use them together

ASP.NET Core AWS Serverless and CORS

I'm using Visual Studio to publish an ASP.NET Core 2.1 app to AWS Lambda (serverless). No matter what I've tried I cannot get CORS to work.
All I really want to do is add the header access-control-allow-origin globally to my web app.
Has anyone ever successfully added headers to an ASP.NET Core 2.1 Serverless app?
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// AddCors must be before AddMvc
services.AddCors();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// UseCors must be before UseMvc
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
// Also tried this
// app.UseCors(
// o => o.WithOrigins("http://example.com").AllowAnyMethod()
//);
app.UseMvc();
}
No CORS headers are added to my pages. I'm using Chrome dev tools to inspect my headers. I should see them on the homepage (for example) correct?
Any ideas? I'm dyin over here. Thanks!
EDIT
This application only uses API Gateway, Lambda and a few other services. It's great because I'm only charged when someone hits my app. There are no hourly charges. No EC2 or ELB which is amazing.
Also, I almost added this to my original post. The article #sturcotte06 references has a gotcha.
The API Gateway (automatically generated) uses the ANY method in a proxy integration. The above article says this...
Important
When applying the above instructions to the ANY method in a proxy integration, any applicable CORS headers will not be set. Instead, your backend must return the applicable CORS headers, such as Access-Control-Allow-Origin.
Ugh! So it's saying I must do this on the backend (Startup.cs right?) which is exactly what seems to get ignored when published.
For whatever reason app.UseCors does not work in my scenario. However, app.Use does...
app.Use((context, next) =>
{
context.Response.Headers["Access-Control-Allow-Origin"] = "https://example.com";
return next.Invoke();
});
app.UseMvc();

Categories