HTTP request with SSL 128 bits - node.js

Working on a webapp using Ogone Direct Paiment, a code working for an old account is working but giving me same error for the new one.
I've added the call made and the answer, maybe someone is used to Ogone API.
The error seems to tell me I have to make a SSL 128bit call but I have no idea how to do that. I've tried lot of things, including userAgent, generate certificate myself with openssl command but without result.
If you're familiar with Ogone, let me know how to fix it or how to change the configuration to allow simple queries.
Otherwise, could you explain me how to make a SSL 128 bit call with nodeJS module request?
Request call
const request= require('request');
const datas = {
url : 'https://secure.ogone.com/ncol/prod/orderdirect_utf8.asp',
method:"POST",
form: 'queryUrlEncoded',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
request(datas, (err, response, body) => {
err && console.error(err);
body && console.log(body);
});
Response received
<?xml version="1.0"?>
<ncresponse [...] NCSTATUS="5" NCERROR="50001115" NCERRORPLUS="SSL 128 required">
</ncresponse>

The module you are using has feature to apply SSL but for that you would need a certificate with key, long story short, yes it is possible.
const fs = require('fs')
, path = require('path')
, certFile = path.resolve(__dirname, 'ssl/client.crt')
, keyFile = path.resolve(__dirname, 'ssl/client.key')
, caFile = path.resolve(__dirname, 'ssl/ca.cert.pem')
, request = require('request');
const options = {
url: 'https://api.some-server.com/',
cert: fs.readFileSync(certFile),
key: fs.readFileSync(keyFile),
passphrase: 'password',
ca: fs.readFileSync(caFile)
};
request.get(options);
Copied from documentation.
Click Here for Documentation

Related

how to increase tps (throughput) of my nodejs custom library which makes https request

Created a nodejs library which makes an https request with client certificates(.crt,.key files) to a different server to get the response. For making a request I used the "request" npm module.
While benchmarking the library,
I was making 2000 requests to my library to make a request but the library couldn't handle more than 150-200
simultaneously. Suppose, I used Http server then library throughput has been increased with 1800-1850 simultaneously.
what I observed is while making https request, I think the event loop is blocked. so that it couldn't able to handle or accept the requests.
I have also tried using the https core module, node-fetch, axios npm modules. There is no difference in the throughput of my library.
Also, we have tried using the cluster concept of nodejs. but it's not suitable for my library.
Please help me with what should I do, to increase the throughput of my library.
My Code:
const request = require('request');
const fs = require('fs');
const path = require('path');
function makeRequest() {
let headers = {'Content-Type':'application/json'};
let body = '{name:'library'}';
let options = {
url: 'https://IP:PORT/CONTEXT',
method: 'POST',
headers: headers,
body: body,
agentOptions:
{
cert: fs.readFileSync(path.resolve(__dirname, 'ssl/my.crt')),
key: fs.readFileSync(path.resolve(__dirname, 'ssl/my.key')),
passphrase: '123456'
}
}
request(options, (err, response, body) => {
if (err) {
console.log('err :>> ', err);
} else {
console.log('response :>> ', response.statusCode);
}
})
}

How to send a post request and authenticate with a .pem certificate and passphrase [duplicate]

This question already has answers here:
How to do HTTPS GET with client certificate in node
(1 answer)
Nodejs request to a web service with .p12 certificate
(2 answers)
Node.js Rest call to a server that requires a certificate
(1 answer)
Closed 3 years ago.
I'm trying to make a POST request from a Node/Express server to a ecommerce provider while authenticating with a .PEM certificate, which I converted from a .p12 file using openssl as per their instructions. The provider is supposed to return a unique transaction ID.
I've tried using the Request module as below but I'm getting a "bad certificate" error every time. I've tried with agentOptions, without agentOptions, checked the .pem file is being read correctly, etc.
Error: write EPROTO 140059546118016:error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1407:SSL alert number 42
const options = {
url: "https://ecommerce.com:12345/some/route",
agentOptions: {
passphrase: process.env.MY_PASSPHRASE,
ca: fs.readFileSync("./ssl/certificate.pem")
},
rejectUnauthorized: false,
form: {
amount: 100,
currency: 981
}
};
await request.post(options, (err, res, body) => {
console.log({ err, res, body });
});
I'm new to Node.js, and even newer with SSL :( apologies if I'm not explaining or understanding this correctly. Any help/direction will be much appreciated.
SOLVED
Sample working code. Using the same exact key in cert and key fields worked for some reason.
const fs = require("fs");
const request = require("request-promise");
const options = {
url: "https://provider.com:18443/some/path",
headers: {
"User-Agent": "node.js"
},
strictSSL: false,
form: {
// currency, language, provider-specific options here
},
cert: fs.readFileSync("./ssl/my_key.pem"),
key: fs.readFileSync("./ssl/my_key.pem"),
passphrase: process.env.PASSPHRASE
};
const req = await request.post(options, (err, httpResponse, body) => {
// do stuff with body here
})

Calling a SOAP service requiring certificate using Nodejs

Nodejs SOAP client throwing error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames:
I am trying to call a SOAP service using soap in nodejs. However I am getting error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: IP: XXX.XXX.XXX.XXX is not in the cert's list:. I am new to nodejs and not sure how to call a SOAP service which requires certificate from nodejs. Other ways to call SOAP services requiring certificates in Nodejs are also welcome.
var url = "https://soapserviceurl?wsdl";
soap.createClient(url, function (err, client) {
if (err) {
console.log("Error Occurred!!");
console.log(err);
}
else {
console.log(client.describe());
}
});
please try
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0" //this is insecure
Or:
var soap = require('soap'),
request = require('request'),
fs = require('fs');
var url = "https://soapserviceurl?wsdl";
var req = request.defaults({
strictSSL: false
);
soap.createClient(url, {
request : req
}, function(err, client) {
//your code
});
Or:
soap.createClient(url, {
request : req,
wsdl_options: {
cert: fs.readFileSync('cert/cert.pem'), //path to pem
key: fs.readFileSync('cert/cert.key'), //path to private key
rejectUnauthorized: false
}
}, function(err, client) {
//your code
});
The answer above doesn't work anymore because as of SOAP as of v0.40.0, it uses Axios for web requests, and not the request package. I couldn't find a recent answer for this and I spent a while figuring it out.
See in the documentation:
request (Object): Override the default request module (Axios as of v0.40.0).
wsdl_options (Object): Set options for the request module on WSDL requests. If using the default request module, see Request Config | Axios Docs.
Based on the link above and instructions like these https://smallstep.com/hello-mtls/doc/client/axios, this is the new way to do it:
First, so the WSDL endpoint is fetched with authentication, get the client like this:
import soap from 'soap';
import fs from 'fs';
import https from 'https';
const client = await soap.createClientAsync(api_url, {
wsdl_options: {
httpsAgent: new https.Agent({
key: fs.readFileSync('personal.key'),
cert: fs.readFileSync('personal.cert'),
}),
}
});
The key difference is that instead of passing cert and key in wsdl_options, you have to pass a new https.Agent with the cert and key.
Next, before making any call, ensure they are also called with certificate authentication:
client.setSecurity(new soap.ClientSSLSecurity('personal.key', 'personal.cert'));

P12 PFX NodeJS Request

I am trying to make a request with a p12 file or a pfx, but I can't get it to work. If I use PEM and KEY the code works fine. But Azure Keyvault does not support PEM and KEY. Is there an alternative that works with KEY/PEM certificates?
This is how I generated a p12/pfx file if that is the problem.
openssl pkcs12 -export -out certificate.pfx -inkey 1231181189.key -in
1231181189.pem -certfile CA.pem
Here is an example code, if I comment out cert and key the system does not work,
Error: read ECONNRESET
But if I comment out pfx and passphrase and use pem and key the connection work.
var request = require('request');
var fs = require('fs');
var path = require('path');
var certFile = __dirname + '/certs/1231181189.pem';
var keyFile = __dirname + '/certs/1231181189.key';
var options = {
method: 'POST',
url: 'https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests',
headers: { 'Content-Type': 'application/json' },
agentOptions: {
cert: fs.readFileSync(certFile),
key: fs.readFileSync(keyFile),
pfx: fs.readFileSync(__dirname + '/certs/certificate.pfx'),
passphrase: 'swish'
},
body: {
payeePaymentReference: '0123456789',
callbackUrl: 'https://example.com/api/swishcb/paymentrequests',
payerAlias: '4671234768',
payeeAlias: '1231181189',
amount: '100',
currency: 'SEK',
message: 'Kingston USB Flash Drive 8 GB'
},
json: true
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(response.headers);
console.log(body);
});
ECONNRESET means the far end -- in your case the endpoint on swish.net -- unceremoniously disconnected from the https client in your nodejs program. It's hard to know precisely why it did so. It's likely due to some sort of security failure. Robust servers don't explain security failures; after all why help cybercreeps? It's possible looking at a log on that server will tell you more.
In the meantime, it's possible the npm request package you use to wrap node's https agent function doesn't know anything about .pfx files or passwords, and therefore attempts to connect without any client certificates.
The pemutils package may allow you to extract the information you need from your .pfx file and use it. Something like this may work (not debugged).
var request = require('request');
var pemutils = require('pemutils');
var fs = require('fs');
var path = require('path');
const pfxFile = __dirname + '/certs/certificate.pfx';
pemutils.fromPfx({
path: pfxFile,
password: 'myPass'
}, function(err, pfxresults) {
if(err) throw err;
var options = {
method: 'POST',
url: 'https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests',
headers: { 'Content-Type': 'application/json' },
agentOptions: {
cert: pfxresults.certificate,
key: pfxresults.key,
},
body: {
...
},
json: true
};
...
Notice the .fromPfx method is asynchronous.
I have the same issue with Azure APIM and I also need basic auth for the request.
I send request with axios like below:
const fs = require("fs");
const axios = require("axios");
const https = require("https");
(async function () {
try {
const response = await axios.request({
url: "url",
method: "get",
headers: {
accept: "application/json",
},
auth: {
username: "name",
password: "pw",
},
httpsAgent: new https.Agent({
pfx: fs.readFileSync(
__dirname + "/mycert.pfx"
),
}),
});
console.log(JSON.stringify(response.data));
} catch (error) {
console.log(error);
}
})();

Node-fetch: Disable SSL verification

I have the following code, which is run from a express server:
import fetch from 'node-fetch';
let formBody = [];
const dataLogin = {
'username': 'myUser',
'password': 'myPassword'
};
for (let p in dataLogin) {
let encodedKey = encodeURIComponent(p);
let encodedValue = encodeURIComponent(dataLogin[p]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
const url = 'https://external-login-api.com';
return fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': formBody.length
},
body: formBody
});
When I run the code I get the following error, despite being able to run the request in Postman with no problems.
{"message":"request to https://external-login-api.com failed, reason: write EPROTO 7316:error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small:openssl\ssl\statem\statem_clnt.c:1472:\n","type":"system","errno":"EPROTO","code":"EPROTO"}
How do I disable SSL verification for this request?
The other way to do is to set your own agent to the fetch call.
const fetch = require('node-fetch');
const https = require('https');
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
});
const response = await fetch(url, {
method: 'POST',
headers: headers,
body: body,
agent: httpsAgent,
});
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
Will ensure you ignore any rejected TLS certificates, or you can set this as an environment variable when running your node service. However this will likely not help, and is probably a bad idea. The SSL error is not because the certificate is invalid (such as a self signed certificate) but instead because of a weak Diffie-Hellman key in the SSL/TLS configuration.
If this a service you're hosting you should look at correcting and improving your TLS/SSL cyphers. See this answer for more information.
The important part is:
You should use 2048-bit Diffie-Hellman groups or larger. You should
not be using 512-bit or 1024-bit Diffie-Hellman groups.
If this is a third party service, you should consider contacting them or using a different service as they are leaving themselves open to the Logjam attack which is also discussed in the answer linked above.

Resources