Network.request Failing On Android Over Ssl

Hello all.

 

I’m having problems when testing an app on my HTC Sensation running Android 4.0.3

 

I am calling network.request to authorise a login on our web server which returns xml that I then parse in lua to log the user into the app.

 

The code I use to make the network request is as follows:

 

     network.request( myServerURL, “GET”, processLogin )

 

This works very nicely if I use http, but when I use https the processLogin function picks up event.isError

 

So it appears that either there is a bug when using SSL for network.request with Android or I have missed something.

 

The script works fine on all iOS devices with SSL.  It only works via http on my Android though.

 

I am using the latest daily build of Corona which is (as of today) Version 2013.1058 (2013.3.20).

 

I have the following in my build.settings file.

 

    android =

    {

        usesPermissions =

        {

            “android.permission.INTERNET”,

            “android.permission.WRITE_EXTERNAL_STORAGE”,

        },

    },

 

Any ideas very welcome.

 

Thank you!

Hi,

it seems, that we have the same problem (http://forums.coronalabs.com/topic/33984-problems-with-https-and-android/). But you had it a month longer than me… :wink: So maybe you have some clues for me? Could you solve your problem?

Thanks,

Laryllan

Hi

No, I’m afraid I didn’t solve this one.  I think it’s a corona bug rather than anything I’m doing incorrectly.  So sorry, I don’t have any good news for you. 

Corona?  Any ideas please?

Thanks

D

Network requests to https URLs work for me on my Android devices.  I’ve tested it with our sample project “Networking/AsynchHTTP” that is included with the Corona SDK which sends a network request to “https://encrypted.google.com”.  I suggest that you try building that sample project as-is and running it on your Android device.  The result of the test will be outputted to the Android log, which you can access via Android SDK tool “adb logcat” or “ddms”.

Now, typically when I see tech-support issues about network requests working on iOS but not Android, most of the time its because the developer forgot to add HTTP headers to their requests.  You see, Mac and iOS add the following headers to all network requests if you do not provide them…

  ACCEPT: */*
  ACCEPT-LANGUAGE: en-us
  ACCEPT-ENCODING: gzip, deflate

Windows and Android do not add the above header.

(Edit: Android 3.x and above will add the Accept-Encoding gzip header, but older versions will not.)

So, I suggest that you first find out what headers the server you are connecting to requires.  Perhaps try including the above headers, but please note that Windows and Android will not automatically decompress gzip responses (unlike iOS and Mac).  So, I suggest that you set the encoding header to an empty string for maximum compatibility between all platforms…

  ACCEPT-ENCODING:

Odds are, its an encoding issue.  So, make sure to try the above header.

Hi Joshua,

thanks for your reply. As I wrote in my other topic (http://forums.coronalabs.com/topic/33984-problems-with-https-and-android/) the connection to “https://encrypted.google.com” does work - even on Android devices. But I totally have problems with my own url (“https://xxx.grothe-gruppe.de:4444/tools/mobile/read.aspx?f=1&action=ping”) where I always get “event.isError == true” - although this does perfectly work in win simulator, mac simulator and iOS device.

I tried some different but I still did not get it to work. You wrote “… that you first find out what headers the servers youe are connecting to requires…”. How can I get these information? Here is my code that I have tried. Maybe you can help me… Thanks!

Greetings,

Kai

----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- local widget = require("widget") -- Your code here local lblStatus = display.newText("", display.contentWidth / 2, 220, native.systemFont, 16) lblStatus.text = "Please tap a button" local btnTest1 = widget.newButton{ left = 20, top = 100, width = display.contentWidth - 40, height = 40, label = "https://encrypted.google.com", onEvent = function(evt) if evt.phase == "ended" then tryRequest("https://encrypted.google.com") end end } local btnTest2 = widget.newButton{ left = 20, top = 150, width = display.contentWidth - 40, height = 40, label = "test url", onEvent = function(evt) if evt.phase == "ended" then tryRequest("https://xxx.grothe-gruppe.de:4444/tools/mobile/read.aspx?f=1&action=ping") end end } function tryRequest(url) network.request(url, "GET", function(evt) if evt.isError then lblStatus.text = "Error..." else lblStatus.text = "Success!" end end, { headers = { ["accept"] = "\*/\*", ["accept-charset"] = "\*", ["accept-language"] = "de-DE", ["accept-encoding"] = "" -- I also tried "gzip,deflate,sdch" } }) lblStatus.text = "Please wait..." end

I tried to hit the URL by hand with my browser and it’s throwing a security exception.  I had to jump through all the Firefox hoops to accept it and so on.  Perhaps you’re getting the error because your SSL certificates are not setup correctly and your site is considered untrusted.

Hi Rob,

thanks for trying this out. This is absolute possible… We just used this certificate to get it done as quickly as possible. So is there any possibility with Corona to accept this certificate or to trust this site anyway?

Thanks!

Hi Rob

Thanks for following this up.  I need to read through it all properly. Just to add to the pot that the SSL on our server is definitely configured properly.

Cheers

D

Laryllan,

Just to let you know, I was able to reproduce your issue on my Android device.  In fact, I’ve noticed the following error message in the Android log just before the network Lua listener gets called…

>> I/System.out(19926): ERROR: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

This means that Android does not like/trust the certificate.  In fact, my Safari web browser throws a fit about the certificate as well.

But that said, I can look into changing our Android network API to trust all certificates.  I imagine if you’re making a request to an untrusted URL from within your own code, then of course you trust it… and iOS, Mac, and Windows appears to ignore certificates anyways.

Doug, what URL are you trying to access?

Everyone,

We’ve just tested doing a newtork.request() with an HTTPS URL having an untrusted certificate on Mac, Windows, iOS, and Android.  All platforms return “event.isError” true when the certificate is considered untrusted by the operating system.  After discussing it with the rest of the team here, we believe that this is the correct behavior.

So, I would suggest that you connect via HTTP during testing until you are ready to purchase a valid certificate and ready to deploy.  That would be my best suggestion.

Just to throw my two cents in Joshua, I’ve got an SSL host I’m using https with, and I am sending gets, posts and everything else back and forth through network request and it’s working great - iOS and Android…

Had trouble with cookie persistence on android, but once my app stored PHP_SESSID on the client, and sent it back in the headers, my servers were happy with everything…  Messages, pngs (throw in base64 encoding for that…), it’s all good in https as far as I’m concerned… just various server side (and platform side) hoops to identify - and then jump through…

Hi Joshua,

when I read your first answer I have been really happy. As you wrote:

 imagine if you’re making a request to an untrusted URL from within your own code, then of course you trust it…

That’s exactly the point! Although I can understand your point of your second answer (that there should be an error on all devices), it would be great if there would be the possibilty to ignore these errors because I certainly do trust this url.

My problem is a little bit more complicated. The app is thought for our customers as an addition to another one of our products they have bought already. In the app the customers can enter the URL of their own server and the app will communicate with THAT server. So everyone of our customers would have to buy their own valid certificate or to use a non-secure connection via http.

Maybe you and your team can think about it again… It would be really, really helpful if there is the possibility to accept these certificates anyway!

Thanks,

Laryllan

Laryllan,

The reason we decided it was not a good idea was for security reasons.  What I didn’t think of at the time was what it the HTTPS URL was expected to point to a trusted website, but a proxy server or host file caused it to be redirected to an untrusted site to steal information.  For example, a popular app that wants to verify in-app purchases, but its network requests get redirected to an untrusted site that always responds that everything is verified.

In this case, we think it would actually be better for the developer to opt-in to trusting an invalid certificate (say for testing purposes) instead of making that the default.  So, making it a network.request() option would be better.  I’m also thinking that providing more error information via the network event such as “connectionError”, “responseTimeout”, or “certificateError” would be useful as well, because right now you cannot identify exactly why the request failed.

I’m sorry about backpedaling on this.  I didn’t think it through at the time.

Hi Joshua,

making it a network.request() option would be better

more error information via the network event such as “connectionError”, “responseTimeout”, or “certificateError”

These are great news! Both of these suggestions would help very much! It would be great to get them soon.

Thanks,

Laryllan

Hi,

it seems, that we have the same problem (http://forums.coronalabs.com/topic/33984-problems-with-https-and-android/). But you had it a month longer than me… :wink: So maybe you have some clues for me? Could you solve your problem?

Thanks,

Laryllan

Hi

No, I’m afraid I didn’t solve this one.  I think it’s a corona bug rather than anything I’m doing incorrectly.  So sorry, I don’t have any good news for you. 

Corona?  Any ideas please?

Thanks

D

Network requests to https URLs work for me on my Android devices.  I’ve tested it with our sample project “Networking/AsynchHTTP” that is included with the Corona SDK which sends a network request to “https://encrypted.google.com”.  I suggest that you try building that sample project as-is and running it on your Android device.  The result of the test will be outputted to the Android log, which you can access via Android SDK tool “adb logcat” or “ddms”.

Now, typically when I see tech-support issues about network requests working on iOS but not Android, most of the time its because the developer forgot to add HTTP headers to their requests.  You see, Mac and iOS add the following headers to all network requests if you do not provide them…

  ACCEPT: */*
  ACCEPT-LANGUAGE: en-us
  ACCEPT-ENCODING: gzip, deflate

Windows and Android do not add the above header.

(Edit: Android 3.x and above will add the Accept-Encoding gzip header, but older versions will not.)

So, I suggest that you first find out what headers the server you are connecting to requires.  Perhaps try including the above headers, but please note that Windows and Android will not automatically decompress gzip responses (unlike iOS and Mac).  So, I suggest that you set the encoding header to an empty string for maximum compatibility between all platforms…

  ACCEPT-ENCODING:

Odds are, its an encoding issue.  So, make sure to try the above header.

Hi Joshua,

thanks for your reply. As I wrote in my other topic (http://forums.coronalabs.com/topic/33984-problems-with-https-and-android/) the connection to “https://encrypted.google.com” does work - even on Android devices. But I totally have problems with my own url (“https://xxx.grothe-gruppe.de:4444/tools/mobile/read.aspx?f=1&action=ping”) where I always get “event.isError == true” - although this does perfectly work in win simulator, mac simulator and iOS device.

I tried some different but I still did not get it to work. You wrote “… that you first find out what headers the servers youe are connecting to requires…”. How can I get these information? Here is my code that I have tried. Maybe you can help me… Thanks!

Greetings,

Kai

----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- local widget = require("widget") -- Your code here local lblStatus = display.newText("", display.contentWidth / 2, 220, native.systemFont, 16) lblStatus.text = "Please tap a button" local btnTest1 = widget.newButton{ left = 20, top = 100, width = display.contentWidth - 40, height = 40, label = "https://encrypted.google.com", onEvent = function(evt) if evt.phase == "ended" then tryRequest("https://encrypted.google.com") end end } local btnTest2 = widget.newButton{ left = 20, top = 150, width = display.contentWidth - 40, height = 40, label = "test url", onEvent = function(evt) if evt.phase == "ended" then tryRequest("https://xxx.grothe-gruppe.de:4444/tools/mobile/read.aspx?f=1&action=ping") end end } function tryRequest(url) network.request(url, "GET", function(evt) if evt.isError then lblStatus.text = "Error..." else lblStatus.text = "Success!" end end, { headers = { ["accept"] = "\*/\*", ["accept-charset"] = "\*", ["accept-language"] = "de-DE", ["accept-encoding"] = "" -- I also tried "gzip,deflate,sdch" } }) lblStatus.text = "Please wait..." end

I tried to hit the URL by hand with my browser and it’s throwing a security exception.  I had to jump through all the Firefox hoops to accept it and so on.  Perhaps you’re getting the error because your SSL certificates are not setup correctly and your site is considered untrusted.