node.js and nginx SSL handshake failure - nginx

I'm trying to create a basic SSL connection from a node.js app to a locally hosted nginx server; it involves sending the client's credentials as well. The handshake seems like it was successful as calling "verifyPeer" from within a "secure" event verifies that much. However, the server continues to respond with nothing but a 400 response.
If I make the same request with curl on the command line, I get back what I expect:
curl -v -E curl-test.crt --cacert ca.crt https://internal.url:7443/some.file
"curl-test.crt" was created by concatenating the client key and certificate together.
Here is the smallest bit of node.js code needed to get a failure:
global.util = require('util');
var fs = require('fs'),
http = require('http'),
crypto = require('crypto');
var clientCert = fs.readFileSync("tmp/cert.crt", 'ascii'),
clientKey = fs.readFileSync("tmp/key.key", 'ascii'),
caCert = fs.readFileSync("tmp/ca.crt", 'ascii');
var credentials = crypto.createCredentials({"key": clientKey, "cert": clientCert, "ca": caCert});
var client = http.createClient(7443, "internal.url", true, credentials);
client.addListener("secure", function() {
if (!client.verifyPeer()) {
throw new Exception("Could not verify peer");
}
});
var request = client.request('GET', '/some.file', {});
request.on('response', function(response) {
response.on('data', function(body) {
util.log("body: " + body);
});
});
request.end();
And here is the response I get, no matter what "some.file" is changed to:
body: <html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/0.6.32</center>
</body>
</html>
Any help in debugging or solving this issue would be fantastic

Are you getting this message in your nginx error log?
2010/11/23 17:51:59 [info] 13221#0: *1 client sent HTTP/1.1 request without "Host" header while reading client request headers, client: 127.0.0.1, server: testme.local, request: "GET /some.file HTTP/1.1"
If so, you can fix it by simply adding the 'Host' header to your GET request like this:
var request = client.request('GET', '/some.file', {'Host':'internal.url'});
Looks like nginx wants the Host header and node doesn't send it by default. There's probably a way to configure nginx to default to the correct header value as well.
Hope that helps!

Related

Axios network error on Cors Post request with status code 200

I use axios to communicate with my own API (not written in NodeJS).
When I post a non simple request axios always goes directly to the catch block displaying a network error in the console, even with 2 successful Http Requests.
Error: Network Error
Stack trace:
createError#http://localhost:3000/static/js/bundle.js:1634:15
handleError#http://localhost:3000/static/js/bundle.js:1170:14
There is also a CORS warning about a missing header
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://127.0.0.1:8080. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
However it is included in the Options Request!
When I add 'Access-Control-Allow-Origin': '*' in the Axios request headers, the warning is gone, but the browser doesn't fire a Post request after the successful Options request.
For the sake of being complete here are the post request headers.
The code:
postForm = () => {
axios.post("http://127.0.0.1:8080/",
myComplexObj, {
headers: {
//'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
},
timeout: 15000
}
).then(res => {
console.log(res);
alert('success');
})
.catch(function(error) {
//code always end up here
console.log(error);
/*Error: Network Error
Stack trace:
createError#http://localhost:3000/static/js/bundle.js:1634:15
handleError#http://localhost:3000/static/js/bundle.js:1170:14
*/
console.log(error.response); //undefined
console.log(error.response.data); //undefined
}
})
Any help is gladly appreciated.
What I have tried:
Remove the timeout //no change
Remove the Catch block //still no success
Return status code 204 on Options and/or Post requests //no difference
You are confusing because status 200, however, the browser will not allow you to access the response of a CORS request if the Access-Control-Allow-Origin header is missing.
Here are some great articles that explain how CORS works:
https://www.html5rocks.com/en/tutorials/cors/
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Anyway, I think that you are using Django. So, you need add to settings.py:
CORS_ORIGIN_WHITELIST = (
'localhost:8080',
'localhost'
)
Or wherever you have the axios code.

Different behavior CURL vs http.get - CORS

So, I am really getting annoyed at this:
Command line:
$ curl -X GET "cloudant/url" --header "Authorization: Basic YWRtaW46cGFzcw==" --header "Content-Type: application/x-www-form-urlencoded; charset=UTF-8"
{ "response": "OK" }
With Angular 2 http module (inside of an injectable service):
import {Http, Response, Headers} from '#angular/http';
let headers = new Headers();
headers.append("Authorization", "Basic YWRtaW46cGFzcw==");
headers.append("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
this.http.get("cloudant/url", { method: "GET", headers: headers });
405 (Method Not Allowed)
Response for preflight has invalid HTTP status code 405
I should not, nor need to, care about the server configuration. I want to emit a GET request to the server, and any CORS client-sided security concerns are none of my business.
Can I make Http behave like curl in this particular regard?
This is exactly what CORS is intended to do. It prevents you from making cross origin requests from your browser unless the server is set up to specifically allow it. I understand your frustration, but there is no workaround for this.
You're mistaken in thinking that CORS is simply a client side security concern. It takes a well configured server coupled with a well designed front end app to build something really great. And you should care about the server configuration as much as it ensures that you are able to deliver a responsive and snappy front end experience. If any website in the world could just start hitting this API there would be all kinds of additional security and performance concerns for the backend.
I used the fetch API instead:
return fetch(url, { method: "GET" }).then(this.extractData).catch(this.handleError);
...
private extractData(res: Response): Promise<CloudantCheckStatisticsRowMapping> {
let p = res.json();
return p.then(function(body: any) {
console.log("Found " + body.total_rows + " records; last one is the one we need.");
return body.rows[0].doc;
});
}
It seems it's not bothered by the CORS.

Angular2 post with mailchimp

My post works in postman but doesn't work inside my app. What am I doing wrong?
let data = obj;
let url = 'https://us123.api.mailchimp.com/3.0/lists/{somenumber}/members';
let username: string = 'user';
let password: string = 'mytokenhere';
let headers = new Headers();
headers.append("Authorization", "Basic " + btoa(username + ":" + password));
headers.append("Content-Type", "application/x-www-form-urlencoded");
return this._http.post(url, data, {headers: headers}).subscribe(
data => this.response(data),
error => this.response(error)
);
I'm getting a CORS error in app:
'XMLHttpRequest cannot load https://us123.api.mailchimp.com/3.0/lists/{{somenumber}}/members. 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:4200' is therefore not allowed access. The response had HTTP status code 501.'
Mailchimp doesn't support client side calls to their API. What you would need to do is setup a server that can proxy the requests from the browser to Mailchimp. There isn't much you can do client side to get it to work if the Mailchimp API doesn't provide the CORS response headers.
If your API that you create is on the same domain as the website, then the CORS issue would be eliminated (or you can also fix by setting the appropriate headers)
See the note under Authentication:
https://developer.mailchimp.com/documentation/mailchimp/guides/get-started-with-mailchimp-api-3/
More Info:
https://www.moesif.com/blog/technical/cors/Authoritative-Guide-to-CORS-Cross-Origin-Resource-Sharing-for-REST-APIs/

Meteor HTTP blank body with Content-Length 0 and response 302

A Meteor server code, using atmosphere HTTP package, is making a POST http call to a remote server, the response.statusCode comes back 302 and the response header contains:
Content-Length: 0
Centent-Type: text/html
Location: otherURLThanVisitedIn_myURL?key=value
The response headers is the same also in firefox inspector panel when visiting the same page.
How is it that the page loads up and I can see the contents in the browser but when I console.log(response.content.length) I get 0, i.e. no string content received? Thanks
let myURL = getURL();
let myHeaders = getHeadersObj();
let myParams = getParamsObj();
const response = HTTP.call('POST', myURL, {
timeout: 30000,
headers: myHeaders,
params: myParams
});
The 302 status code means there's a redirection. Apparently the Meteor package doesn't follow the redirection automatically.
The first thing to check is that you have a recent version of the package. There was an issue about redirects for POST request.
If it's ok, you can use the followRedirect parameter in the options:
const response = HTTP.call('POST', myURL, {
timeout: 30000,
headers: myHeaders,
params: myParams,
followRedirect: true
});

Angular2 : detect error from HTTP post

I cannot interecept error from http post
a part of my mservice (http post method)
addApplicationLink(applicationLink: ApplicationLink){
let body = JSON.stringify(applicationLink);
let requestHeaders = new Headers();
var headers = new Headers();
headers.set('Content-Type', ['application/json; charset=utf-8']);
let reqoptions = new RequestOptions({
headers: headers
});
return this._http.post(this._applicationLinksUrl + this._linkServicePath,body,{headers: headers});
in my component :
addApplicationLink() {
//todo
this.addNewLink = false;
/* check if must be done after call real rest service */
//this.applicationLinks.push(this.applicationLinkAdd);
this._applicationLinkService.addApplicationLink(this.applicationLinkAdd)
.subscribe(data => {
this.applicationLinks.push(this.applicationLinkAdd)
},
error => {
// handle error
console.error('this an erreor ' + error.status)
}
)
When user tries to add two same applicationlinks , the backend returns an error 409
But when I execute , error.status displays 200 in browser console
I see also in browser console
XMLHttpRequest cannot load http://localhost:7001...... 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 409.
rem : Http post is made with json , thus there is a prefligth call
Have you an idea to intercept error 409 ?
In fact, your server doesn't send back the CORS header (Access-Control-Allow-Origin' header is missing). This prevent the browser from providing the actual 409 error to the Angular2 application within the browser.
You need to fix first the problem on the server and you will be able to see this 409 error.
For more details about how CORS works, you could have a look at this article:
http://restlet.com/blog/2015/12/15/understanding-and-using-cors/

Resources