I am using Angular 1.x to POST a verification request to Google's re-captcha as follows:
var post_data = { //prepare payload for request
'secret':'xxxxx',
'response':fields.myRecaptchaResponse
};
$http.post('https://www.google.com/recaptcha/api/siteverify', post_data)
In my console I can see the following error:
XMLHttpRequest cannot load https://www.google.com/recaptcha/api/siteverify. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://igs.dev' is therefore not allowed access. The response had HTTP status code 405.
I have read multiple answers on Stackoverflow, most seem to suggest adding a plugin to Chrome but that is not a solution for my users who will be using the re-captcha to validate a contact form.
Is this a misconfiguration of my server or is my Angular script missing something? I have already ensured that my domain is configured in my re-captcha account.
ReCaptcha is validated on the server-side, not the client side. The CORS error is due to the fact that the ReCaptcha API is not meant to be used by a browser.
You need to send your recaptcha data to your API/server which then verifies it is correct by sending a request to the ReCaptcha API. There are no CORS restrictions when servers make HTTP requests to each other.
See this Tuts tutorial on how the implementation and flow of data works
The end point https://www.google.com/recaptcha/api/siteverify is part of server side validation and not the client side. You should hit this endpoint from your server, not from your client (Angular 1.X).
So the flow may look like this:
At your client side (Angular 1.X) you will be loading the re-captcha widget in your html which will perform the validation and store a hash value in a hidden input field which will be sent to your server along with the other form details when user submits the form. Now at your server side you will hit that endpoint to verify if the validation was successful.
Also, in no case you should be storing your secret at the client side. It should always be maintained at your server side for server-to-server communication purposes.
Read the docs here.
Related
I added additional API to the Duende IdentityServer 6.2 as described here. Then I tried to access it from a sample App, using typed httpClient using their own library called AccessTokenManagement (aka Identity.Model) pretty much following their simple example. I use Authorization Code flow, everything pretty much simple and default.
It works well until both server and client are on the same dev machine under localhost. As soon as I publish IdentityServer to IIS, the API stops to work, while the rest still works well (I can be authenticated, and I see in the Fiddler that token exchanges work normally).
The call to API consists from two calls:
Calling to /connect/token using refresh token. Server returns access token.
Calling my endpoint using this new access token.
The flow fails on the step 1. Call to /connect/token is already unauthorized and I can't understand why. The "good" and "bad" calls looks the same, I cannot see any differences. Previous call moment ago to /connect/userinfo consists of the same two steps and it works. Logs on both server and client give no clues.
No reverse proxies, just good plain simple URI. Automatic key management is enabled and the keys are in the SQL table, common for dev and published server. Asp.Net Core Data Protection is enabled and keys are also common.
Relevant parts of logs are below. I noticed that "No endpoint entry found for request path" is specific to IdentityServer and it doesn't actually mean that endpoint was not found. It was found but not processed. I also noticed reacher response headers from bad request and log entry about "Cookie signed-in" in good request but not sure what does it mean and whether it's relevant.
I'm running out of ideas.
Bad response from IIS while trying to get new Access Token:
Proper response while developing:
///////Relevant part of log for BAD request
|Duende.AccessTokenManagement.OpenIdConnect.UserAccessAccessTokenManagementService|Token for user test#test.com needs refreshing.
|Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler|AuthenticationScheme: cookie was successfully authenticated.
|Duende.AccessTokenManagement.OpenIdConnect.UserTokenEndpointService|refresh token request to: https://auth.mysite.org/connect/token
|Duende.AccessTokenManagement.OpenIdConnect.UserAccessAccessTokenManagementService|Error refreshing access token. Error = Unauthorized
|System.Net.Http.HttpClient.IdsService.ClientHandler|Sending HTTP request POST https://auth.mysite.org/mycontroller/myaction
|System.Net.Http.HttpClient.IdsService.ClientHandler|Received HTTP response headers after 117.7278ms - 401
///////Same part of GOOD request
|Duende.AccessTokenManagement.OpenIdConnect.UserAccessAccessTokenManagementService|Token for user test#test.com needs refreshing.
|Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler|AuthenticationScheme: Cookies was successfully authenticated.
|Duende.AccessTokenManagement.OpenIdConnect.UserTokenEndpointService|refresh token request to: https://localhost:5001/connect/token
|Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler|AuthenticationScheme: Cookies signed in.
|System.Net.Http.HttpClient.IdsService.ClientHandler|Sending HTTP request POST https://localhost:5001/mycontroller/myaction
|System.Net.Http.HttpClient.IdsService.ClientHandler|Received HTTP response headers after 1994.9611ms - 200
///////Server log during BAD request
Duende.IdentityServer.Hosting.EndpointRouter No endpoint entry found for request path: "/mycontroller/myaction"
Duende.IdentityServer.Hosting.LocalApiAuthentication.LocalApiAuthenticationHandler HandleAuthenticateAsync called
Duende.IdentityServer.Hosting.LocalApiAuthentication.LocalApiAuthenticationHandler AuthenticationScheme: "IdentityServerAccessToken" was not authenticated.
Duende.IdentityServer.Hosting.LocalApiAuthentication.LocalApiAuthenticationHandler AuthenticationScheme: "IdentityServerAccessToken" was challenged.
Okay, found it. Thankfully, looked at Fiddler's WebView and had seen familiar picture!
Then, found this topic. The solution was disabling Basic authentication in IIS settings. Access token request has basic authentication header and it seems like IIS intercepts it. Still a bit unclear why other parts of flow worked.
Forgive me for the obvious error I am obviously committing...
I understand CORS, how and why it's used. But I'm missing the blindingly obvious in this instance.
I'm trying to access a publicly available API that should work fine (I've been assured)
If I hit the endpoint in Chrome, or in Postman, all works fine: wonderful JSON is returned.
When I try to do the same using axios from within my create-react-app's componentDidMount, I get a CORS error, specifically
Access to XMLHttpRequest at 'http://some-interesting-url/sub-url?blabla=blip&foo=bar' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
What is it I'm failing to grasp? Is there anything I can do from my end? (I have no control over the server)
The Postman app is not a browser so it isn't bound by the rules of CORS. In a browser too, trying to access a URL directly doesn't trigger Cross-Origin-Request-Sharing policies. CORS, by definition will only affects the 'cross-origin' requests made from background JS code of a web-page, to another web-page or API not hosted on same domain name.
Based on the error posted, the API in question is not sending Access-Control-Allow-Origin header. If it's possible to get the API changed, that you should get the header added to response (with value '*', or your domain name). However if that's not possible, then you'd need to route the request through a web-server that you own and include this header there. This kind of does work like a proxy, albeit for a specialized use-case.
If you already have some server side application running, you can simply add another end point to your application. A call to this new end point should trigger the 'Public API' call, and send the response back to client. Since the server side program (eg PHP/Python/NodeJS) would never be a browser, they will not face the CORS issues. If your original web-page is also loaded from same web-server, then the response header can be skipped.
I have an AngularJs website and when I am trying to post data then when I am opening my website without using www then I am getting
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource
Otherwise, I am not getting any error.
I tried to search and found that I should implement CORS on my backend which is in NodeJs but can anyone please tell me how can I only implement CORS Headers such that for both www and without, it would work but for any other domain trying to access my API must result in preflight error.
I am trying to do this because I read here which-security-risks-do-cors-imply that allowing all domains can increase security overhead for my website which I do not want.
Thanks.
I'm afraid this is not something you can tweak just in your client-side code. In order for cross-origin requests to work, you need to set an http response header: it's the server, who serves the resource, who will need the change, not the client side code from angularJs.
I believe that you should update your question stating what your server side language is and how are you handling http requests in the server side. As far as I know, just adding a header like:
Access-Control-Allow-Origin: http://client.domain.com
In your responses will do the trick. Where client.domain.com is the domain of your client, angularJs application.
I'm having an issue with a web app I'm building. The web app consists of an angular 4 frontend and a dotnet core RESTful api backend. One of the requirements is that requests to the backend need to be authenticated using SSL mutual authentication; i.e., client certificates.
Currently I'm hosting both the frontend and the backend as Azure app services and they are on separate subdomains.
The backend is set up to require client certificates by following this guide which I believe is the only way to do it for Azure app services:
https://learn.microsoft.com/en-us/azure/app-service/app-service-web-configure-tls-mutual-auth
When the frontend makes requests to the backend, I set withCredentials to true — which, [according to the documentation][1], should also work with client certificates.
The XMLHttpRequest.withCredentials property is a Boolean that indicates whether or not cross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates. Setting withCredentials has no effect on same-site requests.
Relevant code from the frontend:
const headers = new Headers({ 'Content-Type': 'application/json' });
const options = new RequestOptions({ headers, withCredentials: true });
let apiEndpoint = environment.secureApiEndpoint + '/api/transactions/stored-transactions/';
return this.authHttp.get(apiEndpoint, JSON.stringify(transactionSearchModel), options)
.map((response: Response) => {
return response.json();
})
.catch(this.handleErrorObservable);
On Chrome this works, when a request is made the browser prompts the user for a certificate and it gets included in the preflight request and everything works.
For all the other main browsers however this is not the case. Firefox, Edge and Safari all fail the preflight request because the server shuts the connection when they don't include a client certificate in the request.
Browsing directly to an api endpoint makes every browser prompt the user for a certificate, so I'm pretty sure this is explicitly relevant to how most browsers handle preflight requests with client certificates.
Am doing something wrong? Or are the other browsers doing the wrong thing by not prompting for a certificate when making requests?
I need to support other browsers than Chrome so I need to solve this somehow.
I've seen similar issues being solved by having the backend allow rather than require certificates. The only problem is that I haven't found a way to actually do that with Azure app services. It's either require or not require.
Does anyone have any suggestions on how I can move on?
See https://bugzilla.mozilla.org/show_bug.cgi?id=1019603 and my comment in the answer at CORS with client https certificates (I had forgotten I’d seen this same problem reported before…).
The gist of all that is, the cause of the difference you’re seeing is a bug in Chrome. I’ve filed a bug for it at https://bugs.chromium.org/p/chromium/issues/detail?id=775438.
The problem is that Chrome doesn’t follow the spec requirements on this, which mandate that the browser not send TLS client certificates in preflight requests; so Chrome instead does send your TLS client certificate in the preflight.
Firefox/Edge/Safari follow the spec requirements and don’t send the TLS client cert in the preflight.
Update: The Chrome screen capture added in an edit to the question shows an OPTIONS request for a GET request, and a subsequent GET request — not the POST request from your code. So perhaps the problem is that the server forbids POST requests.
The request shown in https://i.stack.imgur.com/GD8iG.png is a CORS preflight OPTIONS request the browser automatically sends on its own before trying the POST request in your code.
The Content-Type: application/json request header your code adds is what triggers the browser to make that preflight OPTIONS request.
It’s important to understand the browser never includes any credentials in that preflight OPTIONS request — so the server the request is being sent to must be configured to not require any credentials/authentication for OPTIONS requests to /api/transactions/own-transactions/.
However, from https://i.stack.imgur.com/GD8iG.png it appears that server is forbidding OPTIONS requests to that /api/transactions/own-transactions/. Maybe that’s because the request lacks the credentials the server expects or maybe it’s instead because the server is configured to forbid all OPTIONS requests, regardless.
So the result of that is, the browser concludes the preflight was unsuccessful, and so it stops right there and never moves on to trying the POST request from your code.
Given what’s shown in https://i.stack.imgur.com/GD8iG.png it’s hard to understand how this could actually be working as expected in Chrome — especially given that no browsers ever send credentials of any kind in the preflight requests, so any possible browsers differences in handling of credentials would make no difference as far as the preflight goes.
I followed the instructions found in the readme in the stormapth-sdk-react github respository to set up a basic login form. The form displays, but I am immediately greeted by errors in the console:
XMLHttpRequest cannot load https://{redacted}.apps.stormpath.io/me. 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 403.
I get an identical error for the login endpoint.
The Client API Guide indicates that client endpoints have to be configured to allow traffic from a particular domain, but does not provide any instructions for how to do this:
Applications that use the Client API have two relevant configuration parameters, both found on your Application’s page in the Stormpath Admin Console:...
Authorized Callback URIs: This list should include any URIs that your users will be returned to after they have completed authentication with an outside provider, for example as a part of the social login flow. For example, if you do not specify a redirect URI when you kick off the social login flow, the user will be redirected the first URI in this list.
Authorized Origin URIs: This list should include the application’s URL, or whatever URL will be included in the Origin header of requests sent to the Client API.
What do I need to do to get this working?
To fix this, you can login to https://api.stormpath.com, navigate to Applications > My Application, and modify the Authorized Origin URIs to include http://localhost:3000.
Stormpath seems to use a pretty similar setup to many API services. Like the directions say, go to your Stormpath Admin Console, and put your hostname (http://localhost:3000) in the relevant fields for both 1. and 2.
Doing so tells the Stormpath API to allow data to be sent to your application.
The Cross-Origin Resource Sharing (CORS) mechanism gives web servers cross-domain access controls, which enable secure cross-domain data transfers.
As the server you are using (for react) differs from the server you are requesting data(node or something else). (even the subdomain or port matters)
index.js: (server)
const cors = require('cors');
..
..
app.use(cors());
for more info about using cors: npm cors