I am trying to get CORS to work with a new WebAPI project. The project is just the default WebAPI template (i.e. has MVC and WebAPI references) using ActiveDirectoryBearerAuthentication.
Whenever I try and make a request to my API I am met with the following error:
XMLHttpRequest cannot load https://localhost:44385/api/values. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://localhost:44369' is therefore not allowed access.
I have installed Microsoft.Owin.Cors, and Microsoft.AspNet.WebApi.Cors.
My WebApiConfig is this:
public static void Register(HttpConfiguration config)
{
config.EnableCors();
....
My Startup.Auth is this:
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
....
Solutions around the net say to add:
<customHeaders>
<!-- Adding the following custom HttpHeader will help prevent CORS from stopping the Request-->
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
to the web.config. However, doing this just allows everything regardless of whether Microsoft.AspNet.WebApi.Cors is installed, enabled, or not.
To allow only a single domain you can do the following:
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
<clear />
<add name="Access-Control-Allow-Origin" value="http://www.myalloweddomain.com" />
</customHeaders>
</httpProtocol>
</system.webServer>
However, that's only allowed for a single domain. If you try to add an additional add node your site won't load. If you want to allow multiple domains, then you need to try one of the solutions listed here.
Things to check:
Owin kicks in on IIS (make sure you're including Microsoft.Owin.Host.SystemWeb)
Check that IIS doesn't hijack your request IIS hijacks CORS Preflight OPTIONS request
Use fiddler to fire OPTION request directly to specified url (sometimes the PREFLIGHT request just mask 500 returned by server) - browsers aren't very good in handling that
Put:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, HEAD, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
</customHeaders>
</httpProtocol>
in the Web Config, this literally covers everything and will let through everything according to the "*" wildcard. If you want concrete domains to be whitelisted you put them into:
<add name="Access-Control-Allow-Origin" value="*" />
Enabling you can do either through global configuration as you have been doing or instead with an attribute:
[EnableCors(origins: "*", headers: "*", methods: "*")]
On the relevant controller. Its one of the two, if you use both options it will choke.
Also you can write your own attribute which can handle loading of origins, headers and methods from a web.config appSettings or from a database by overriding EnableCors attribute if you prefer but that is already beyond the scope of your question I think.
Related
I have an Angular page which is making use of an Entity Framework powered ASP.NET server. Both Angular and ASP.NET applications run on different local addresses. To prevent CORS errors, I have configured some settings at the server side.
At the ASP.NET side, in WebApiConfig.cs I have enabled all of the access permissions from the Angular local address with this;
config.EnableCors(new EnableCorsAttribute("http://localhost:4200", headers: "*", methods: "*"));
However, when I trying to Edit a value from the Angular page, I am still having the CORS error.
Access to XMLHttpRequest at 'http://localhost:62677/Assets/Edit/177738ba-16cd-4b08-b339-974f0547e626' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
Inserting a new value to the database or getting all of the values from the database is working without the CORS error but editing an existing value gives an error.
I tried to add a break-point at the above code in WebApiConfig.cs and debug it, however, line of code is never reached.
Any help is appreciated, thanks
Addition: Also I have the following configurations in my Web.config file;
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
New ERROR after implementing Shyam Vemula's solution:
Access to XMLHttpRequest at 'http://localhost:62677/Assets/Edit/177738ba-16cd-4b08-b339-974f0547e626' from origin 'http://localhost:4200' has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.
Try this one. Add the following in Global.asmx
void Application_BeginRequest(object sender, EventArgs e)
{
var context = HttpContext.Current;
var response = context.Response;
// enable CORS
response.AddHeader("Access-Control-Allow-Origin", "*");
if (context.Request.HttpMethod == "OPTIONS")
{
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS");
response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
response.End();
}
}
and Remove this from Web.config file
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
I am running a WEB API project locally through Visual studio, on port 49374.
I am then running an MVC project locally through VS, on port 57062.
I am trying to call an API in my WEB API project (49374), from the MVC project(57062), but am getting a 401.2 response, see below:
When I call the API directly from the browser, it works fine.
CORS is setup in the Web API Web config as follows:
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost:57062" />
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, DELETE" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
<add name="Access-Control-Allow-Credentials" value="true" />
<!--<add name="Access-Control-Allow-Credential-Header" value="true"/>-->
</customHeaders>
</httpProtocol>
and the project has the following settings on VS:
I am out of ideas as to what the problem could be - can anyone suggest anything?
I have encountered the same probleme. IIS Express does not seem to use the custom headers in the web.config.
I fixed it by adding in the global.asax.cs :
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.Request.Headers.AllKeys.Contains("Origin"))
{
Context.Response.AddHeader("Access-Control-Allow-Origin", "http://localhost:57062");
Context.Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
Context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
Context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
if (Context.Request.HttpMethod == "OPTIONS") Context.Response.End();
}
}
I have a C# asp.net application.It was sent to security assessment and below were the risks.
-Missing "Content-Security-Policy" header
-Missing "X-Content-Type-Options" header
-Missing "X-XSS-Protection" header
-It was observed that server banner is getting disclosed in HTTP response.
-It was observed that service version is getting disclosed in HTTP response.
I have the below code in the web.cofig file
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By"/>
<add name="X-Frame-Options" value="DENY"/>
<add name="X-XSS-Protection" value="1; mode=block"/>
<add name="X-Content-Type-Options" value="nosniff "/>
</customHeaders>
</httpProtocol>
I thought this will add the headers. But the security team says the issue is not fixed. Is there any alternate for this.And for the Banner disclosure, I don't have access to server. can I fix this within the application.
After research I found this: Inside Global.asax I have this code:
protected void Application_PreSendRequestHeaders()
{
// Response.Headers.Remove("Server");
Response.Headers.Set("Server", "My httpd server");
Response.Headers.Remove("X-AspNet-Version");
Response.Headers.Remove("X-AspNetMvc-Version");
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
var app = sender as HttpApplication;
if (app != null && app.Context != null)
{
app.Context.Response.Headers.Remove("Server");
}
}
Is this the correct fix. Please help
Adding and removing headers during Application_BeginRequest always leads to headaches with your server complaining about not being able to do things after headers are set.
Typically "X-AspNet-Version" and "X-AspNetMvc-Version" are IIS custom headers and removing them depends on the verion of IIS you are using.
With new versions of IIS you can set it in Web.Config:
<system.web>
<httpRuntime enableVersionHeader="false" />
</system.web>
In older version you need to use IIS manager (see https://www.google.com/search?q=iis+remove++X-AspNet-Version&ie=utf-8&oe=utf-8):
You can remove the MVC header in app_start in Global.asax
MvcHandler.DisableMvcResponseHeader = true;
Your web.config should work fine:
<add name="X-Frame-Options" value="DENY"/>
<add name="X-XSS-Protection" value="1; mode=block"/>
<add name="X-Content-Type-Options" value="nosniff "/>
If not, Application_PreSendRequestHeaders is an appropriate place to add or remove headers well.
HttpContext.Current.Response.Headers.Add("X-Frame-Options", "DENY");
HttpContext.Current.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
HttpContext.Current.Response.Headers.Add("X-Content-Type-Options", "nosniff");
HttpContext.Current.Response.Headers.Remove("Server");
You can use the web developer console on your web browser (usually opened by hitting F12) and click on the network tab to see what headers the server is sending.
Ensure you add the httpProtocol in the system.webServer as shown below:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="DENY" />
<add name="X-Xss-Protection" value="1; mode=block" />
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
</system.webServer>
To remove the "server" header, add the code below in your Global.asax file
protected void Application_PreSendRequestHeaders()
{
Response.Headers.Remove("Server");
}
You can add any header globally using web.config e.g.
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
<add name="Cache-Control" value="no-store" />
<add name="X-XSS-Protection" value="1; mode=block" />
<add name="X-Content-Type-Options" value="nosniff" />
<add name="Strict-Transport-Security" value="max-age=31536000" />
</customHeaders>
</httpProtocol>
</system.webServer>
Refer : Adding Custom Headers Globally
I'm getting the following error:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
when making the following request to my web api from my angular2 app:
return this.http.get("http://localhost/api/test", { headers })
.map(res => this.extractData(res))
.catch(this.handleError);
Some considerations:
I'm using Microsoft.Owin.Cors
Requests work fine when they don't include headers. This one includes headers for authentication purposes.
I can make the request using Chrome.
Microsoft.Owin.Cors is installed in the solution
app.UseCors(CorsOptions.AllowAll); is at the start of the configuration method of startup.cs
The following is included in the web.config file:
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionControllerv4.0" />
</handlers>
thanks!
I think the problem is that you don't configure preflight requests on the server side (for OPTIONS methods).
There are two kinds of requests with CORS:
Simple requests. This use case applies if we use HTTP GET, HEAD and POST methods. In the case of POST methods, only content types with the following values are supported: text/plain, application/x-www-form-urlencoded and multipart/form-data.
Preflighted requests. When the ‘simple requests’ use case doesn’t apply, a first request (with the HTTP OPTIONS method) is made to check what can be done in the context of cross-domain requests.
When adding headers, you switch from simple to preflight requests. So an OPTIONS request is executed under the hood before the target request.
See this article for more details:
http://restlet.com/blog/2015/12/15/understanding-and-using-cors/
add these lines to webapiconfig.cs file
var cors = new EnableCorsAttribute("", "", "*");
config.EnableCors(cors);
you can do one more thing in ApplicationOAuthProvider.cs add this line in GrantResourceOwnerCredentials method
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
I have this App where I would like to set my custom headers in the Web.Config, alas this is not always fool proof.
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="*" />
<add name="Access-Control-Allow-Headers" value="*" />
</customHeaders>
The above set and iterations of it such as
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="OPTIONS,GET,PUT,DELETE,POST" />
<add name="Access-Control-Allow-Headers" value="Authorization,Content-Type" />
</customHeaders>
has not worked worked for me in all scenario's. As of now this setting works in about 50% of the test machines and gives 405 Method Not Allowed in others.
The alternative is set this in WebApiConfig.cs and uncomment the custom headers in Web.config.
//Web API Cross origin requests - Enable
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
Why is there so much ambiguity in this and how do I know for sure where CORS will work all the time? I am really interested in setting CORS on Web.config only as I would like the flexibility of modifying it in the deployed version.
I believe that your 'random' issue occurs because you are not handling the preflight Options requests for PUT and Delete verbs.
For the two verbs mentioned above an extra request is generated, Options, to which Web API needs to respond in order to confirm that it is indeed configured to support CORS.
To handle this, all you need to do is send an empty response back. You can do this inside your actions, or you can do it globally like this:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
Response.Flush();
}
}
This extra check was added to ensure that old APIs that were designed to accept only GET and POST requests will not be exploited. Imagine sending a DELETE request to an API designed when this verb didn't exist. The outcome is unpredictable and the results might be dangerous.
Also, in web.config, you should specify the methods instead of using *
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
There is no ambiguity with CORS, you have a few cases that you need to think about
1- if you want to enable CORS for your Web APIs only use "Microsoft.AspNet.WebApi.Cors" library.
2- if you want to enable CORS for the whole website (including the Web APIs, SignalR, ..etc ) use "Microsoft.Owin.Cors" library.
using any library from the above 2 will definitely work and cors will be enabled, now if you want to configure the urls, you can do that from your database/config file, so when your application starts the url that you pass to the EnableCors for example can come from the database/config file, but the bottom line is to avoid adding any cors headers to the web.config.
To know to enable CORS for your Web API, you can have a look to my article here, which enables CORS for the Web APIs and use it from AngularJS client.
Hope that helps.
For anyone reading this, this may help.
Even with the following startup code
var cors = new EnableCorsAttribute("*", "*", "GET, POST, PUT, DELETE, OPTIONS");
config.EnableCors(cors);
I had to explcitly add the verbs to the Web Api action method:
[Route("sanity")]
[HttpOptions]
[HttpPost]
public List<PostImportView> Sanity(SanityFilter filter)
{
....
Pretty pointless and annoying