安卓应用安全指南 5.4.1 通过 HTTPS 的通信 示例代码

本文涉及的产品
Digicert DV 证书 单域名,20个 3个月
图像搜索,7款服务类型 1个月
简介: 5.4.1 通过 HTTPS 的通信 示例代码 原书:Android Application Secure Design/Secure Coding Guidebook 译者:飞龙 协议:CC BY-NC-SA 4.0你可以通过下面的图表(图 5.4-1)找出你应该实现的 HTTP / HTTPS 通信类型。

5.4.1 通过 HTTPS 的通信 示例代码

原书:Android Application Secure Design/Secure Coding Guidebook

译者:飞龙

协议:CC BY-NC-SA 4.0

你可以通过下面的图表(图 5.4-1)找出你应该实现的 HTTP / HTTPS 通信类型。

当发送或接收敏感信息时,将使用 HTTPS 通信,因为其通信通道使用 SSL / TLS 加密。 以下敏感信息需要 HTTPS 通信。

  • Web 服务的登录 ID /密码。
  • 保持认证状态的信息(会话 ID,令牌,Cookie 等)
  • 取决于 Web 服务的重要/机密信息(个人信息,信用卡信息等)

具有网络通信的智能手机应用是“系统”和 Web 服务器的一部分。 而且你必须根据整个“系统”的安全设计和编码,为每个通信选择 HTTP 或 HTTPS。 表 5.4-1 用于比较 HTTP 和 HTTPS。 表 5.4-2 是示例代码的差异。

表 5.4-1 HTTP 与 HTTPS 通信方式的比较

HTTP HTTPS
特性 URL
加密内容
内容的篡改检测
对服务器进行认证
损害的风险 由攻击者读取内容
由攻击者修改内容
应用访问了伪造的服务器

表 5.4-2 HTTP/HTTPS 通信示例代码的解释

示例代码 通信 收发敏感信息 服务器证书
通过 HTTP 的通信 HTTP 不适用 -
通过 HTTPS 的通信 HTTPS OK 服务器证书由可信第三方机构签署,例如 Cybertrust 和 VeriSign
通过 HTTPS 使用私有证书的通信 HTTTPS OK 私有证书(经常能在内部服务器或测试服务器上看到的操作)

Android 支持java.net.HttpURLConnection / javax.net.ssl.HttpsURLConnection作为 HTTP / HTTPS 通信 API。 在 Android 6.0(API Level 23)版本中,另一个 HTTP 客户端库 Apache HttpClient 的支持已被删除。

5.4.1.1 通过 HTTP 进行通信

它基于两个前提,即通过 HTTP 通信发送/接收的所有内容都可能被攻击者嗅探和篡改,并且你的目标服务器可能被攻击者准备的假服务器替换。 只有在没有造成损害或损害在允许范围内的情况下,才能使用 HTTP 通信,即使在本地也是如此。 如果应用无法接受该前提,请参阅“5.4.1.2 通过 HTTPS 进行通信”和“5.4.1.3 通过 HTTPS 使用私有证书进行通信”。

以下示例代码显示了一个应用,它在 Web 服务器上执行图像搜索,获取结果图像并显示它。与服务器的 HTTP 通信在搜索时执行两次。第一次通信是搜索图像数据,第二次是获取它。它使用AsyncTask创建用于通信过程的工作线程,来避免在 UI 线程上执行通信。与服务器的通信中发送/接收的内容,在这里不被认为是敏感的(例如,用于搜索的字符串,图像的 URL 或图像数据)。因此,接收到的数据,如图像的 URL 和图像数据,可能由攻击者提供。为了简单地显示示例代码,在示例代码中没有采取任何对策,通过将接收到的攻击数据视为可容忍的。此外,在 JSON 解析或显示图像数据期间,可能出现异常的处理将被忽略。根据应用规范,有必要正确处理例外情况。

要点:

  1. 发送的数据中不得包含敏感信息。
  2. 假设收到的数据可能来自攻击者。

HttpImageSearch.java

package org.jssec.android.https.imagesearch;

import android.os.AsyncTask;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

public abstract class HttpImageSearch extends AsyncTask<String, Void, Object> {

    @Override
    protected Object doInBackground(String... params) {
        byte[] responseArray;
        // --------------------------------------------------------
        // Communication 1st time: Execute image search
        // --------------------------------------------------------
        // *** POINT 1 *** Sensitive information must not be contained in send data.
        // Send image search character string
        StringBuilder s = new StringBuilder();
        for (String param : params){
            s.append(param);
            s.append('+');
        }
        s.deleteCharAt(s.length() - 1);
        String search_url = "http://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=" +
        s.toString();
        responseArray = getByteArray(search_url);
        if (responseArray == null) {
            return null;
        }
        // *** POINT 2 *** Suppose that received data may be sent from attackers.
        // This is sample, so omit the process in case of the searching result is the data from an attacker.
        // This is sample, so omit the exception process in case of JSON purse.
        String image_url;
        try {
            String json = new String(responseArray);
            image_url = new JSONObject(json).getJSONObject("responseData")
                .getJSONArray("results").getJSONObject(0).getString("url");
        } catch(JSONException e) {
            return e;
        }
        // --------------------------------------------------------
        // Communication 2nd time: Get images
        // --------------------------------------------------------
        // *** POINT 1 *** Sensitive information must not be contained in send data.
        if (image_url != null ) {
            responseArray = getByteArray(image_url);
            if (responseArray == null) {
                return null;
            }
        }
        // *** POINT 2 *** Suppose that received data may be sent from attackers.
        return responseArray;
    }

    private byte[] getByteArray(String strUrl) {
        byte[] buff = new byte[1024];
        byte[] result = null;
        HttpURLConnection response;
        BufferedInputStream inputStream = null;
        ByteArrayOutputStream responseArray = null;
        int length;
        try {
            URL url = new URL(strUrl);
            response = (HttpURLConnection) url.openConnection();
            response.setRequestMethod("GET");
            response.connect();
            checkResponse(response);
            inputStream = new BufferedInputStream(response.getInputStream());
            responseArray = new ByteArrayOutputStream();
            while ((length = inputStream.read(buff)) != -1) {
                if (length > 0) {
                    responseArray.write(buff, 0, length);
                }
            }
            result = responseArray.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    // This is sample, so omit the exception process
                }
            }
            if (responseArray != null) {
                try {
                    responseArray.close();
                } catch (IOException e) {
                    // This is sample, so omit the exception process
                }
            }
        }
        return result;
    }

    private void checkResponse(HttpURLConnection response) throws IOException {
        int statusCode = response.getResponseCode();
        if (HttpURLConnection.HTTP_OK != statusCode) {
            throw new IOException("HttpStatus: " + statusCode);
        }
    }
}

ImageSearchActivity.java

package org.jssec.android.https.imagesearch;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

public class ImageSearchActivity extends Activity {

    private EditText mQueryBox;
    private TextView mMsgBox;
    private ImageView mImgBox;
    private AsyncTask<String, Void, Object> mAsyncTask ;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mQueryBox = (EditText)findViewById(R.id.querybox);
        mMsgBox = (TextView)findViewById(R.id.msgbox);
        mImgBox = (ImageView)findViewById(R.id.imageview);
    }

    @Override
    protected void onPause() {
        // After this, Activity may be deleted, so cancel the asynchronization process in advance.
        if (mAsyncTask != null) mAsyncTask.cancel(true);
        super.onPause();
    }

    public void onHttpSearchClick(View view) {
        String query = mQueryBox.getText().toString();
        mMsgBox.setText("HTTP:" + query);
        mImgBox.setImageBitmap(null);
        // Cancel, since the last asynchronous process might not have been finished yet.
        if (mAsyncTask != null) mAsyncTask.cancel(true);
        // Since cannot communicate by UI thread, communicate by worker thread by AsynchTask.
        mAsyncTask = new HttpImageSearch() {

            @Override
            protected void onPostExecute(Object result) {
                // Process the communication result by UI thread.
                if (result == null) {
                    mMsgBox.append("¥nException occurs¥n");
                } else if (result instanceof Exception) {
                    Exception e = (Exception)result;
                    mMsgBox.append("¥nException occurs¥n" + e.toString());
                } else {
                    // Exception process when image display is omitted here, since it's sample.
                    byte[] data = (byte[])result;
                    Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
                    mImgBox.setImageBitmap(bmp);
                }
            }
        }.execute(query); 
        // pass search character string and start asynchronous process
    }

    public void onHttpsSearchClick(View view) {
        String query = mQueryBox.getText().toString();
        mMsgBox.setText("HTTPS:" + query);
        mImgBox.setImageBitmap(null);
        // Cancel, since the last asynchronous process might not have been finished yet.
        if (mAsyncTask != null) mAsyncTask.cancel(true);
        // Since cannot communicate by UI thread, communicate by worker thread by AsynchTask.
        mAsyncTask = new HttpsImageSearch() {
            @Override
            protected void onPostExecute(Object result) {
                // Process the communication result by UI thread.
                if (result instanceof Exception) {
                    Exception e = (Exception)result;
                    mMsgBox.append("¥nException occurs¥n" + e.toString());
                } else {
                    byte[] data = (byte[])result;
                    Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
                    mImgBox.setImageBitmap(bmp);
                }
            }
        }.execute(query); 
        // pass search character string and start asynchronous process
    }
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.jssec.android.https.imagesearch"
    android:versionCode="1"
    android:versionName="1.0">
    <uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:icon="@drawable/ic_launcher"
        android:allowBackup="false"
        android:label="@string/app_name" >
        <activity
            android:name=".ImageSearchActivity"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.Light"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

5.4.1.2 使用 HTTPS 进行通信

在 HTTPS 通信中,检查服务器是否可信,以及传输的数据是否加密。 为了验证服务器,Android HTTPS 库验证“服务器证书”,它在 HTTPS 事务的握手阶段从服务器传输,其要点如下:

  • 服务器证书由可信的第三方证书机构签署
  • 服务器证书的期限和其他属性有效
  • 服务器的主机名匹配服务器证书的主题字段中的 CN(通用名称)或 SAN(主题备用名称)

如果上述验证失败,则会引发SSLException(服务器证书验证异常)。 这可能意味着中间人攻击或服务器证书缺陷。 你的应用必须根据应用规范,以适当的顺序处理异常。

下一个示例代码用于 HTTPS 通信,它使用可信的第三方证书机构颁发的服务器证书连接到 Web 服务器。 对于使用私有服务器证书的 HTTPS 通信,请参阅“5.4.1.3 通过 HTTPS 使用私有证书进行通信”。

以下示例代码展示了一个应用,它在 Web 服务器上执行图像搜索,获取结果图像并显示它。 与服务器的 HTTPS 通信在搜索时执行两次。 第一次通信是搜索图像数据,第二次是获取它。 它使用AsyncTask创建用于通信过程的工作线程,来避免在 UI 线程上执行通信。 与服务器的通信中发送/接收的所有内容,在这里被认为是敏感的(例如,用于搜索的字符串,图像的 URL 或图像数据)。 为了简单地显示示例代码,不会执行针对SSLException的特殊处理。 根据应用规范,有必要正确处理异常。 另外,下面的示例代码允许使用 SSLv3 进行通信。 通常,我们建议配置远程服务器上的设置来禁用 SSLv3,以避免针对 SSLv3 中的漏洞(称为 POODLE)的攻击。

要点:

  1. URI 以https://开头。
  2. 发送数据中可能包含敏感信息。
  3. 尽管数据是从通过 HTTPS 连接的服务器发送的,但要小心并安全地处理收到的数据。
  4. SSLException应该在应用中以适当的顺序处理。

HttpsImageSearch.java

package org.jssec.android.https.imagesearch;

import org.json.JSONException;
import org.json.JSONObject;
import android.os.AsyncTask;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

public abstract class HttpsImageSearch extends AsyncTask<String, Void, Object> {

    @Override
    protected Object doInBackground(String... params) {
        byte[] responseArray;
        // --------------------------------------------------------
        // Communication 1st time : Execute image search
        // --------------------------------------------------------
        // *** POINT 1 *** URI starts with https://.
        // *** POINT 2 *** Sensitive information may be contained in send data.
        StringBuilder s = new StringBuilder();
        for (String param : params){
            s.append(param);
            s.append('+');
        }
        s.deleteCharAt(s.length() - 1);
        String search_url = "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=" +
        s.toString();
        responseArray = getByteArray(search_url);
        if (responseArray == null) {
            return null;
        }
        // *** POINT 3 *** Handle the received data carefully and securely,
        // even though the data was sent from the server connected by HTTPS.
        // Omitted, since this is a sample. Please refer to "3.2 Handling Input Data Carefully and Securely."
        String image_url;
        try {
            String json = new String(responseArray);
            image_url = new JSONObject(json).getJSONObject("responseData")
                .getJSONArray("results").getJSONObject(0).getString("url");
        } catch(JSONException e) {
            return e;
        }
        // --------------------------------------------------------
        // Communication 2nd time : Get image
        // --------------------------------------------------------
        // *** POINT 1 *** URI starts with https://.
        // *** POINT 2 *** Sensitive information may be contained in send data.
        if (image_url != null ) {
            responseArray = getByteArray(image_url);
            if (responseArray == null) {
                return null;
            }
        }
        return responseArray;
    }

    private byte[] getByteArray(String strUrl) {
        byte[] buff = new byte[1024];
        byte[] result = null;
        HttpURLConnection response;
        BufferedInputStream inputStream = null;
        ByteArrayOutputStream responseArray = null;
        int length;
        try {
            URL url = new URL(strUrl);
            response = (HttpURLConnection) url.openConnection();
            response.setRequestMethod("GET");
            response.connect();
            checkResponse(response);
            inputStream = new BufferedInputStream(response.getInputStream());
            responseArray = new ByteArrayOutputStream();
            while ((length = inputStream.read(buff)) != -1) {
                if (length > 0) {
                    responseArray.write(buff, 0, length);
                }
            }
            result = responseArray.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    // This is sample, so omit the exception process
                }
            }
            if (responseArray != null) {
                try {
                    responseArray.close();
                } catch (IOException e) {
                    // This is sample, so omit the exception process
                }
            }
        }
        return result;
    }

    private void checkResponse(HttpURLConnection response) throws IOException {
        int statusCode = response.getResponseCode();
        if (HttpURLConnection.HTTP_OK != statusCode) {
            throw new IOException("HttpStatus: " + statusCode);
        }
    }
}

其他示例代码文件与“5.4.1.1 通过 HTTP 进行通信”相同,因此请参阅“5.4.1.1 通过 HTTP 进行通信”。

5.4.1.3 使用私有证书通过 HTTPS 进行通信

这部分展示了一个 HTTPS 通信的示例代码,其中包含私人颁发的服务器证书(私有证书),但不是可信的第三方机构颁发的服务器证书。 请参阅“5.4.3.1 如何创建私有证书并配置服务器”,来创建私有证书机构和私有证书的根证书,并在 Web 服务器中设置 HTTPS。 示例程序的资产中包含cacert.crt文件。 它是私有证书机构的根证书文件。

以下示例代码展示了一个应用,在 Web 服务器上获取图像并显示该图像。 HTTPS 用于与服务器的通信。 它使用AsyncTask创建用于通信过程的工作线程,来避免在 UI 线程上执行通信。 与服务器的通信中发送/接收的所有内容(图像的 URL 和图像数据)都被认为是敏感的。 为了简单地显示示例代码,不会执行针对SSLException的特殊处理。 根据应用规范,有必要正确处理异常。

要点:

  1. 使用私人证书机构的根证书来验证服务器证书。
  2. URI 以https://开头。
  3. 发送数据中可能包含敏感信息。
  4. 接收的数据可以像服务器一样被信任。
  5. SSLException应该在应用中以适当的顺序处理。

PrivateCertificathettpsGet.java

package org.jssec.android.https.privatecertificate;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManagerFactory;
import android.content.Context;
import android.os.AsyncTask;

public abstract class PrivateCertificateHttpsGet extends AsyncTask<String, Void, Object> {

    private Context mContext;

    public PrivateCertificateHttpsGet(Context context) {
        mContext = context;
    }

    @Override
    protected Object doInBackground(String... params) {
        TrustManagerFactory trustManager;
        BufferedInputStream inputStream = null;
        ByteArrayOutputStream responseArray = null;
        byte[] buff = new byte[1024];
        int length;
        try {
            URL url = new URL(params[0]);
            // *** POINT 1 *** Verify a server certificate with the root certificate of a private certificate authority.
            // Set keystore which includes only private certificate that is stored in assets, to client.
            KeyStore ks = KeyStoreUtil.getEmptyKeyStore();
            KeyStoreUtil.loadX509Certificate(ks,
                mContext.getResources().getAssets().open("cacert.crt"));
            // *** POINT 2 *** URI starts with https://.
            // *** POINT 3 *** Sensitive information may be contained in send data.
            trustManager = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManager.init(ks);
            SSLContext sslCon = SSLContext.getInstance("TLS");
            sslCon.init(null, trustManager.getTrustManagers(), new SecureRandom());
            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            HttpsURLConnection response = (HttpsURLConnection)con;
            response.setDefaultSSLSocketFactory(sslCon.getSocketFactory());
            response.setSSLSocketFactory(sslCon.getSocketFactory());
            checkResponse(response);
            // *** POINT 4 *** Received data can be trusted as same as the server.
            inputStream = new BufferedInputStream(response.getInputStream());
            responseArray = new ByteArrayOutputStream();
            while ((length = inputStream.read(buff)) != -1) {
                if (length > 0) {
                    responseArray.write(buff, 0, length);
                }
            }
            return responseArray.toByteArray();
        } catch(SSLException e) {
            // *** POINT 5 *** SSLException should be handled with an appropriate sequence in an application.
            // Exception process is omitted here since it's sample.
            return e;
        } catch(Exception e) {
            return e;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (Exception e) {
                    // This is sample, so omit the exception process
                }
            }
            if (responseArray != null) {
                try {
                    responseArray.close();
                } catch (Exception e) {
                    // This is sample, so omit the exception process
                }
            }
        }
    }

    private void checkResponse(HttpURLConnection response) throws IOException {
        int statusCode = response.getResponseCode();
        if (HttpURLConnection.HTTP_OK != statusCode) {
            throw new IOException("HttpStatus: " + statusCode);
        }
    }
}

KeyStoreUtil.java

package org.jssec.android.https.privatecertificate;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;

public class KeyStoreUtil {

    public static KeyStore getEmptyKeyStore() throws KeyStoreException,
        NoSuchAlgorithmException, CertificateException, IOException {
        KeyStore ks = KeyStore.getInstance("BKS");
        ks.load(null);
        return ks;
    }

    public static void loadAndroidCAStore(KeyStore ks)
    throws KeyStoreException, NoSuchAlgorithmException,
    CertificateException, IOException {
        KeyStore aks = KeyStore.getInstance("AndroidCAStore");
        aks.load(null);
        Enumeration<String> aliases = aks.aliases();
        while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();
            Certificate cert = aks.getCertificate(alias);
            ks.setCertificateEntry(alias, cert);
        }
    }

    public static void loadX509Certificate(KeyStore ks, InputStream is)
        throws CertificateException, KeyStoreException {
        try {
            CertificateFactory factory = CertificateFactory.getInstance("X509");
            X509Certificate x509 = (X509Certificate)factory.generateCertificate(is);
            String alias = x509.getSubjectDN().getName();
            ks.setCertificateEntry(alias, x509);
        } finally {
            try { is.close(); } catch (IOException e) { /* This is sample, so omit the exception process
            */ }
        }
    }
}

PrivateCertificateHttpsActivity.java

package org.jssec.android.https.privatecertificate;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

    public class PrivateCertificateHttpsActivity extends Activity {

    private EditText mUrlBox;
    private TextView mMsgBox;
    private ImageView mImgBox;
    private AsyncTask<String, Void, Object> mAsyncTask ;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mUrlBox = (EditText)findViewById(R.id.urlbox);
        mMsgBox = (TextView)findViewById(R.id.msgbox);
        mImgBox = (ImageView)findViewById(R.id.imageview);
    }

    @Override
    protected void onPause() {
        // After this, Activity may be discarded, so cancel asynchronous process in advance.
        if (mAsyncTask != null) mAsyncTask.cancel(true);
        super.onPause();
    }

    public void onClick(View view) {
        String url = mUrlBox.getText().toString();
        mMsgBox.setText(url);
        mImgBox.setImageBitmap(null);
        // Cancel, since the last asynchronous process might have not been finished yet.
        if (mAsyncTask != null) mAsyncTask.cancel(true);
        // Since cannot communicate through UI thread, communicate by worker thread by AsynchTask.
        mAsyncTask = new PrivateCertificateHttpsGet(this) {
            @Override
            protected void onPostExecute(Object result) {
                // Process the communication result through UI thread.
                if (result instanceof Exception) {
                    Exception e = (Exception)result;
                    mMsgBox.append("¥nException occurs¥n" + e.toString());
                } else {
                    byte[] data = (byte[])result;
                    Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
                    mImgBox.setImageBitmap(bmp);
                }
            }
        }.execute(url); 
        // Pass URL and start asynchronization process
    }
}
相关文章
|
26天前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
105 4
|
16天前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
23天前
|
安全 搜索推荐 网络安全
HTTPS协议是**一种通过计算机网络进行安全通信的传输协议
HTTPS协议是**一种通过计算机网络进行安全通信的传输协议
51 11
|
2月前
|
存储 缓存 安全
https访问提示不安全,证书密钥验证上如何解决
【10月更文挑战第4天】访问提示不安全,证书密钥验证上如何解决
414 2
|
3月前
|
安全 网络协议 网络安全
在实现HTTPS时,有哪些常见的安全协议
在实现HTTPS时,有哪些常见的安全协议
161 1
|
2月前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
372 0
|
2月前
|
编解码 JSON 安全
使用search-guard加固安全为https访问
使用search-guard加固安全为https访问
|
3月前
|
Java Android开发 数据安全/隐私保护
Android中多进程通信有几种方式?需要注意哪些问题?
本文介绍了Android中的多进程通信(IPC),探讨了IPC的重要性及其实现方式,如Intent、Binder、AIDL等,并通过一个使用Binder机制的示例详细说明了其实现过程。
389 4
|
5月前
|
Java Android开发 Spring
Android Spingboot 实现SSE通信案例
【7月更文挑战第14天】以下是使用Android和Spring Boot实现SSE(Server-Sent Events)通信的案例摘要: 在`MainActivity`中: - 初始化界面元素并设置按钮点击事件。 - `startSseRequest`方法创建`WebClient`对象,设置请求头,发送请求,并处理响应和错误。 请确保将`your-server-url`替换为实际的服务器地址。
135 14
|
5月前
|
存储 安全 数据安全/隐私保护
🔎Android安全攻防实战!守护你的应用数据安全,让用户放心使用!🛡️
【7月更文挑战第28天】在移动应用盛行的时代,确保Android应用安全性至关重要。本文以问答形式探讨了主要安全威胁(如逆向工程、数据窃取)及其对策。建议使用代码混淆、签名验证、数据加密等技术来增强应用保护。此外,还推荐了加密API、HTTPS通信、代码审计等措施来进一步加强安全性。综上所述,全面的安全策略对于构建安全可靠的应用环境必不可少。#Android #应用安全 #代码混淆 #数据加密
91 3