What could be different in https implementation for python vs nodejs?

Viewed 277

I am trying to figure out one weird issue. I have working python code which I want to translate to NodeJS. Python code very simple and works:

import requests

LOGIN_URL = 'https://android.clients.google.com/auth'
params = {'Email': '***', 'EncryptedPasswd': b'***', 'service': 'androidmarket', 'accountType': 'HOSTED_OR_GOOGLE', 'has_permission': 1, 'source': 'android', 'device_country': 'us', 'lang': 'us'}
response = requests.post(LOGIN_URL, data=params, verify=True)
print(response.text)

Here is NodeJS version code:

const request = require('request');

const LOGIN_URL = 'https://android.clients.google.com/auth'
const params = {'Email': '***', 'EncryptedPasswd': '***', 'service': 'androidmarket', 'accountType': 'HOSTED_OR_GOOGLE', 'has_permission': 1, 'source': 'android', 'device_country': 'us', 'lang': 'us'}
request({url: LOGIN_URL, method: 'POST', form: params}, function(error, response) {
   console.log(response.statusCode);
});

This does not work, I am getting back 403 - Bad request. I have tried to change protocol to http and then check packets contents in Wireshark. They are pretty much same with minor differences. I tried eliminating all the differences by overriding headers in NodeJS version, it did not help. So my guess is something wrong with https?

What am I missing? What could be the difference between Python and NodeJS?

1 Answers

Second guess:

Logins require cookies, NodeJS requests disables cookies by default. Try:

const request = request.defaults({jar: true})

First guess:

Differences between the python code and the Node.js code as posted:

  • The python code sends these headers:
HTTP_ACCEPT: */*
HTTP_ACCEPT_ENCODING: gzip, deflate
HTTP_CONNECTION: keep-alive
HTTP_USER_AGENT: python-requests/2.24.0
  • The Node code sends only these headers:
HTTP_CONNECTION: close

Quite possibly the headers could be the problem, but also possible is that the Python code has access to a cookie jar and is adding cookies to the request the that the Node.JS code is not.

Another possibility is that your two clients are using two different TLS stacks (or at least 2 different configurations) and the NodeJS client is not able to negotiate an acceptable cypher.

I suggest you use a tool like Postman to manually try variants of requests to figure out which ones work and which ones do not. If you get it working in Postman, use Postman to export the code snippets for Python and NodeJS and confirm that they work. If the exported code works in Python but not NodeJS, then the problem is not the code.

Most likely the problem is something you are not aware of and therefore not telling us about. Have Postman export curl and wget commands, too, so you can verify that they work inside your Docker containers and that the issue is not with the container or Docker networking. Use curl -v to see what TLS cipher is being negotiated and configure NodeJS to only use that version of TLS and only that cipher, because Google likes to block clients that allow for downgrading to old broken TLS versions or weak ciphers.

Related