首页

关于andorid开发中使用https通讯对敏感数据进行安全传输

标签:android,https,敏感数据,通信,安全     发布时间:2017-11-05   

一、前言

敏感数据必须通过https传输,包括但不限于以下:

1、用户账号/密码。@b@2、用户登录验证状态,例如session ID、token、cookie。@b@3、用户个人信息,如信用卡号、身份证信息、手机号。

二、原代码示例

1.使用http通讯,安全要求和编码示例:a、不可以发送敏感数据、b、收到的数据可能来自攻击者,需要进行处理

HttpImageSearch.java@b@ @b@package org.jssec.android.https.imagesearch;@b@ @b@import android.os.AsyncTask;@b@import org.json.JSONException;@b@import org.json.JSONObject;@b@import java.io.BufferedInputStream;@b@import java.io.ByteArrayOutputStream;@b@import java.io.IOException;@b@import java.net.HttpURLConnection;@b@import java.net.URL;@b@ @b@public abstract class HttpImageSearch extends AsyncTask<String, Void, Object> {@b@ @b@       @Override@b@       protected Object doInBackground(String... params) {@b@              byte[] responseArray;@b@              // --------------------------------------------------------@b@              // Communication 1st time: Execute image search@b@              // --------------------------------------------------------@b@ @b@              // *** POINT 1 *** Sensitive information must not be contained in send data.@b@              // Send image search character string@b@              StringBuilder s = new StringBuilder();@b@              for (String param : params){@b@                     s.append(param);@b@                     s.append('+');@b@              }@b@              s.deleteCharAt(s.length() - 1);@b@ @b@              String search_url = "http://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=" + s.toString();@b@ @b@              responseArray = getByteArray(search_url);@b@              if (responseArray == null) {@b@                     return null;@b@              }@b@ @b@              // *** POINT 2 *** Suppose that received data may be sent from attackers.@b@              // This is sample, so omit the process in case of the searching result is the data from an attacker.@b@              // This is sample, so omit the exception process in case of JSON purse.@b@              String image_url;@b@              try {@b@                     String json = new String(responseArray);@b@                     image_url = new JSONObject(json).getJSONObject("responseData")@b@                     .getJSONArray("results").getJSONObject(0).getString("url");@b@              } catch(JSONException e) {@b@                     return e;@b@              }@b@ @b@              // --------------------------------------------------------@b@              // Communication 2nd time: Get images@b@              // --------------------------------------------------------@b@              // *** POINT 1 *** Sensitive information must not be contained in send data.@b@              if (image_url != null ) {@b@                     responseArray = getByteArray(image_url);@b@                     if (responseArray == null) {@b@                            return null;@b@                     }@b@              }@b@              // *** POINT 2 *** Suppose that received data may be sent from attackers.@b@                     return responseArray;@b@       }@b@ @b@       private byte[] getByteArray(String strUrl) {@b@              byte[] buff = new byte[1024];@b@              byte[] result = null;@b@              HttpURLConnection response;@b@              BufferedInputStream inputStream = null;@b@              ByteArrayOutputStream responseArray = null;@b@              int length;@b@ @b@              try {@b@                     URL url = new URL(strUrl);@b@                     response = (HttpURLConnection) url.openConnection();@b@                     response.setRequestMethod("GET"); response.connect();@b@                     checkResponse(response);@b@ @b@                     inputStream = new BufferedInputStream(response.getInputStream());@b@                     responseArray = new ByteArrayOutputStream();@b@                    @b@                     while ((length = inputStream.read(buff)) != -1) {@b@                            if (length > 0) {@b@                                   responseArray.write(buff, 0, length);@b@                            }@b@                     }@b@                     result = responseArray.toByteArray();@b@              } catch (IOException e) {@b@                     e.printStackTrace();@b@              } finally {@b@                     if (inputStream != null) {@b@                            try {@b@                                   inputStream.close();@b@                            } catch (IOException e) {@b@                                   // This is sample, so omit the exception process@b@                            }@b@              }@b@              if (responseArray != null) {@b@                     try {@b@                            responseArray.close();@b@                     } catch (IOException e) {@b@                            // This is sample, so omit the exception process@b@                     }@b@              }@b@       }@b@       return result; }@b@       private void checkResponse(HttpURLConnection response) throws IOException {@b@              int statusCode = response.getResponseCode();@b@              if (HttpURLConnection.HTTP_OK != statusCode) {@b@                     throw new IOException("HttpStatus: " + statusCode);@b@              }@b@       }@b@}
ImageSearchActivity.java@b@ @b@package org.jssec.android.https.imagesearch;@b@ @b@import android.app.Activity;@b@import android.graphics.Bitmap;@b@import android.graphics.BitmapFactory;@b@import android.os.AsyncTask;@b@import android.os.Bundle;@b@import android.view.View;@b@import android.widget.EditText;@b@import android.widget.ImageView;@b@import android.widget.TextView;@b@ @b@public class ImageSearchActivity extends Activity {@b@ @b@       private EditText mQueryBox;@b@       private TextView mMsgBox;@b@       private ImageView mImgBox;@b@       private AsyncTask<String, Void, Object> mAsyncTask ;@b@ @b@       @Override@b@       public void onCreate(Bundle savedInstanceState) {@b@              super.onCreate(savedInstanceState);@b@              setContentView(R.layout.activity_main);@b@              mQueryBox = (EditText)findViewById(R.id.querybox);@b@              mMsgBox = (TextView)findViewById(R.id.msgbox);@b@              mImgBox = (ImageView)findViewById(R.id.imageview);@b@       }@b@ @b@       @Override@b@       protected void onPause() {@b@              // After this, Activity may be deleted, so cancel the asynchronization process in advance.@b@              if (mAsyncTask != null) mAsyncTask.cancel(true);@b@              super.onPause();@b@       }@b@ @b@       public void onHttpSearchClick(View view) {@b@              String query = mQueryBox.getText().toString();@b@              mMsgBox.setText("HTTP:" + query);@b@              mImgBox.setImageBitmap(null);@b@ @b@              // Cancel, since the last asynchronous process might not have been finished yet.@b@              if (mAsyncTask != null) mAsyncTask.cancel(true);@b@ @b@              // Since cannot communicate by UI thread, communicate by worker thread by AsynchTask.@b@              mAsyncTask = new HttpImageSearch() {@b@              @Override@b@              protected void onPostExecute(Object result) {@b@                     // Process the communication result by UI thread.@b@                     if (result == null) {@b@                     mMsgBox.append("¥nException occurs¥n");@b@                     } else if (result instanceof Exception) {@b@                            Exception e = (Exception)result;@b@                            mMsgBox.append("¥nException occurs¥n" + e.toString());@b@                     }else{@b@                            // Exception process when image display is omitted here, since it's sample.@b@                            byte[] data = (byte[])result;@b@                            Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);@b@                            mImgBox.setImageBitmap(bmp);@b@                     }@b@              }@b@                     }.execute(query); // pass search character string and start asynchronous process@b@       }@b@ @b@       public void onHttpsSearchClick(View view) {@b@              String query = mQueryBox.getText().toString();@b@              mMsgBox.setText("HTTPS:" + query);@b@              mImgBox.setImageBitmap(null);@b@ @b@              // Cancel, since the last asynchronous process might not have been finished yet.@b@              if (mAsyncTask != null) mAsyncTask.cancel(true);@b@              // Since cannot communicate by UI thread, communicate by worker thread by AsynchTask.@b@              mAsyncTask = new HttpsImageSearch() {@b@                     @Override@b@                     protected void onPostExecute(Object result) {@b@                     // Process the communication result by UI thread.@b@                     if (result instanceof Exception) {@b@                            Exception e = (Exception)result;@b@                            mMsgBox.append("¥nException occurs¥n" + e.toString());@b@                     }else{@b@                            byte[] data = (byte[])result;@b@                            Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);@b@                            mImgBox.setImageBitmap(bmp);@b@                     }@b@              }@b@                     }.execute(query); // pass search character string and start asynchronous process@b@       }@b@}
AndroidManifest.xml@b@ @b@<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.jssec.android.https.imagesearch" android:versionCode="1" android:versionName="1.0">@b@ @b@       <uses-permission android:name="android.permission.INTERNET"/>@b@       <application@b@              android:icon="@drawable/ic_launcher"@b@              android:allowBackup="false"@b@              android:label="@string/app_name" >@b@              <activity@b@                     android:name=".ImageSearchActivity"@b@                     android:label="@string/app_name"@b@                     android:theme="@android:style/Theme.Light"@b@                     android:exported="true" >@b@                     <intent-filter>@b@                            <action android:name="android.intent.action.MAIN" />@b@                            <category android:name="android.intent.category.LAUNCHER" />@b@                     </intent-filter>@b@              </activity>@b@       </application>@b@</manifest>

三、安全代码示例

1.使用https,安全要求及编码示例:

1、url以https://开始@b@2、敏感数据可以包括其中。@b@3、处理收到的数据,确认其真实性。@b@4、处理SSLException。
HttpsImageSearch.java@b@ @b@package org.jssec.android.https.imagesearch;@b@ @b@import org.json.JSONException;@b@import org.json.JSONObject;@b@ @b@import android.os.AsyncTask;@b@ @b@import java.io.BufferedInputStream;@b@import java.io.ByteArrayOutputStream;@b@import java.io.IOException;@b@import java.net.HttpURLConnection;@b@import java.net.URL;@b@ @b@public abstract class HttpsImageSearch extends AsyncTask<String, Void, Object> {@b@       @Override@b@       protected Object doInBackground(String... params) {@b@              byte[] responseArray;@b@              // --------------------------------------------------------@b@              // Communication 1st time : Execute image search@b@              // --------------------------------------------------------@b@              // *** POINT 1 *** URI starts with https://.@b@              // *** POINT 2 *** Sensitive information may be contained in send data.@b@              StringBuilder s = new StringBuilder();@b@              for (String param : params){@b@                     s.append(param);@b@                     s.append('+');@b@              }@b@              s.deleteCharAt(s.length() - 1);@b@             @b@              String search_url = "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=" + s.toString();@b@             @b@              responseArray = getByteArray(search_url);@b@              if (responseArray == null) {@b@                     return null;@b@              }@b@ @b@              // *** POINT 3 *** Handle the received data carefully and securely,@b@              // even though the data was sent from the server connected by HTTPS.@b@              // Omitted, since this is a sample. Please refer to "3.2 Handling Input Data Carefully and Securely."@b@              String image_url;@b@              try {@b@                     String json = new String(responseArray);@b@                     image_url = new JSONObject(json).getJSONObject("responseData")@b@                     .getJSONArray("results").getJSONObject(0).getString("url");@b@              } catch(JSONException e) {@b@                     return e; }@b@                    @b@              // --------------------------------------------------------@b@              // Communication 2nd time : Get image@b@              // --------------------------------------------------------@b@              // *** POINT 1 *** URI starts with https://.@b@              // *** POINT 2 *** Sensitive information may be contained in send data.@b@              if (image_url != null ) {@b@                     responseArray = getByteArray(image_url);@b@                     if (responseArray == null) {@b@                            return null;@b@                     }@b@              }@b@ @b@              return responseArray;@b@       }@b@       private byte[] getByteArray(String strUrl) {@b@              byte[] buff = new byte[1024];@b@              byte[] result = null;@b@              HttpURLConnection response;@b@              BufferedInputStream inputStream = null;@b@              ByteArrayOutputStream responseArray = null;@b@              int length;@b@ @b@              try {@b@                     URL url = new URL(strUrl);@b@                     response = (HttpURLConnection) url.openConnection();@b@                     response.setRequestMethod("GET"); response.connect();@b@                     checkResponse(response);@b@ @b@                     inputStream = new BufferedInputStream(response.getInputStream());@b@                     responseArray = new ByteArrayOutputStream();@b@ @b@                     while ((length = inputStream.read(buff)) != -1) {@b@                            if (length > 0) {@b@                                   responseArray.write(buff, 0, length);@b@                            }@b@                     }@b@                     result = responseArray.toByteArray();@b@              } catch (IOException e) {@b@                     e.printStackTrace();@b@              } finally {@b@                     if (inputStream != null) {@b@                            try {@b@                                   inputStream.close();@b@                            } catch (IOException e) {@b@                                   // This is sample, so omit the exception process@b@                            }@b@                     }@b@ @b@                     if (responseArray != null) {@b@                            try {@b@                                   responseArray.close();@b@                            } catch (IOException e) {@b@                                   // This is sample, so omit the exception process@b@                            }@b@                     }@b@              }@b@              return result;@b@       }@b@ @b@       private void checkResponse(HttpURLConnection response) throws IOException {@b@              int statusCode = response.getResponseCode();@b@              if (HttpURLConnection.HTTP_OK != statusCode) {@b@                     throw new IOException("HttpStatus: " + statusCode);@b@              }@b@       }@b@}

2.使用https 私有证书,安全要求和编码示例:

1、确认私有证书的颁发机构。@b@2、url以http://开始@b@3、敏感数据可以发送@b@4、接收 到的数据可以被信任。@b@5、处理SSLException
PrivateCertificathettpsGet.java@b@ @b@package org.jssec.android.https.privatecertificate;@b@ @b@import java.io.BufferedInputStream;@b@import java.io.ByteArrayOutputStream;@b@import java.io.IOException;@b@import java.net.HttpURLConnection;@b@import java.net.URL;@b@import java.security.KeyStore;@b@import java.security.SecureRandom;@b@import javax.net.ssl.HostnameVerifier;@b@import javax.net.ssl.HttpsURLConnection;@b@import javax.net.ssl.SSLContext;@b@import javax.net.ssl.SSLException;@b@import javax.net.ssl.SSLSession;@b@import javax.net.ssl.TrustManagerFactory;@b@import android.content.Context;@b@import android.os.AsyncTask;@b@ @b@public abstract class PrivateCertificateHttpsGet extends AsyncTask<String, Void, Object> {@b@ @b@       private Context mContext;@b@ @b@       public PrivateCertificateHttpsGet(Context context) {@b@              mContext = context;@b@       }@b@ @b@       @Override@b@       protected Object doInBackground(String... params) {@b@              TrustManagerFactory trustManager;@b@              BufferedInputStream inputStream = null;@b@              ByteArrayOutputStream responseArray = null;@b@              byte[] buff = new byte[1024];@b@              int length;@b@ @b@              try {@b@                     URL url = new URL(params[0]);@b@                     // *** POINT 1 *** Verify a server certificate with the root certificate of a private certificate authorit@b@                     // Set keystore which includes only private certificate that is stored in assets, to client.@b@                     KeyStore ks = KeyStoreUtil.getEmptyKeyStore();@b@                     KeyStoreUtil.loadX509Certificate(ks,mContext.getResources().getAssets().open("cacert.crt"));@b@ @b@                     // *** POINT 2 *** URI starts with https://.@b@                     // *** POINT 3 *** Sensitive information may be contained in send data.@b@                     trustManager = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());@b@                     trustManager.init(ks);@b@                     SSLContext sslCon = SSLContext.getInstance("TLS");@b@                     sslCon.init(null, trustManager.getTrustManagers(), new SecureRandom());@b@                    @b@                     HttpURLConnection con = (HttpURLConnection)url.openConnection();@b@                     HttpsURLConnection response = (HttpsURLConnection)con;@b@                     response.setDefaultSSLSocketFactory(sslCon.getSocketFactory());@b@                    @b@                     response.setSSLSocketFactory(sslCon.getSocketFactory());@b@                     checkResponse(response);@b@ @b@                     // *** POINT 4 *** Received data can be trusted as same as the server.@b@                     inputStream = new BufferedInputStream(response.getInputStream());@b@                     responseArray = new ByteArrayOutputStream();@b@                     while ((length = inputStream.read(buff)) != -1) {@b@                            if (length > 0) {@b@                                   responseArray.write(buff, 0, length);@b@                            }@b@                     }@b@                     return responseArray.toByteArray();@b@              } catch(SSLException e) {@b@                     // *** POINT 5 *** SSLException should be handled with an appropriate sequence in an application.@b@                     // Exception process is omitted here since it's sample.@b@                     return e;@b@                     } catch(Exception e) {@b@                            return e;@b@                     } finally {@b@                     if (inputStream != null) {@b@                            try {@b@                                   inputStream.close();@b@                            } catch (Exception e) {@b@                                   // This is sample, so omit the exception process@b@                            }@b@                     }@b@                     if (responseArray != null) {@b@                            try {@b@                                   responseArray.close();@b@                            } catch (Exception e) {@b@                                   // This is sample, so omit the exception process@b@                            }@b@                     }@b@              }@b@       }@b@ @b@       private void checkResponse(HttpURLConnection response) throws IOException {@b@              int statusCode = response.getResponseCode();@b@              if (HttpURLConnection.HTTP_OK != statusCode) {@b@                     throw new IOException("HttpStatus: " + statusCode);@b@              }@b@       }@b@}
KeyStoreUtil.java@b@ @b@package org.jssec.android.https.privatecertificate;@b@ @b@import java.io.IOException;@b@import java.io.InputStream;@b@import java.security.KeyStore;@b@import java.security.KeyStoreException;@b@import java.security.NoSuchAlgorithmException;@b@import java.security.cert.Certificate;@b@import java.security.cert.CertificateException;@b@import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate;@b@import java.util.Enumeration;@b@ @b@public class KeyStoreUtil {@b@       public static KeyStore getEmptyKeyStore() throws KeyStoreException,@b@              NoSuchAlgorithmException, CertificateException, IOException {@b@                     KeyStore ks = KeyStore.getInstance("BKS");@b@                     ks.load(null);@b@                     return ks;@b@       }@b@ @b@       public static void loadAndroidCAStore(KeyStore ks)throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {@b@              KeyStore aks = KeyStore.getInstance("AndroidCAStore");@b@              aks.load(null);@b@              Enumeration<String> aliases = aks.aliases();@b@              while (aliases.hasMoreElements()) {@b@                     String alias = aliases.nextElement();@b@                     Certificate cert = aks.getCertificate(alias);@b@                     ks.setCertificateEntry(alias, cert);@b@              }@b@       }@b@ @b@       public static void loadX509Certificate(KeyStore ks, InputStream is) throws CertificateException, KeyStoreException {@b@              try {@b@                     CertificateFactory factory = CertificateFactory.getInstance("X509");@b@                     X509Certificate x509 = (X509Certificate)factory.generateCertificate(is);@b@                     String alias = x509.getSubjectDN().getName();@b@                     ks.setCertificateEntry(alias, x509);@b@              } finally {@b@                     try { is.close(); } catch (IOException e) { /* This is sample, so omit the exception process */@b@                     }@b@              }@b@       }@b@}
PrivateCertificathettpsActivity.java@b@ @b@package org.jssec.android.https.privatecertificate;@b@ @b@import android.app.Activity;@b@import android.graphics.Bitmap;@b@import android.graphics.BitmapFactory;@b@import android.os.AsyncTask;@b@import android.os.Bundle;@b@import android.view.View;@b@import android.widget.EditText;@b@import android.widget.ImageView;@b@import android.widget.TextView;@b@ @b@public class PrivateCertificateHttpsActivity extends Activity {@b@ @b@       private EditText mUrlBox;@b@       private TextView mMsgBox;@b@       private ImageView mImgBox;@b@       private AsyncTask<String, Void, Object> mAsyncTask ;@b@ @b@       @Override@b@       public void onCreate(Bundle savedInstanceState) {@b@              super.onCreate(savedInstanceState);@b@              setContentView(R.layout.activity_main);@b@              mUrlBox = (EditText)findViewById(R.id.urlbox);@b@              mMsgBox = (TextView)findViewById(R.id.msgbox);@b@              mImgBox = (ImageView)findViewById(R.id.imageview);@b@       }@b@ @b@       @Override@b@       protected void onPause() {@b@              // After this, Activity may be discarded, so cancel asynchronous process in advance.@b@              if (mAsyncTask != null) mAsyncTask.cancel(true);@b@              super.onPause();@b@       }@b@      @b@       public void onClick(View view) {@b@              String url = mUrlBox.getText().toString();@b@              mMsgBox.setText(url);@b@              mImgBox.setImageBitmap(null);@b@ @b@              // Cancel, since the last asynchronous process might have not been finished yet.@b@              if (mAsyncTask != null) mAsyncTask.cancel(true);@b@ @b@ @b@              // Since cannot communicate through UI thread, communicate by worker thread by AsynchTask.@b@              mAsyncTask = new PrivateCertificateHttpsGet(this) {@b@                     @Override@b@                     protected void onPostExecute(Object result) {@b@                            // Process the communication result through UI thread.@b@                            if (result instanceof Exception) {@b@                                   Exception e = (Exception)result;@b@                                   mMsgBox.append("¥nException occurs¥n" + e.toString());@b@                            }else{@b@                                   byte[] data = (byte[])result;@b@                                   Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);@b@                                   mImgBox.setImageBitmap(bmp);@b@                            }@b@                     }@b@              }.execute(url); // Pass URL and start asynchronization process }@b@       }            @b@}