Showing posts with label cors. Show all posts
Showing posts with label cors. Show all posts

Wednesday, September 26, 2018

Accessing secure endpoint from WKWebView loaded from local files

Leave a Comment

So we are in development of an iPhone application (iOS 9+, not 8), where we are using WKWebView and local files to start the thing up. To get data into the app we are planning to use a secure service that will also handle authentication, and were thinking that CORS was the way to do this.

Loading files from the file system, however, sets the origin in the HTTP request to null, which is not allowed when we also want to send cookies (for authentication).

So my question(s):

  • Can we set an origin in WKWebView to overwrite the null with something like https://acme.server.net?
  • What are other people (you) doing?
  • Should we consider doing something else other than CORS? (JSONP is not an option).

1 Answers

Answers 1

You can create a local webserver on the iPhone and load your files from that. This way origin will not be null and you can use CORS to connect to your server.

I have found GCDWebServer to be easy to work with.

Personally I would rather use HTML5 AppCache or ServiceWorkers to create a local application cache without the need for CORS, but WKWebView does not support these and to my knowledge you are forced to use the webserver approach

Read More

Thursday, September 20, 2018

Clients are unable to connect to server during selenium tests

Leave a Comment

I'm working on selenium tests (written in C# using the chrome webdriver) for a javascript web app that uses a backend server running on WebApi 5.2.4. It is CORS enabled with very permissive settingss:

namespace SealingService {     public static class WebApiConfig     {         public static void Register(HttpConfiguration config)         {             // Web API configuration and services              var cors = new EnableCorsAttribute("*", "*", "*");             config.EnableCors(cors);              // etc...         }     } } 

Normally everything works as expected. But on some machines when the server is started by the test scripts the client encounters CORS errors on every request. The chrome dev console shows the standard Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. message. The server logs show that the OPTION requests are reaching it, and it's sending a response.

When I try to access any of the API routes manually, the server returns the generic ASP.NET 404 page. This makes me think that our CORS configuration actually could be working correctly, but the server is not being started/configured correctly by our test script, so the routes are not being registered. Thus, all API routes are returning the 404 page, which is obviously not CORS enabled.

This is the applicationhost.config used by IIS during the tests. This is how the server is started by the test script:

public static Process StartIIS(string siteName) {     return Process.Start(@"C:\Program Files (x86)\IIS Express\iisexpress.exe", $"/site:{siteName} /config:{_applicationHostConfigFilePath}"); } 

The errors only occur on some machines, and we can't figure out what is configured differently between them. I've tried using Chrome's --disable-web-security flag but it doesn't seem to make any difference.

2 Answers

Answers 1

You can usually solve pre-flight errors with a change to your web.config:

<system.webServer>      ...  <httpProtocol>     <customHeaders>         <add name="Access-Control-Allow-Origin" value="*" />         <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept, Cache-Control" />         <add name="Access-Control-Allow-Credentials" value="true" />         <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />     </customHeaders> </httpProtocol> </system.webServer> 

Or via code in a custom handler with something like:

if (request.Headers.Contains("Origin") && request.Method.Method == "OPTIONS") {     var response = new HttpResponseMessage();     response.StatusCode = HttpStatusCode.OK;     response.Headers.Add("Access-Control-Allow-Origin", "*");     response.Headers.Add("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization");            response.Headers.Add("Access-Control-Allow-Methods", "DELETE, POST, PUT, OPTIONS, GET"); } 

If it works you can then try refining things by e.g. changing Access-Control-Allow-Origin to just your front-ends address.

Answers 2

Assuming you are using windows OS. If yes then, did you allow your application to bypass windows firewall..? ex: if you have a application running on localhost:9000, then you need to make sure windows firewall has rules to allow port 9000.

Hope, this resolves your issue.

Read More

Wednesday, August 8, 2018

How and why is Apache intercepting some CORS requests to Rails?

Leave a Comment

Before Chrome makes a cross-domain AJAX call it makes an OPTIONS check like this:

curl \ 'https://fubar.com/users/sign_in' \ -X OPTIONS \ -H 'Access-Control-Request-Method: POST' \ -H 'Origin: http://snafu.com' \ -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36' \ -H 'Access-Control-Request-Headers: content-type' \ --compressed \ --insecure \ --verbose 

(I added --insecure and --verbose for testing.)

I can see this request in the Apache logs but it doesn't get to Rails.

127.0.0.1 - - [27/Jul/2018:09:22:44 -0400] "OPTIONS /users/sign_in HTTP/1.1" 200 - 

If I remove either the Access-Control-Request-Method or Origin headers then it does pass the request to Rails.

Something about the combination of these two headers seems to be causing Apache to handle the request itself and not give Rails a chance to process it.

I am not setting any headers or defining any rewrite rules in the Apache config; it's basically a vanilla install.

I'm not able to find any documentation or configurations explaining why this would be happening and how to prevent it.

1 Answers

Answers 1

1) OPTIONS HTTP call at 'https://fubar.com/users/sign_in' performed from chrome browser with request headers 'Access-Control-Request-Method: POST' and 'Origin: http://snafu.com'

2) the server at 'https://fubar.com/users/sign_in' receives the request

STEP 1

The routing is handles from either nginx or apache webserver which will first apply their own config rules. This settings are included in the file inside /etc/apache2 or /etc/nginx

For example with nginx you can define rules to add_header to the http response or settings to redirect to another url

for example

add_header "Access-Control-Allow-Origin: '*'" 

this will add the header "Access-Control-Allow-Origin: '*'" to all responses. If for example you apply this response to all OPTIONS requests, then all subsequent http request will be whitelisted from any http origin

STEP 2

once the nginx/apache redirection rules are applied, the rails router receives the request and redirects to your controller.

Here you can still add any header you want inside the controller, you can redirect OPTIONS request to a specific controller action, which can add a specific header, be careful to not add twice the same header as that can cause issues.

In this action you can rewrite the Access-Control-Allow-Origin header in the response from the OPTIONS request to whitelist only specific origin domains (you just need to write a routing rule which is applied only to OPTIONS requests)

The origin domain is written in the header of the request

request headers 'Access-Control-Request-Method: POST' and 'Origin: http://snafu.com'

Read More

Wednesday, July 18, 2018

Firefox does not keep cookies sent by cross-domain even with all CORS allow

Leave a Comment

I experience a problem with Firefox while Chrome works fine. Here is the situation:

  • Website1.com returns an html page in SSL.
  • This page makes a request to Website2.com in SSL either via img tag or XMLHttpRequest (same issue).
  • Website2.com returns a cookie to be set for itself
  • Firefox ignores this cookie. It is never stored even though it shows in the console.
  • The console doesn't complain about anything.

Client sends:

Origin: https://website1.com 

Server returns:

Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: * Access-Control-Allow-Methods: * Access-Control-Allow-Origin: https://website1.com Access-Control-Expose-Headers: * Set-Cookie: ... 

What else am I missing about CORS?

Thanks!

1 Answers

Answers 1

Access-Control-Allow-Credentials: true 

Is a special flag. If one side declares it other also have to declare it or else it's security failure and browser will not accept data.

So add the same header to client request. (Or if you control server, consider doing without cookies and passing data with other mechanism)

Read More

Monday, December 11, 2017

Can't rewrite Access_Control_Allow_Origin

Leave a Comment

I have one site that works like a cdn for my other sites.

I have added following to Web.config

<httpProtocol>   <customHeaders>     <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />     <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS,PUT,DELETE" />     <add name="Arr-Disable-Session-Affinity" value="True" />   </customHeaders> </httpProtocol>  <rewrite>   <outboundRules>     <clear />     <rule name="AddCrossDomainHeader">       <match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />       <conditions logicalGrouping="MatchAll" trackAllCaptures="true">         <add input="{HTTP_ORIGIN}" pattern="(http(s)?://((.+\.)?[a-zA-Z0-9-]*\.ap\.dk|(.+\.)?localhost\:[0-9]*))" />       </conditions>       <action type="Rewrite" value="{C:0}" />     </rule>   </outboundRules> </rewrite> 

I was inspired by answer #2 in here Access-control-allow-origin with multiple domains

But the rewrite of Access_Control_Allow_Origin does only work on localhost. On live site, it is not rewritten and then I get an error like this:

Failed to load https://aptestlogin.ap.dk//Widgets/Footer.html: The 'Access-Control-Allow-Origin' header has a value 'https://aptestproject.ap.dk' that is not equal to the supplied origin. Origin 'https://aptestcompany.ap.dk' is therefore not allowed access

In order to load this 'Footer.html' I'll have to clear cache in my brower, and repeat this if I open a another site that calls for this.

4 Answers

Answers 1

Try check regex pattern. Maybe forward slashes is unescaped // or something else.

https?:\/\/((.+\.)?[a-zA-Z0-9-]*\.ap\.dk|(.+\.)?localhost(\:[0-9]*)?) 

Answers 2

https://enable-cors.org/server_aspnet.html

Above will provide a solution for your matter.

Answers 3

Can you try like this

Install-Package Microsoft.AspNet.WebApi.Cors

Open the file App_Start/WebApiConfig.cs.

public static void Register(HttpConfiguration config)         {              config.EnableCors(); //add this           } 

Answers 4

Change

<match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" /> 

to

<match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern="*" /> 
Read More

Friday, November 3, 2017

Why does dynamically generating an SVG using HTMLObjectElement lead to a Cross-Origin error?

Leave a Comment

Consider the following JavaScript snippet:

const app = document.getElementById('root'); const svg = `<svg version="1.1" id="Layer_1"...`; const obj = document.createElement('object');  obj.setAttribute('type', 'image/svg+xml'); obj.setAttribute('data', `data:image/svg+xml; base64,${btoa(svg)}`);  app.appendChild(obj);  setTimeout(() => {   console.log(obj.contentDocument.querySelector('svg')); }, 1500); 

(See this JSFiddle for a full example)

When this runs, the following error is given in the console (Google Chrome):

Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLObjectElement': Blocked a frame with origin "https://fiddle.jshell.net" from accessing a cross-origin frame. at setTimeout (https://fiddle.jshell.net/_display:77:19)

With that in mind;

  1. Why is this considered a cross-origin request when trying to access the contentDocument of the object that has been created entirely dynamically, with no external resources?

  2. Is there a way to generate SVGs dynamically in this way, without offending the browsers cross-origin policy?

2 Answers

Answers 1

The problem here is that data: URLs are treated as having a unique origin that differs from the origin of the context that created the embedded data: context:

Note: Data URLs are treated as unique opaque origins by modern browsers, rather than inheriting the origin of the settings object responsible for the navigation.

The WHATWG specification describes how content documents are accessed, which includes a cross origin check. The WHATWG same-origin comparison will never treat a traditional scheme-host-port "tuple" origin as equal to an "opaque" data: origin.

Instead, use Blob with URL.createObjectURL to generate a same-origin temporary URL whose contents will be readable by the outer environment:

var svgUrl = URL.createObjectURL(new Blob([svg], {'type':'image/svg+xml'})); obj.setAttribute('data', svgUrl); 

I don't know the security reason why this approach is allowed while a raw data: URL is not, but it does appear to work. (I guess because the generated URL is readable only by the origin that generated it, whereas a data: URL doesn't know how to be readable only by the original of its originating context.)

Note also that some versions of Internet Explorer support createObjectURL but erroneously treat the generated URLs as having a null origin, which would cause this approach to fail.

Other options are:

  1. Don't use a data: URL and instead serve the SVG content from the same origin as your page that creates the <object> element.

  2. Ditch the <object> and contentDocument altogether and use an inline <svg> element instead (fiddle):

    const obj = document.createElement('div'); obj.innerHTML = svg; app.appendChild(obj); setTimeout(() => {   console.log(obj.querySelector('svg')); }, 1500); 

    Most browsers support inline <svg> elements (notably, IE 9.0+; other browsers much earlier). This means you can do

    <div>     <svg>         ...     </svg> </div> 

    and it will just render the SVG document inside the <div> as you would expect.

  3. Depending on what you want to do with the SVG, you can load it into a DOMParser and do DOM exploration/manipulation within the parser.

    var oParser = new DOMParser(); var svgDOM = oParser.parseFromString(svg, "text/xml"); console.log(svgDOM.documentElement.querySelector('path')); svgDOM.documentElement.querySelector('path').remove(); 

    But the DOM model will be separate from the SVG rendered in the <object>. To change the <object>, you need to serialize the parsed DOM structure and re-push it to the the data property:

    var oSerializer = new XMLSerializer(); var sXML = oSerializer.serializeToString(svgDOM); obj.setAttribute('data', `data:image/svg+xml; base64,${btoa(sXML)}`); 

    This doesn't seem super performant, because it needs the browser to re-parse a brand-new SVG document, but it will get around the security restrictions.

    Think of the <object> as a one-way black hole that can receive SVG information to render, but will not expose any information back. This isn't an informatic problem, though, since you have the information that you just fed into the <object>: there's nothing that contentDocument can tell you that you don't already know.

    However, if you want to make components within the SVG interactive by attaching listeners to components within the SVG structure that execute code on your main page, I don't think this approach will work. The separation between an <object> and its surrounding page has the same kind of embedding relationship as an <iframe>.

Answers 2

because the object tag defines an embedded object within the HTML document, it's not part of the document itself, and therefore must respect the CORS like a frame

Same-origin policy

here clearly states that the content of the object tag is considered an external resource

The HTML element represents an external resource, which can be treated as an image, a nested browsing context, or a resource to be handled by a plugin.

Read More

Wednesday, November 1, 2017

CORS Options Preflight Hanging

Leave a Comment

I have a ASP Web API project that is being hosted over SSL. I have another ASP MVC project that makes use of the API. While debugging, I am seeing behavior where the OPTIONS requests are hanging often (but not always) and preventing the other calls from proceeding.

In the Chrome debugger, these are just shown as 'Pending'. If launch Fiddler, everything works fine. I see no errors at all, things just hang. This fails before it hits the authorization code, so I can't even set any breakpoints.

Could this be a certificate problem? Firewall?

1 Answers

Answers 1

Could you try this: adding following node in web.config.

<system.webServer>     <handlers>          <!-- your other handlers -->          <remove name="OPTIONSVerbHandler" />     </handlers> </system.webServer> 
Read More

Saturday, October 21, 2017

How to enable CORS for angularjs project running using gulp serve

Leave a Comment

I have an Angularjs project. I build it using gulp serve. I,m using ckeditor to uploade a file on remote server and i get this error:

Permission denied to access property "CKEDITOR" on cross-origin object 

my gulp server.js file is as below

'use strict';   var path = require('path');  var gulp = require('gulp');  var conf = require('./conf');  var browserSync = require('browser-sync');  var browserSyncSpa = require('browser-sync-spa');  var util = require('util');  var proxyMiddleware = require('http-proxy-middleware');   function  browserSyncInit(baseDir, browser) {  browser = browser === undefined ? 'default' : browser;  var routes = null;  if(baseDir === conf.paths.src || (util.isArray(baseDir) &&   baseDir.indexOf(conf.paths.src) !== -1)) {     routes = {       '/bower_components': 'bower_components'     };  }  var server = {    baseDir: baseDir,    middleware: function (req, res, next) {    res.setHeader('Access-Control-Allow-Origin', '*');    res.setHeader('Access-Control-Allow-Headers', '*');    res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS, POST, PUT');    res.setHeader('Access-Control-Allow-Credentials', 'GET,OPTIONS, POST, PUT');   next(); }, routes: routes };   browserSync.instance = browserSync.init({    startPath: '/',    server: server,    browser: browser,    ghostMode: false  }); }   browserSync.use(browserSyncSpa({     selector: '[ng-app]'// Only needed for angular apps   }));   gulp.task('serve', ['watch'], function () {     browserSyncInit([path.join(conf.paths.tmp, '/serve'), conf.paths.src]);     connect.server(server);  }); gulp.task('serve:dist', ['build'], function () {     browserSyncInit(conf.paths.dist);     connect.server(server);  });  gulp.task('serve:e2e', ['inject'], function () {  browserSyncInit([conf.paths.tmp + '/serve', conf.paths.src], []);  connect.server(server);  });  gulp.task('serve:e2e-dist', ['build'], function () {    browserSyncInit(conf.paths.dist, []);    connect.server(server);   }); 

but "Access-Control-Allow-Origin', '*'" did not set in header and i still get that error!

when page load Http response and request headers are as below:

response headers:

Access-Control-Allow-Origin * Access-Control-Allow-Headers    * Access-Control-Allow-Methods    GET,OPTIONS, POST, PUT Access-Control-Allow-Credentials    true Accept-Ranges   bytes Cache-Control   public, max-age=0 Last-Modified   Wed, 11 Oct 2017 05:56:16 GMT ETag    W/"91a-15f0a01475b" Date    Sat, 14 Oct 2017 05:03:02 GMT Connection  keep-alive 

request headers :

Host    localhost:3000 User-Agent  Mozilla/5.0 (X11; Ubuntu; Linu…) Gecko/20100101 Firefox/56.0 Accept  application/json, text/plain, */* Accept-Language en-US,en;q=0.5 Accept-Encoding gzip, deflate Referer http://localhost:3000/ Cookie  language=fa; io=qkk4hCbXxaQ78a…FxfKICyH9dwHZOr5m2aJJ89Z0DS2H Connection  keep-alive If-Modified-Since   Wed, 11 Oct 2017 05:56:16 GMT If-None-Match   W/"91a-15f0a01475b" 

Thanks :)

I also used CORS Everywhere Firefox add-on. but it did not work

0 Answers

Read More

Wednesday, October 11, 2017

Super slow preflight OPTIONS in Chrome only

Leave a Comment

I've been struggling recently with a super-weird problem only happening in Chrome: as my API (NodeJS) is on a different subdomain, I need to use CORS to reach it from my front-end (EmberJS).

It's working pretty well but I'm very frequently (95% of the time) having very very slow OPTIONS queries, delaying any API calls by about 3 seconds.

2 requests, OPTIONS takes 3 seconds

Most of this time is spent downloading an empty content:

Downloading an empty content takes 3 seconds

It gets even weirder when I'm trying this on another website we made using a similar architecture, experiencing the exact same problem.

A few other things I tried:

  • I've been trying this with Firefox and Safari, and didn't get any delay.
  • I've been trying this locally or in production, experimenting the same delay.
  • I've been trying this with incognito mode (no extensions), and I have the exact same problem.

We're using on the back-end NodeJS with the CORS package.

Now, I have no idea if the problem is on either Chrome 60, NodeJS, the CORS package or EmberJS + jQuery.

Anyone experienced this too?

0 Answers

Read More

Sunday, September 17, 2017

Determine if ajax call failed due to insecure response or connection refused

Leave a Comment

I've been doing a lot of research and could not find a way to handle this. I'm trying to perform a jQuery ajax call from an https server to a locahost https server running jetty with a custom self signed certificate. My problem is that I cannot determine whether the response is a connection refused or a insecure response (due to the lack of the certificate acceptance). Is there a way to determine the difference between both scenarios? The responseText, and statusCode are always the same in both cases, even though in the chrome console I can see a difference:

net::ERR_INSECURE_RESPONSE net::ERR_CONNECTION_REFUSED 

responseText is always "" and statusCode is always "0" for both cases.

My question is, how can I determine if a jQuery ajax call failed due to ERR_INSECURE_RESPONSE or due to ERR_CONNECTION_REFUSED?

Once the certificate is accepted everything works fine, but I want to know whether the localhost server is shut down, or its up and running but the certificate has not yet been accepted.

$.ajax({     type: 'GET',     url: "https://localhost/custom/server/",     dataType: "json",     async: true,     success: function (response) {         //do something     },     error: function (xhr, textStatus, errorThrown) {         console.log(xhr, textStatus, errorThrown); //always the same for refused and insecure responses.     } }); 

enter image description here

Even performing manually the request I get the same result:

var request = new XMLHttpRequest(); request.open('GET', "https://localhost/custom/server/", true); request.onload = function () {     console.log(request.responseText); }; request.onerror = function () {     console.log(request.responseText); }; request.send(); 

6 Answers

Answers 1

There is no way to differentiate it from newest Web Browsers.

W3C Specification:

The steps below describe what user agents must do for a simple cross-origin request:

Apply the make a request steps and observe the request rules below while making the request.

If the manual redirect flag is unset and the response has an HTTP status code of 301, 302, 303, 307, or 308 Apply the redirect steps.

If the end user cancels the request Apply the abort steps.

If there is a network error In case of DNS errors, TLS negotiation failure, or other type of network errors, apply the network error steps. Do not request any kind of end user interaction.

Note: This does not include HTTP responses that indicate some type of error, such as HTTP status code 410.

Otherwise Perform a resource sharing check. If it returns fail, apply the network error steps. Otherwise, if it returns pass, terminate this algorithm and set the cross-origin request status to success. Do not actually terminate the request.

As you can read, network errors does not include HTTP response that include errors, that is why you will get always 0 as status code, and "" as error.

Source


Note: The following examples were made using Google Chrome Version 43.0.2357.130 and against an environment that I've created to emulate OP one. Code to the set it up is at the bottom of the answer.


I though that an approach To work around this would be make a secondary request over HTTP instead of HTTPS as This answer but I've remembered that is not possible due that newer versions of browsers block mixed content.

That means that the Web Browser will not allow a request over HTTP if you are using HTTPS and vice versa.

This has been like this since few years ago but older Web Browser versions like Mozilla Firefox below it versions 23 allow it.

Evidence about it:

Making a HTTP request from HTTPS usign Web Broser console

var request = new XMLHttpRequest(); request.open('GET', "http://localhost:8001", true); request.onload = function () {     console.log(request.responseText); }; request.onerror = function () {     console.log(request.responseText); }; request.send(); 

will result in the following error:

Mixed Content: The page at 'https://localhost:8000/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://localhost:8001/'. This request has been blocked; the content must be served over HTTPS.

Same error will appear in the browser console if you try to do this in other ways as adding an Iframe.

<iframe src="http://localhost:8001"></iframe> 

Using Socket connection was also Posted as an answer, I was pretty sure that the result will be the same / similar but I've give it a try.

Trying to Open a socket connection from the Web Broswer using HTTPS to a non Secure socket endpoint will end in mixed content errors.

new WebSocket("ws://localhost:8001", "protocolOne"); 

1) Mixed Content: The page at 'https://localhost:8000/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://localhost:8001/'. This request has been blocked; this endpoint must be available over WSS.

2) Uncaught DOMException: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.

Then I've tried to connect to a wss endpoint too see If I could read some information about network connection errors:

var exampleSocket = new WebSocket("wss://localhost:8001", "protocolOne"); exampleSocket.onerror = function(e) {     console.log(e); } 

Executing snippet above with Server turned off results in:

WebSocket connection to 'wss://localhost:8001/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED

Executing snippet above with Server turned On

WebSocket connection to 'wss://localhost:8001/' failed: WebSocket opening handshake was canceled

But again, the error that the "onerror function" output to the console have not any tip to differentiate one error of the other.


Using a proxy as this answer suggest could work but only if the "target" server has public access.

This was not the case here, so trying to implement a proxy in this scenario will lead Us to the same problem.

Code to create Node.js HTTPS server:

I've created two Nodejs HTTPS servers, that use self signed certificates:

targetServer.js:

var https = require('https'); var fs = require('fs');  var options = {     key: fs.readFileSync('./certs2/key.pem'),     cert: fs.readFileSync('./certs2/key-cert.pem') };  https.createServer(options, function (req, res) {     res.setHeader('Access-Control-Allow-Origin', '*');     res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');     res.setHeader('Access-Control-Allow-Headers', 'Content-Type');     res.writeHead(200);     res.end("hello world\n"); }).listen(8001); 

applicationServer.js:

var https = require('https'); var fs = require('fs');  var options = {     key: fs.readFileSync('./certs/key.pem'),     cert: fs.readFileSync('./certs/key-cert.pem') };  https.createServer(options, function (req, res) {     res.writeHead(200);     res.end("hello world\n"); }).listen(8000); 

To make it work you need to have Nodejs Installed, Need to generate separated certificates for each server and store it in the folders certs and certs2 accordingly.

To Run it just execute node applicationServer.js and node targetServer.js in a terminal (ubuntu example).

Answers 2

As of now: There is no way to differentiate this event between browers. As the browsers do not provide an event for developers to access. (July 2015)

This answer merely seeks to provide ideas for a potential, albiet hacky and incomplete, solution.


Disclaimer: this answer is incomplete as it doesn't completely solve OP's issues (due to cross-origin policies). However the idea itself does has some merit that is further expanded upon by: @artur grzesiak here, using a proxy and ajax.


After quite a bit of research myself, there doesn't seem to be any form of error checking for the difference between connection refused and an insecure response, at least as far as javascript providing a response for the difference between the two.

The general consensus of my research being that SSL certificates are handled by the browser, so until a self-signed certificate is accepted by the user, the browser locks down all requests, including those for a status code. The browser could (if coded to) send back it's own status code for an insecure response, but that doesn't really help anything, and even then, you'd have issues with browser compatibility (chrome/firefox/IE having different standards... once again)

Since your original question was for checking the status of your server between being up versus having an unaccepted certificate, could you not make a standard HTTP request like so?

isUp = false; isAccepted = false;  var isUpRequest = new XMLHttpRequest(); isUpRequest.open('GET', "http://localhost/custom/server/", true); //note non-ssl port isUpRequest.onload = function() {     isUp = true;     var isAcceptedRequest = new XMLHttpRequest();     isAcceptedRequest.open('GET', "https://localhost/custom/server/", true); //note ssl port     isAcceptedRequest.onload = function() {         console.log("Server is up and certificate accepted");         isAccepted = true;     }     isAcceptedRequest.onerror = function() {         console.log("Server is up and certificate is not accepted");     }     isAcceptedRequest.send(); }; isUpRequest.onerror = function() {     console.log("Server is down"); }; isUpRequest.send(); 

Granted this does require an extra request to verify server connectivity, but it should get the job done by process of elimination. Still feels hacky though, and I'm not a big fan of the doubled request.

Answers 3

@Schultzie's answer is pretty close, but clearly http - in general - will not work from https in the browser environment.

What you can do though is to use an intermediate server (proxy) to make the request on your behalf. The proxy should allow either to forward http request from https origin or to load content from self-signed origins.

Having your own server with proper certificate is probably an overkill in your case -- as you could use this setting instead of the machine with self-signed certificate -- but there is a plenty of anonymous open proxy services out there.

So two approaches that come to my mind are:

  1. ajax request -- in such a case the proxy has to use appropriate CORS settings
  2. use of an iframe -- you load your script (probably wrapped in html) inside an iframe via the proxy. Once the script loaded it sends a message to its .parentWindow. If your window received a message you can be sure the server is running (or more precisely was running a fraction of second before).

If you are only interested in your local environment you can try to run chrome with --disable-web-security flag.


Another suggestion: did you try to load an image programatically to find out if more info is present there?

Answers 4

Check out jQuery.ajaxError() Taken reference from : jQuery AJAX Error Handling (HTTP Status Codes) It catches global Ajax errors which you can handle in any number of ways over HTTP or HTTPS:

if (jqXHR.status == 501) { //insecure response } else if (jqXHR.status == 102) { //connection refused } 

Answers 5

Unfortunately the present-day browser XHR API does not provide an explicit indication for when the browser refuses to connect due to an "insecure response", and also when it does not trust the website's HTTP/SSL certificate.

But there are ways around this problem.

One solution I came up with to determine when the browser does not trust the HTTP/SSL certificate, is to first detect if an XHR error has occurred (using the jQuery error() callback for instance), then check if the XHR call is to an 'https://' URL, and then check if the XHR readyState is 0, which means that the XHR connection has not even been opened (which is what happens when the browser does not like the certificate).

Here's the code where I do this: https://github.com/maratbn/RainbowPayPress/blob/e9e9472a36ced747a0f9e5ca9fa7d96959aeaf8a/rainbowpaypress/js/le_requirejs/public/model_info__transaction_details.js#L88

Answers 6

I don't think there's currently a way to detect these error messages, but a hack that you can do is to use a server like nginx in front of your application server, so that if the application server is down you'll get a bad gateway error from nginx with 502 status code which you can detect in JS. Otherwise, if the certificate is invalid you'll still get the same generic error with statusCode = 0.

Read More

Monday, July 3, 2017

Font not loading - CORS says header contains no Access Control but there is

Leave a Comment

The problem: I am using html generated from one site that is being pushed to another site (different domains). All is working well except the font (used mainly for icons) is not showing up. I am receiving a CORS error as described further below.

I have added the following code to my .htaccess file on the site where the fonts are stored that allows fonts to be access across any domain:

<FilesMatch ".(eot|ttf|otf|woff)">     Header set Access-Control-Allow-Origin "*" </FilesMatch> 

I checked the header using cUrl:

curl -I https://mywebsite.com/fonts/flatpack.woff?tzy7cr HTTP/1.1 200 OK Server: nginx Date: Fri, 23 Jun 2017 18:33:58 GMT Content-Type: text/plain Content-Length: 142020 Connection: keep-alive X-Accel-Version: 0.01 Last-Modified: Fri, 23 Jun 2017 17:49:02 GMT ETag: "1a474c-22ac4-552a4378235b7" Accept-Ranges: bytes X-Powered-By: PleskLin Access-Control-Allow-Origin: * 

The Access Origin response tells me that the font should be readable but I'm still getting this error from the requesting website:

Access to Font at https://mywebsite/fonts/flatpack.woff?tzy7cr' from origin 'http://anotherwebsite.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://anotherwebsite.com' is therefore not allowed access.

Thoughts or suggestions???

Edit: Here is a live link to a test page that fails to load the icon fonts.

2 Answers

Answers 1

Almost got it right:

Header add Access-Control-Allow-Origin "*" Header add Access-Control-Allow-Methods: "GET" 

You need to add the header not set. I'd also add the method to be sure.

Answers 2

Premium font purchased by some other website can be abused another site. That is the reason of complication at browser level coding. Image will not suffer such issue. Font related CORS is complicated by types of fonts, browsers and bugs. Unless you are using paid origin pull CDN or known font provider (free or paid), it is practical to serve font from own server for the sake of making sure that font loads on all browsers, all devices. It is worthy to read :

  1. official W3 doc about CORS,
  2. Mozilla doc,
  3. MaxCDN's guide,
  4. W3's CSS font doc,
  5. this old bug report
  6. this pull request

There are three options from the above resources for giving you a correct answer. You need to test from webpagetest dot org from different user agents & devices and try to watch the video of screenshot.

One :

SetEnvIf Origin "https?://(.*\.(mozilla|allizom)\.(com|org|net))" CORS=$0 Header set Access-Control-Allow-Origin %{CORS}e env=CORS  <FilesMatch "\.(ttf|woff|eot)$">     Header append vary "Origin"     ExpiresActive On     ExpiresDefault "access plus 1 year" </FilesMatch> 

Two (Single domain, HTTPS) :

<FilesMatch "\.(ttf|otf|eot|woff)$">         SetEnvIf Origin "^http(s)?://(.+\.)?anotherwebsite\.com$" AccessControlAllowOrigin=$0         Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin </FilesMatch> 

Three (Multiple domains) :

<FilesMatch "\.(ttf|otf|eot|woff)$">     <IfModule mod_headers.c>         SetEnvIf Origin "http(s)?://(www\.)?(anotherwebsite.com|cdn.anotherwebsite.com|blahblah.anotherwebsite.com)$" AccessControlAllowOrigin=$0         Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin     </IfModule> </FilesMatch> 

Also make sure that proper MIME types are present :

AddType application/vnd.ms-fontobject    .eot AddType application/x-font-opentype      .otf AddType image/svg+xml                    .svg AddType application/x-font-ttf           .ttf AddType application/font-woff            .woff AddType application/font-woff2           .woff2 

Make sure to run Apache configtest before restarting. You may need to activate some module.

Read More

Tuesday, May 16, 2017

CORS doesn't work despite headers set

Leave a Comment

I have an app where the client makes a multipart request from example.com to api.example.com through https with Nginx, then api uploads the file to Amazon S3.

It works on my machine but breaks when other people try it on a different network. Giving me this error:

[Error] Origin https://example.com is not allowed by Access-Control-Allow-Origin. [Error] Failed to load resource: Origin https://example.com is not allowed by Access-Control-Allow-Origin. (graphql, line 0) [Error] Fetch API cannot load https://api.example.com/graphql. Origin https://example.com is not allowed by Access-Control-Allow-Origin. 

I'm using the cors npm package on the API like this:

app.use(cors()); 

All of this is going through an Nginx reverse proxy on DigitalOcean. Here this is my Nginx config:

Individual server configs at /etc/nginx/conf.d/example.com.conf and /etc/nginx/conf.d/api.example.com.conf, almost identical, just the addresses and names different:

 server {         listen 443 ssl http2;         listen [::]:443 ssl http2;         server_name example.com;          ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;         ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;          include snippets/ssl-params.conf;          location / {             proxy_set_header X-Real-IP $remote_addr;             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;             proxy_set_header X-NginX-Proxy true;             proxy_pass http://localhost:3000/;             proxy_ssl_session_reuse off;             proxy_set_header Host $http_host;             proxy_cache_bypass $http_upgrade;             proxy_redirect off;         }     } 

It works perfectly fine when I use it on localhost on my computer but as soon as I put it on DigitalOcean I can't upload. And it only breaks on this multipart request when I'm uploading a file, other regular cors GET and POST requests work.

2 Answers

Answers 1

The problem turned out to be Nginx not accepting large files. Placing this in the location block of my nginx server config solved my issue: client_max_body_size 10M;

Answers 2

Issue is probably not with nginx since it's only a mobile issue. Try Using, instead of * for Access-Control-Allow-Origin you can use your origin as well.

app.use(function(req, res, next) {     res.header("Access-Control-Allow-Origin", "*");     res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");     res.header("Authorization", "Access-Control-Allow-Headers", "Origin","X-Requested-With", "Content-Type", "Accept");     next(); }); 

UPDATE

Try following if above does not work, this enables everything for the time being.

app.use(cors()); 
Read More

Thursday, March 16, 2017

Exposing POST Endpoint on Elastic Beanstalk

Leave a Comment

I have a Chrome extension that needs to send data to a separate application I have running on Elastic Beanstalk via POST request. The POST endpoint itself is working fine via http, as confirmed using cURL.

However, given I am posting JSON data from a non-origin domain, the AJAX POST request is performed via https. This is causing the POST request to timeout, both from the Chrome extension and from cURL. I've done some research on how to change the CORS settings on the nginx server on Elastic Beanstalk, but I don't really know what I'm doing and kinda grasping at straws. How can I enable CORS on ELB/nginx?

1 Answers

Answers 1

NGINX instance working on EB machines are just proxying the request to your application and passing back the response to the client. You can set CORS headers in your application and that's it.

Read More

Wednesday, March 1, 2017

Post as Option, Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header

Leave a Comment

XMLHttpRequest cannot load http://xxx.xxx. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 500.

I am trying to send a xml soap with ajax but gives me that error. I have tried many option but nothing seems to work, here is the code:

var soapMessage =                 '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://xxx.xxx/">'+                 '<soapenv:Header/>'+                 '<soapenv:Body>'+                    '<wsdl:test1>'+                       '<PUI>12345</PUI>'+                    '</wsdl:test1>'+                ' </soapenv:Body>'+              '</soapenv:Envelope>';              $.ajax({                 url: 'http://xxx.xxx',                  type: 'POST',                 dataType: 'xml',                  data: soapMessage,                  crossDomain: true,                 processData: false,                 contentType: 'text/xml; charset=\"utf-8\"',                 headers: {                     SOAPAction: "http://xxx.xxx"                 },                 success: function (msg, data) {                     alert(msg);                  },                 error: function (msg, data) {                     alert("Error");                 }             }); 

what am I doing wrong here? I send a POST action but it read it as OPTION. How to fix this?

I use Boomerang Rest and Soap Client to test this service and it gives me response correctly. When I use my own program as above it gives me XMLHttpRequest cannot load http://xxxxx" error. I am using apache tomcat 6.0 and using a Java web Application for the code

2 Answers

Answers 1

You’re doing that request cross-origin, so the server you’re making the request to must send an Access-Control-Allow-Origin response header to indicate it allows cross-origin requests.

See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS for more details.

For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. For example, XMLHttpRequest and Fetch follow the same-origin policy. So, a web application using XMLHttpRequest or Fetch could only make HTTP requests to its own domain.

And the reason an OPTIONS request happens is that when you send a cross-origin request with a Content-Type header that has a value other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, your browser first does a CORS preflight check.

Your request sends Content-Type: text/xml; charset="utf-8", so that causes a preflight.

As far as workarounds if the server you’re sending the request to is not one that you control and can configure, you can use an open reverse proxy like https://cors-anywhere.herokuapp.com/.

The way it works is that instead of sending your request directly to http://xxx.xxx, you send it instead to https://cors-anywhere.herokuapp.com/http://xxx.xxx and that proxies your request and responds to the browser with Access-Control-Allow-Origin and other expected CORS headers.

Of course you need to understand that if your request contains any confidential information, you’d be exposing it to the maintainers of cors-anywhere.herokuapp.com if they log data for requests.

Answers 2

My work around for this was to write a filter that appends the origin as an accepted origin onto any options request and added it to whatever servlet that would need to accept such requests. Here's my implementation:

public class CorsFilter implements Filter {      private static List<String> validServers = Arrays.asList([you need to fill this in with whatever sites you want to allow access]);      @Override     public void init(FilterConfig filterConfig) throws ServletException {     }      @Override     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {         if (servletRequest instanceof HttpServletRequest) {             HttpServletRequest request = (HttpServletRequest) servletRequest;             HttpServletResponse response = (HttpServletResponse) servletResponse;             String origin = request.getHeader("Origin");             if (StringUtils.isNotBlank(origin)) { //this is a cors request                 boolean hasPrefix = origin.contains("/");                 boolean hasPort = origin.contains(":");                 String serverAlias = origin.substring(hasPrefix ? origin.lastIndexOf("/") + 1 : 0, hasPort ? origin.lastIndexOf(":") : origin.length());                 if (validServers.contains(serverAlias)) {                     response.setHeader("Access-Control-Allow-Credentials", "true");                     response.setHeader("Access-Control-Allow-Methods", "OPTIONS, POST, GET, PUT, DELETE");                     response.setHeader("Access-Control-Allow-Origin", origin);                     response.setHeader("Access-Control-Allow-Headers", "Content-Type");                     //credentials are not sent on options requests, kick out here so that the access control headers and nothing else can be returned                     if ("OPTIONS".equals(request.getMethod())) {                         response.setStatus(200);                         return;                     }                 } else {                     response.sendError(HttpStatus.SC_FORBIDDEN);                     response.flushBuffer();                     return;                 }             }         }          filterChain.doFilter(servletRequest, servletResponse);     }       @Override     public void destroy() {     } } 
Read More

Monday, September 26, 2016

Referrer and origin preflight request headers in Safari are not changing when user navigates

Leave a Comment

I have two web pages hosted on a.example.com and b.example. Each web page is including a script with a <script> tag, hosted on another domain and served with correct CORS headers.

At a certain point, user navigates from a.example.com to b.example.com.

Safari has here a strange behavior: the referrer and origin headers in preflight request are filled with a.example.com, making the server sending a bad value in Access-Control-Allow-Origin (and so the script can't be executed).

Is there a way to force Safari browser to send correct origin header in that kind of scenario ?

1 Answers

Answers 1

Does the cache policy for the script include Vary: Origin?

Respectively is there actually a second request after navigating to b.example.com?

If not, there is a chance that Safari is actually serving the script from cache - despite the Access-Control-Allow-Origin policy forbidding it to access the resource. Which is a conforming behavior, if the cache policy isn't configured correctly.

Read More

Wednesday, September 14, 2016

Ionic 2 / Angular 2 / CORS: HTTP Headers not being sent with request

Leave a Comment

I'm working on a project using Ionic 2 (2.0.0-beta.10). I try to pass an authorization token with the request. However the header is not being sent. Also other headers I tried to pass with the request are not being sent.

let url = 'http://www.example.com/savedata'; let data = JSON.stringify({ email: 'test@test.com', password: '123456' });  let headers = new Headers();  headers.append('Content-Type', 'application/json'); headers.append('Authorization', 'Bearer ' + "tokenContent");  let options = new RequestOptions({ headers: headers });  this.http.post(url, data, options).map(res => res.json()).subscribe(data => {                  console.log("it worked");  }, error => {                 console.log("Oooops!"); }); 

My REST API receives this request with the following headers:

Host:               www.example.com  Connection:         keep-alive   Access-Control-Request-Method:  POST     Origin:             http://evil.com/     User-Agent:         Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36    Access-Control-Request-Headers: authorization, content-type  Accept:             */*  Referer:            http://localhost:8100/?restart=794567    Accept-Encoding:        gzip, deflate, sdch  Accept-Language:        en-US,en;q=0.8   

The data (body) comes in correct, only the headers problem I cannot resolve. Any help would be very appreciated.

1 Answers

Answers 1

If you are calling REST API (example.com in your example) that is located on a different domain from your Angular 2 / Ionic app ( evil.com in your example), then you need to configure REST API server to return this header:

Access-Control-Allow-Origin: http://evil.com  

Which will allow the browser to send async HTTP requests from evil.com host to the rest api server.

It is done by enabling CORS on the rest api server, you can read about it a bit more.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Several libraries for the backend that enable cross origin requests:

https://github.com/expressjs/cors - NodeJS/Express

https://pypi.python.org/pypi/Flask-Cors/ - Python cors library for Flask

and the list continues for almost any other backend framework.

Read More

Thursday, June 30, 2016

OPTIONS (failed) only on Chrome and Firefox

Leave a Comment

I make a POST request and the request just sits, pending until it eventually fails. I've monitored the nginx logs and the node server logs and the request doesn't even register. This works for anyone else that I've had test it except one other colleague. If I use the edge browser or a different computer it works fine.

I have attempted to make POST requests to other (custom) servers and it hangs on options there as well. I have also made the POST request with jQuery and it fails the same way.

It's maybe worth noting that I am using the withCredentials flag.

Headers:

Provisional headers are shown Access-Control-Request-Headers:content-type Access-Control-Request-Method:GET Origin:http://localhost:8080 Referer:http://localhost:8080/<path> User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36 

The request:

  public login(user) {     const endpoint = `http://<url>`;      let headers = new Headers();     headers.append('Content-type', 'application/json');      return this.http       .post(endpoint, JSON.stringify(user), {         headers: headers,       });    } 

I subscribe to the call in my component:

this._accountService.login(this.user)         .subscribe(res => {             console.log("logged in!");             if (res.json().status === "success") {                 window.location.href = `/home/${this.org}/${this.product}`;             }             else {                 // What other options are there?                 console.log("Do something else maybe?");             }         },         err => {             this.invalidLogin = true;             console.log("Ye shall not pass!");         }); 

Successful user's headers

Accept:*/* Accept-Encoding:gzip, deflate, sdch Accept-Language:en-US,en;q=0.8 Access-Control-Request-Headers:content-type Access-Control-Request-Method:POST Connection:keep-alive Host:<url> Origin:<url> Referer:http://apps-dev.eng.stone-ware.com/welcome/ibm/luw User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.33 Safari/537.36 

From chrome://net-internals/#events

t=61869793 [st=    0] +REQUEST_ALIVE  [dt=60162]                        --> has_upload = false                        --> is_pending = true                        --> load_flags = 34624 (DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES | MAYBE_USER_GESTURE | VERIFY_EV_CERT)                        --> load_state = 14 (WAITING_FOR_RESPONSE)                        --> method = "OPTIONS"                        --> net_error = -1 (ERR_IO_PENDING)                        --> status = "IO_PENDING"                        --> url = "<url>" t=61929955 [st=60162]   -HTTP_STREAM_PARSER_READ_HEADERS                          --> net_error = -324 (ERR_EMPTY_RESPONSE) t=61929955 [st=60162]   -HTTP_TRANSACTION_READ_HEADERS                          --> net_error = -324 (ERR_EMPTY_RESPONSE) t=61929955 [st=60162]   -URL_REQUEST_START_JOB                          --> net_error = -324 (ERR_EMPTY_RESPONSE) t=61929955 [st=60162]    URL_REQUEST_DELEGATE  [dt=0] t=61929955 [st=60162] -REQUEST_ALIVE                        --> net_error = -324 (ERR_EMPTY_RESPONSE) 

I'm really guessing this is related to something that is cached in my browser(s) but I really cannot find what. I've cleared all cookies and anything that could be stored. Where else can I check to clear things? This is clearly something local to my computer/browser (and one other unfortunate person).

4 Answers

Answers 1

Please try to subscribe() to the observable.

return this.http   .post(endpoint, JSON.stringify(user), {     headers: headers,   }).subscribe(() => console.log("POST done!")); 

Answers 2

Have you tried setting the 'Cache-Control' in your headers? I think in jQuery you can simply set

$.ajax({       cache: false  }); 

or adding a header with a regular ajax request

request.setRequestHeader("Cache-Control", "no-cache");  

Answers 3

There are issues with CORS and using localhost as the domain (which you have listed in the ORIGIN headers). Typically CORS / OPTIONS requests don't work properly when localhost is involved for certain security reasons, but hanging isn't normally what happens so this might not be the correct answer but its worth a shot!

Try adding a new host to your local machine and removing localhost from the equation. Just throwing this idea out there and hope that it might help you out!

Answers 4

Why don't you just prevent getting into OPTIONS request loop . It really drives you crazy at times . Other browsers do not trigger OPTIONS request but chrome and firefox does to ensure CORS . I have successfully used this library named as xdomain from github , and it really works !! Their github introduction page introduce xdomain as a CORS alternative . And most importantly i used it in JQuery , but it also does support Angular's http service . Have a look at it . It may help you for good :) . Here's the link to library Xdomain CORS Alternative

Read More

Monday, June 27, 2016

CORS not working with route

Leave a Comment

I have an issue with an endpoint on my web api. I have a POST method that is not working due to:

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 405.

I cannot see why that is not working since I have plenty of methods that are working indeed with the same COSR configuration. The only difference is that this method has a specified route, as you can see below:

// POST: api/Clave         [EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]         [Route("{id:int}/clave")]         [HttpPost]         public HttpResponseMessage Post(int id, [FromBody]CambioClaveParameters parametros)         {             UsuarioModel usuario = SQL.GetUsuario(id);              if (Hash.CreateMD5(parametros.ViejaClave) != usuario.Clave.ToUpper())             {                 return Request.CreateResponse(HttpStatusCode.BadRequest);             }             else if (Hash.CreateMD5(parametros.ViejaClave) == usuario.Clave.ToUpper())             {                 SQL.ModificarClaveUsuario(id, Hash.CreateMD5(parametros.NuevaClave));                  return Request.CreateResponse(HttpStatusCode.OK);             }             else             {                 return Request.CreateResponse(HttpStatusCode.InternalServerError);             }         } 

Any Ideas of why this is happening?.

Thanks!.

4 Answers

Answers 1

if you are using web api just create one class at root level name it Startup.cs If you can try adding following code in your startup and see if that works. This code will inject cors middelware in ur application pipeline. You probably need to add owin via nuget. Give it a try

[assembly: OwinStartup(typeof(MyProject.API.Startup))]  namespace MyProject.API {     public class Startup     {         public void Configuration(IAppBuilder app)         {             app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);             app.UseWebApi(WebApiConfig.Register());         }      } } 

Answers 2

Your Web API response is clearly a 405, which indicates that you are calling an URI that does not support your HTTP Method (in this case POST).

Starting from this you need to understand why your URI does not support POST. The most probable answer is that you are calling the wrong URI. The fact that you are getting a CORS error is not the root of your problem and derives from the fact that the wrong URI you are calling does not set any Access-Control-Allow-Origin header.

Looking at your controller method:

[EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)] [Route("{id:int}/clave")] [HttpPost] public HttpResponseMessage Post(int id, [FromBody]CambioClaveParameters parametros) 

It appears to me that you are using a Route attribute, but not setting a RoutePrefix attribute in your controller class.

This means that the correct URI for your method is the following one:

http://localhost:xxxx/1/clave 

And not, as you might think, that one:

http://localhost:xxxx/api/Clave/1/clave 

If you want to access your resource using the second URI you need to put a new RoutePrefix attribute in your Controller:

[RoutePrefix("api/Clave")] public class ClaveController : ApiController {     //.. } 

Answers 3

Hope you are doing good ! you can use below code that will allow origin access on each request response.

 protected void Application_BeginRequest(object sender, EventArgs e)         {    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", *");} 

for more reference you can get help from below link. http://enable-cors.org/server_aspnet.html

Answers 4

Based upon the word "preflight" in your message, this is an OPTIONS verb issue. If you examine the requests and responses, I believe you'll see that the request directly before your POST is an OPTIONS request. The OPTIONS request is asking the server what methods are allowed to be called. If you haven't enabled an OPTIONS response, or your OPTIONS response doesn't include the POST method for that Uri, you'll get this response.

Here's a link describing the concept (see section Preflight CORS Requests) https://msdn.microsoft.com/en-us/magazine/dn532203.aspx

To account for this bypassing everything OPTIONS is designed to do, you can add code similar to this (don't be a cargo-cult programmer) to a new or existing module's BeginRequest method:

if (context.Request.HttpMethod.ToLower() == "options") {    var origin = context.Request.Headers["origin"];    context.Response.StatusCode = 200;    context.Response.AddHeader("Access-Control-Allow-Origin", origin);    context.Response.AddHeader("Access-Control-Allow-Credentials", "true");    context.Response.AddHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS");    context.Response.End(); } 

Ideally, though, you would want to programmatically determine whether the request is a valid, and if so, then output a response customized for what is actually allowed.

Read More

Wednesday, April 27, 2016

$http returning error response NULL on first call after launch (ionic) everytime, but after subsequent http post its ok

Leave a Comment

Whenever I launch my app, and click on login on the first few tries, the login will attempt a POST http to the server. However $http always (everytime) returns NULL on first try. sometimes after several few tries still NULL if done fast. But subsequently, its all ok.

I dont get it, why is $http returning error response NULL initially ??

Here is my login controller doing the http post

Login Controller (LoginCtrl) https://gist.github.com/anonymous/771194bc5815e4ccdf38b57d6158853f

var req = {   method: 'POST',   url: baseURL,   data: postObject,   //timeout: 5000 }; 

err is NULL here:

}).error(function(err) { 

I dont know if it is CORS but I'ved got this set in config.xml

 <access origin="*" /> 

my config.xml https://gist.github.com/anonymous/b2df3a857338d14ec3fcd6dda776e212

Any ideas ? Im using ionic 1.7.14 on device iOS 9.3.1

UPDATE

I'ved put the problem code here. can logout first to goto login screen. enter in anything in username/password field, click login once failed, second or third try will be success.

https://github.com/axilaris/ionic_null_http_problem

some troubleshooting so far: i noticed the http post request is called twice. not sure why.

UPDATED the code using $http.post.then but still has the same effect

 $http.post(baseURL, postObject).then(function successCallback(response)   response has NULL data --> Object {data: null, status: 0, config: Object, statusText: ""} 

3 Answers

Answers 1

It is hard to diagnose having the above details only. However the problem could be that your handler (login function) is triggered before digest cycle finished updating $scope.data.username and $scope.data.password and for the first tries it sends empty values for those to the server and works fine later. You can run Safari web inspector to see what is sent to the server to prove this. The fix may depend on how your view/template is coded. Can you please share it? Or, ideally, create a working sample at http://play.ionic.io/

Another option to fix could be to try to wrap your code related to http request into

$timeout(function() {      // your code goes here }); 

or, consider using .$applyAsync() (see the docs for details) This might help to fix the problem

Answers 2

You are probably getting this inconsistent behavior as you are using the 'success' promise method instead of 'then' (note that use of the success method has now been deprecated).

The key differences between these two methods are:

  • then() - full power of the promise API but slightly more verbose
  • success() - doesn't return a promise but offeres slightly more convienient syntax

as highlighted in this answer.

Hence in your scenario, instead of using 'success':

var req = {   method: 'POST',   url: baseURL + 'session/login',   data: postObject,   //timeout: 5000 };  $http(req).success(function(resp) {... 

use 'then' along with angular's post shortcut method (you don't have to use this shortcut method, but I think it makes the code more succinct) e.g.:

$http.post(baseURL + 'session/login', postObject).then(function successCallback(response) {   // this callback will be called asynchronously   // when the response is available }, function errorCallback(response) {   // called asynchronously if an error occurs   // or server returns response with an error status. }); 

Using 'then' returns a promise resolved with a value returned from a callback, so it should give you a consistently valid result.

Answers 3

it was a timeout in app.js that caused it. was set to 1 second which gives it it arbitrary success rate.

config.timeout = 1000; 
Read More

Monday, April 25, 2016

jQuery AJAX call results in error status 403

Leave a Comment

I'm making a query to a web service using jQuery AJAX. My query looks like this:

var serviceEndpoint = 'http://example.com/object/details?version=1.1'; $.ajax({   type: 'GET',    url: serviceEndpoint,   dataType: 'jsonp',   contentType: 'jsonp',   headers: { 'api-key':'myKey' },   success: onSuccess,   error: onFailure }); 

When I execute this, I get a status error of 403. I do not understand why my call results in having the status code 403. I'm in control of the security on my service and it is marked as wide-open. I know the key is valid, because I'm using it in another call, which works. Here is the call that works:

var endpoint = 'http://example.com/object/data/item?version=1.1'; $.ajax({    type: 'POST',    url: endpoint,    cache: 'false',   contentType:'application/json',   headers: {     'api-key':'myKey',     'Content-Type':'application/json'   },   data: JSON.stringify({     id: 5,     count:true   }),   success: onDataSuccess,   error: onDataFailure }); 

I know these are two different endpoints. But I'm 100% convinced this is not a server-side authentication or permission error. Once again, everything is wide open on the server-side. Which implies that I'm making some mistake on my client-side request.

I feel I should communicate that this request is being made during development. So, I'm running this from http://localhost:3000. For that reason, I immediately assumed it was a CORS issue. But everything looks correct. The fact that my POST request works, but my GET doesn't has me absolutely frustrated. Am I missing something? What could it be?

2 Answers

Answers 1

The reason of 403 error is you are not sending headers. Since you are making a CORS request, you cannot send any custom headers unless server enables these header by adding Access-Control-Allow-Headers to the response.

In a preflighted-request, client makes 2 requests to the server. First one is preflight (with OPTION method) and the second one is the real request. The server sends Access-Control-Allow-Headers header as a response of the preflight request. So it enables some headers to be sent. By this way your POST request can work, because the POST request is a preflighted-request. But for a GET request, there is no preflight to gather Access-Control-Allow-Headers header. So browser doesn't send your custom headers.

A workaround for this issue:

As a workaround, set your dataType and contentType to json as the following:

var serviceEndpoint = 'http://example.com/object/details?version=1.1'; $.ajax({   type: 'GET',    url: serviceEndpoint,   dataType: 'json',   contentType: 'json',   headers: { 'api-key':'myKey' },   success: onSuccess,   error: onFailure }); 

By this way, your get request will be a preflighted request. If your server enables the api-key with Access-Control-Allow-Headers header, it will work.

Sample server configuration for the above request (written in express.js):

res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', '*'); res.setHeader('Access-Control-Allow-Headers', 'api-key,content-type'); res.setHeader('Access-Control-Allow-Credentials', true); 

ADDED:

Actually, contentType should be either application/javascript or application/json while doing a jsonp request. There is no contentType as jsonp.

Answers 2

If you look at the API page for jQuery's Ajax call, it mentions the following in the Content-Type section:

Note: For cross-domain requests, setting the content type to anything other than application/x-www-form-urlencoded, multipart/form-data, or text/plain will trigger the browser to send a preflight OPTIONS request to the server.

That page doesn't really mention what a "preflight OPTIONS request" is, but I found some interesting links when looking that phrase up online:

What's intersting is the code example & the CORS image at the HTML5Rocks page. The image shows how the Ajax calls are being made from the JavaScript code to the browser to the server & how the responses are round-tripping between all 3 of those.

We tend to think of JavaScript + Browser = Client, but in the illustration the author is explaining the difference between the web developer's code & the browser developer's code, where the former is written in JavaScript code, but the latter was written using C, C++ or C# code.

A good packet analyzer tool is Fiddler, which would be similar to Wireshark. Either one of those tools, should show you the pre-flight requests which are being sent from the browser to the server. Most likely, that's where your Ajax request is being blocked at by the server with a 403 Forbidden error.

Read More