Hello I have an android application inserting data to mysql database with php. My insert code works perfect on Avd and my android phone. But it gives error on tablet. My tablet is connected to wireless internet and other parts of application works fine and getting data from json. What is the difference between devices about this error?
try{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.mysite.com/android3.php");
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
Log.e("pass 1", "connection success ");
}
catch(Exception e){
Log.e("Fail 1", e.toString());
Toast.makeText(getApplicationContext(), "error error error", Toast.LENGTH_LONG).show();
}
It might be because of : http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html
This was introduced in API 11 and android allows network calls on main thread in previous versions without throwing an error.
I'm just about done working on an app for a local gym, and as my testing is nearly complete, and a version 1 is nearly finished, I'm starting to think about securing the app against any MITM type attacks. While I know the chances are next to zero of someone even wanting to MITM this app (as opposed to say, a banking app), I would still like to be a little proactive in security.
While the app sends/receives no user information (data sent back and forth is stuff like weight, reps, time, the name of the class the user checks in to, etc.), I am transmitting the names of all active gym members (to be used for an auto complete text box). I would like to encrypt the names, but I've been finding it difficult to change my code from HTTP to HTTPS. I've got HTTPS and a self-signed cert on my server, but can't seem to get the android side to work (keep getting no peer cert errors in eclipse). As a work around, I've thought about using AES128 to encrypt/hash each name, then decrypt it on the phone, and then likewise do the same when sending data back through PHP to the database.
Is this a sufficient alternative to encrypting the entire session? Call it "Lazy SSL", as if someone were to get the key, they would be able to decrypt the data, but again, we are only transmitting names, no other user information.
Here is the unencrypted code I'm using (I left out unnecessary stuff to make this block smalller):
public JSONObject makeHttpRequest(String url, String method, List<NameValuePair> params) {
if (method == "POST") {
// request method is POST
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new UrlEncodedFormEntity(params));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}
This is in a larger class used for parsing Json:
My entire JSONParser class
I'm calling this class in places I need to pull or send data to the server, such as the following:
final JSONParser jsonParser = new JSONParser();
final List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("tag", Globals.TAG_GETMEMBERS));
params.add(new BasicNameValuePair("LastRow", lastRow));
// getting JSON string from URL
final JSONObject json = jsonParser.makeHttpRequest(
Globals.WEBSERVICE_URL, "POST", params);
using various resources:
How to enable a self-signed certificate for SSL sockets on Android?
http://randomizedsort.blogspot.com/2010/09/step-to-step-guide-to-programming.html
I was able to get something useful, I originally tried doing the "trust all certs" method, but since that is MITM prone, I would rather not use it (plus it wasn't working. Using the 2nd link I've gotten so far as re-generating the cert, I've downloaded the bouncy castle jar (
I also used the following commands to generate a keystore, and import it into my project:
keytool -genkey -dname "cn = smashwebserver, ou=Development Team, o=Smash Gyms, L=Sunnyvale, s=California, c=US" -alias ssltest -keypass ssltest -keystore c:\dell\ssltest.keystore -storepass ssltest -validity 180
keytool -export -alias ssltest -keystore c:\dell\ssltest.keystore -file c:\dell\ssltest.cer -storepass ssltest -keypass ssltest
keytool -import -alias ssltestcert -file C:\dell\ssltest.cer -keypass ssltestcert -keystore "C:\Users\Evan Richardson\workspace\SmashGyms\res\raw\ssltestcert" -storetype BKS -storepass ssltestcert -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "C:\Users\Evan Richardson\workspace\SmashGyms\libs\bcprov-jdk15on-147.jar"
The resulting JSONParser class block looks like this:
if (method == "POST") {
// Load the self-signed server certificate
char[] passphrase = "ssltest".toCharArray();
KeyStore ksTrust = KeyStore.getInstance("BKS");
ksTrust.load(context.getResources().openRawResource(
R.raw.ssltestcert), passphrase);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
tmf.init(ksTrust);
// Create a SSLContext with the certificate
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(),
new SecureRandom());
// request method is POST
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new UrlEncodedFormEntity(params));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}
however now I get the following error:
10-29 11:55:28.470: W/System.err(9561): java.io.IOException: Wrong version of key store.
I looked that error up, and a possible solution was found here:Android bouncy castle: IOException
I've downloaded the 145 version of bouncycastles Jar, and used that. This fixes the ioexception error, but now I get the following:
10-29 12:21:57.536: W/System.err(12506): Catch exception while startHandshake: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x10b9a10: Failure in SSL library, usually a protocol error
10-29 12:21:57.536: W/System.err(12506): error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol (external/openssl/ssl/s23_clnt.c:683 0x4026dced:0x00000000)
10-29 12:21:57.536: W/System.err(12506): return an invalid session with invalid cipher suite of SSL_NULL_WITH_NULL_NULL
10-29 12:21:57.586: W/System.err(12506): javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
Strangely enough, if I change my url to "https://google.com", I don't get any errors, just the following:
10-29 14:03:50.198: V/httpresponsetag:(17810): <!DOCTYPE html>
10-29 14:03:50.198: V/httpresponsetag:(17810): <html lang=en>
10-29 14:03:50.198: V/httpresponsetag:(17810): <meta charset=utf-8>
10-29 14:03:50.198: V/httpresponsetag:(17810): <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
10-29 14:03:50.198: V/httpresponsetag:(17810): <title>Error 405 (Method Not Allowed)!!1</title>
10-29 14:03:50.198: V/httpresponsetag:(17810): <style>
10-29 14:03:50.198: V/httpresponsetag:(17810): *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}#media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}
10-29 14:03:50.198: V/httpresponsetag:(17810): </style>
10-29 14:03:50.198: V/httpresponsetag:(17810): <a href=//www.google.com/><img src=//www.google.com/images/errors/logo_sm.gif alt=Google></a>
10-29 14:03:50.198: V/httpresponsetag:(17810): <p><b>405.</b> <ins>That’s an error.</ins>
10-29 14:03:50.198: V/httpresponsetag:(17810): <p>The request method <code>POST</code> is inappropriate for the URL <code>/</code>. <ins>That’s all we know.</ins>
This may indicate it's in fact my self signed cert, but if i open up https:servername, it works (of course with the default warning)
EDIT:
I was getting the same errors even with accepting all certs, so i went and looked in my browser with the hostname I'm using, same error. I then looked at my NAT settings on my router...I was forwarding to port 80, instead of 443. FAIL. changed to 443, now it looks like it's working, at least with accepting all certs and the following code:
public JSONObject makeHttpRequest(String url, String method,
List<NameValuePair> params) throws NoSuchAlgorithmException,
CertificateException, NotFoundException, KeyStoreException,
KeyManagementException {
// Making HTTP request
try {
// check for request method
if (method == "POST") {
// request method is POST
// defaultHttpClient
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs,
String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs,
String authType) {
}
} };
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts,
new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc
.getSocketFactory());
} catch (Exception e) {
}
// Now you can access an https URL without having the certificate in the truststore
HttpClient client = new DefaultHttpClient();
client = this.sslClient(client);
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new UrlEncodedFormEntity(params));
// Log.v(TAG, EntityUtils.toString(result.getEntity()));
HttpResponse httpResponse = client.execute(httpPost);
// Log.v("httpresponsetag:", EntityUtils.toString(httpResponse
// .getEntity()));
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}
Forget about re-inventing lazy-SSL or whatever. Simply use SSL and fix your code. And do not turn off certificate verification and trust all certificates. Using a self-signed certificate is not particularly difficult, post what you have tried and people will point you in the right direction. Generally you need to:
get the certificate
put it in a raw resource in your app
read it and initialize a KeyStore with it
pass this to your SSL socket factory
initialize your HTTP client with the socket factory from 4.
This is how to do it if you are using HttpClient, the point is registering the SSLSocketFactory:
KeyStore ts = KeyStore.getInstance("BKS");
InputStream in = getResources().openRawResource(R.raw.mytruststore);
ts.load(in, TRUSTSTORE_PASSWORD.toCharArray());
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(ts);
schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
HttpParams params = new BasicHttpParams();
ClientConnectionManager cm =
new ThreadSafeClientConnManager(params, schemeRegistry);
HttpClient client = new DefaultHttpClient(cm, params);
See this for more examples, a sample project and some background information: http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html
I don't see why you would want to work around SSL and invent your own encryption scheme. I have a feeling your self-signed cert is causing you issues, perhaps you need to turn off verifying the self-signed cert in eclipse?
I understand you are working with ssl but there is one alternative if you would like. It is using encode and decode.
function encodeString($ss,$ntime){
for($i=0;$i<$ntime;$i++){
$ss=base64_encode($ss);
}
return $ss;
}
function decodeString($ss,$ntime){
for($i=0;$i<$ntime;$i++){
$ss=base64_decode($ss);
}
return $ss;
}
You can use it like,
encodeString("$membername", 3); //3 will make the encryption more strong. Higher the value higher the encryption.
decodeString("$membername", 3); //decodes the member name.
when sending data to a php server through android I cam across this error: "Notice: Undefined index: IT in C:\xampp\htdocs\hello.php on line 4". After a few hours of messing around with it I can't solve my issue.
hello.php :
<?php
mysql_connect("localhost","user","pass");
mysql_select_db("mmo");
$r=mysql_query("update players set X = '".$_REQUEST['IT']."' where 22=22");
if(!$r)
echo "Error in query: ".mysql_error();
mysql_close();
header('Refresh: 0.01; URL=http://localhost/hello.php');
?>
update method in android:
public void UpdateSeverWithPlayer()
{List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("IT","3"));
try{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://10.0.2.2/hello.php");
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
}catch(Exception e){
Log.e("log_tag", "Error in http connection"+e.toString());
}}
I am working on the android emulator and do have the internet permission. As always help is greatly appreciated.
EDIT 1: It appears the issue is in the android and not the php code.
You're not sending your query string propertly somehow, so there is no $_REQUEST['IT'] on the PHP side. do a var_dump($_REQUEST) to see what's coming through. Or better yet, don't use $_REQUEST. It's somewhat insecure. Better use the superglobal directly related to your HTTP method, _GET or _POST.
As well, the Refresh header is non-standard. it'll work, but you shouldn't depend on it. An HTTP level redirect uses the Location: header. Refresh: is a non-standard old-school Netscape extension.
I had some problem understanding the following line of code. What exactly does it do and how does it help me query the database from android
$q=mysql_query("SELECT * FROM people WHERE birthyear>'".$_REQUEST['year']."'");
while($e=mysql_fetch_assoc($q))
$output[]=$e;
print(json_encode($output));
I know the initial part of it means select every record from table people where birthyear...
But after that I get confused. I am calling this php function from android using http post
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("year","1980"));
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://10.0.2.2/retrieve.php");
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
Where is an input stream. Can someone help me out?
The PHP code queries the database and constructs a JSON output, which it sends to the calling client. Try calling the php from a browser (put the URL in the address bar) - and you should get the JSON back.
On the Android side, java code is using HTTPClient wrapper to call your php and get the response. Socket (HTTP connection) InputStream is handled internally by HttpClient when you call relevant methods. From your point of view, all you need to do is deal with the content of the entity.
You can just open the input stream from the entity (your is variable) and read the data from it:
InputStream is = entity.getContent();
then read the content of the stream as you normally would. You should get the json as was sent by the php.
PHP gets the value of required minimum year from year request parameter. In android, a NameValuePair is created with name=year and value=1980. This NameValuePair is passed as POST parameter in the form year=1980 to the PHP code. Again, this is handled internally by the HTTPClient wrapper class. Then the PHP code reads the value of request parameter "year" to get the minimum value for the query.
In the above code is is the instance of InputStream entity.getContent() returns InputStream type object. In the line is = entity.getContent(); is is the InputStream
i have been trying to call a PHP script with the android system. i am using Eclipse helio and everything else i have written works fine on it - not much yet. so i block copied this code and it does not work: i have no warnings or errors and i can debug and step through it, but it always comes back with
"E log_tag : Error in http connection java.net.UnknownHostException: www.X.com"
here is the code:
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("Lat","19.80"));
nameValuePairs.add(new BasicNameValuePair("Lon","13.22"));
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.X.com/new/getAllPeopleBornAfter.php");
try{
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
Log.i("postData", response.getStatusLine().toString());
}
catch(Exception e)
{
Log.e("log_tag", "Error in http connection "+e.toString());
}
and the PHP which runs fine if i go there with a browser:
mysql_connect("mysql27.x.com","name","PW");
mysql_select_db("dbname");
$q = mysql_query("SELECT * FROM people");
while ($e = mysql_fetch_assoc($q)) $output[] = $e;
mysql_close();
echo (json_encode($output));
?>
if you guys want me to run anything in a different format or any more info - please let me know - i cant find any thing more than just unknownhostexception
Can you access www.X.com from the emulator/phone?
Do you have the INTERNET permission?
Did you remember to put:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
into your manifest file?
Are you behind a proxy network? Should you be setting the proxy ip address and port number? I'm no good with php. But I get this error when I try to connect to the internet through java programs. The solution works good for me.