一、前言
敏感数据必须通过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@}