保护Android上的通信安全

48 阅读4分钟

随着最近的所有数据泄露,隐私已成为一个重要的主题。几乎每个应用程序都通过网络进行通信,因此考虑用户信息的安全性非常重要。在这篇文章中,您将了解保护Android应用程序通信的最新实践。

一 使用HTTPS

在开发应用程序时,最好将网络请求限制为必要的网络请求。对于必要的,请确保它们是通过HTTPS而不是HTTP制作的。HTTPS是一种加密流量的协议,因此窃听者无法轻易拦截它。关于Android的好处是迁移就像将URL从http更改为https一样简单。

`URL url =` `new` `URL(``"[https://example.com](https://example.com/)"``);`

`HttpsURLConnection httpsURLConnection = (HttpsURLConnection)url.openConnection();`

`httpsURLConnection.connect();`

事实上,Android N及更高版本可以使用Android的网络安全配置强制执行HTTPS 。

在Android Studio中,选择项目的app / res / xml目录。如果xml目录尚不存在,请创建它。选择它,然后单击文件>新文件。称之为network_security_config.xml。该文件的格式如下:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="false">
    <domain includeSubdomains="true">example.com</domain>
  </domain-config>
</network-security-config>

要告诉Android使用此文件,请将文件名添加到AndroidManifest.xml文件中的application标记:

<application android:networkSecurityConfig="@xml/network_security_config"

二 更新加密提供程序

多年来,HTTPS协议已被多次利用。当安全研究人员报告漏洞时,缺陷通常会被修补。应用修补程序可确保应用程序的网络连接使用最新的行业标准协议。最新版本的协议包含的弱点比以前少。

要更新加密提供程序,您需要包含Google Play服务。在build.gradle的模块文件中,将以下行添加到dependencies部分:

implementation 'com.google.android.gms:play-services-safetynet:15.0.1'

该安全网服务API还有更多的功能,包括安全浏览 API,检查的网址,看看他们是否已被标记为已知威胁,以及验证码 API,以防止垃圾邮件和其他恶意流量您的应用程序。

同步完成后摇篮,你可以调用ProviderInstallerinstallIfNeededAsync方法:

public class MainActivity extends Activity implements ProviderInstaller.ProviderInstallListener
{
  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    ProviderInstaller.installIfNeededAsync(this, this);
  }
}

onProviderInstalled()当提供程序成功更新或已更新时,将调用此方法。否则,onProviderInstallFailed(int errorCode, Intent recoveryIntent)被称为。

三 证书和公钥固定

当您与服务器建立HTTPS连接时,服务器会显示数字证书并由Android验证,以确保连接安全。证书可以使用来自中间证书颁发机构的证书进行签名。中间权限使用的此证书可以由另一个中间权限签名,依此类推,只要最后一个证书由已被Android操作系统信任的根证书颁发机构签名,这是可信的。

如果信任链中的任何证书无效,则连接不安全。虽然这是一个很好的系统,但它并非万无一失。攻击者可能会指示Android操作系统接受自定义证书。拦截代理可以拥有受信任的证书,如果设备由公司控制,则公司可能已将设备配置为接受其自己的证书。这些场景允许“中间人”攻击,允许解密和读取HTTPS流量。

通过检查根据预期证书副本提供的服务器证书,可以解决证书锁定问题。这可以防止在证书与预期证书不同时建立连接。

为了在Android N及更高版本上实现固定,您需要将证书的哈希(称为引脚)添加到network_security_config.xml文件中。这是一个示例实现:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="false">
    <domain includeSubdomains="true">duckduckgo.com</domain>
    <pin-set>
      <pin digest="SHA-256">lFL47+i9MZkLqDTjnbPTx2GZbGmRfvF3GkEh+J+1F3g=</pin>
      <pin digest="SHA-256">w9MWhhnFZDSPWTFBjaoeGuClsrCs7Z70lG7YNlo8t+s=</pin>
    </pin-set>
  </domain-config>
</network-security-config>

注意:如果您需要支持运行早于Android N的操作系统版本的设备,则可以使用TrustKit库。它以完全相同的方式使用网络安全配置文件。

四 消毒和验证

到目前为止,所有的保护措施,您的连接应该是非常安全的。即便如此,也不要忘记定期编程验证。盲目信任从网络收到的数据是不安全的。一个好的编程实践是“按合同设计”,其中您的方法的输入和输出满足定义特定接口期望的合同。

例如,如果您的服务器需要48个字符或更少的字符串,请确保该接口最多只返回48个字符。

if (editText.getText().toString().length() <= 48)
{
    ; //return something...
}
else
{
    ; //return default or error
}

如果您只是期望来自服务器的数字,您的输入应该检查这一点。虽然这有助于防止无辜的错误,但它也降低了注入和内存损坏攻击的可能性。当数据传递给NDK 或 JNI -native C和C ++代码时尤其如此。

将数据发送到服务器也是如此。不要盲目发送数据,特别是如果它是用户生成的。例如,限制用户输入的长度是一种好习惯,特别是如果它将由SQL服务器或将运行代码的任何技术执行。

虽然保护服务器免受攻击超出了本文的范围,但作为移动开发人员,您可以通过删除服务器正在使用的语言的字符来完成您的工作。这样,输入不易受到注入攻击。一些示例是在对用户输入不重要时剥离引号,分号和斜杠:

string = string.replace("\", "").replace(";", "").replace(""", "").replace("'", "");

如果您确切知道预期的格式,则应检查此格式。一个很好的例子是电子邮件验证

private final String emailRegexString = "^[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,4}$";
private boolean isValidEmailString(String emailString)
{
     return emailString != null &&   Pattern.compile(emailRegexString).matcher(emailString).matches();
}

也可以检查文件。如果您要将照片发送到服务器,则可以将其检查为有效照片。前两个字节和最后两个字节总是FF D8和FF D9 为JPEG格式。

private static boolean isValidJPEGAtPath(String pathString) throws IOException
{
    RandomAccessFile randomAccessFile = null;
    try
    {
        randomAccessFile = new RandomAccessFile(pathString, "r");
        long length = randomAccessFile.length();
        if (length < 10L)
        {
            return false;
        }
        byte[] start = new byte[2];
        randomAccessFile.readFully(start);
        randomAccessFile.seek(length - 2);
        byte[] end = new byte[2];
        randomAccessFile.readFully(end);
        return start[0] == -1 && start[1] == -40 && end[0] == -1 && end[1] == -39;
    }
    finally
    {
        if (randomAccessFile != null)
        {
            randomAccessFile.close();
        }
    }
}

显示直接显示来自服务器的消息的错误警报时要小心。错误消息可能会泄露私人调试或安全相关信息。解决方案是让服务器发送错误代码,客户端查找该错误代码以显示预定义的消息。

五 与其他应用程序通信

当您保护与设备之间的通信时,保护IPC也很重要。有些情况下,开发人员已经离开了共享文件或已经实现了套接字来交换敏感信息。这不安全。最好使用Intent。您可以通过提供如下所示的包名来使用Intent发送数据:

Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.app","com.example.app.TheActivity"));
intent.putExtra("UserInfo", "Example string");
startActivity(intent);

要将数据广播到多个应用,您应该强制只有使用您的签名密钥签名的应用才能获取数据。否则,任何注册接收广播的应用都可以读取您发送的信息。同样,如果您已注册接收广播,则恶意应用可以向您的应用发送广播。发送和接收使用签名作为protectionLevel的广播时,您可以使用权限。您可以在清单文件中定义自定义权限,如下所示:

<permission android:name="com.example.mypermission" android:protectionLevel="signature"/>

然后您可以像这样授予权限:

<uses-permission android:name="com.example.mypermission"/>

两个应用程序都需要在清单文件中具有权限才能使其正常工作。发送广播:

Intent intent = new Intent();
intent.putExtra("UserInfo", "Example string");
intent.setAction("com.example.SOME_NOTIFICATION");
sendBroadcast(intent, "com.example.mypermission");

或者,您可以在发送广播时将其限制为与指定包匹配的一组应用。在清单文件中设置为将排除从应用程序外部接收的广播。setPackage(String)android:exportedfalse

六 端到端加密

了解HTTPS保护网络通信的限制非常重要。在大多数HTTPS实现中,加密在服务器处终止。例如,您与公司服务器的连接可能是通过HTTPS进行的,但是一旦该流量到达服务器,它就会被解密。然后可以通过建立另一个HTTPS会话或通过未加密的方式将其转发到其他服务器。公司能够查看已发送的信息,并且在大多数情况下,这是业务运营的要求。但是,这也意味着公司可以将信息传递给未加密的第三方。

最近出现了一种称为“端到端加密”的趋势,其中只有两个终端通信设备可以读取流量。一个很好的例子是加密的聊天应用程序,其中两个移动设备通过服务器相互通信; 只有发送者和接收者才能阅读彼此的消息。

一个帮助您理解端到端加密的类比是想象您希望某人向您发送只有您可以阅读的消息。为此,您可以在保留挂锁密钥(私钥)的同时为其提供一个带有打开挂锁的盒子(公钥)。用户编写消息,将其放入框中,锁定挂锁并将其发回给您。只有您可以阅读该消息,因为您是唯一一个带钥匙解锁挂锁的人。

通过端到端加密,两个用户都可以互相发送密钥。服务器仅提供通信服务,但无法读取通信内容。虽然实现细节超出了本文的范围,但它是一项功能强大的技术。如果你想了解更多关于这种方法的知识,一个很好的起点是开源信号项目的GitHub回购。

结论

随着GDPR等所有新的隐私法律,安全性变得越来越重要。这通常是移动应用程序开发的一个被忽视的方面。

在本教程中,您已经介绍了安全性最佳实践,包括使用HTTPS,证书锁定,数据清理和端到端加密。在开发移动应用程序时,这些最佳实践应作为安全性的基础。如果您有任何疑问,请随时将它们留在下面,当您在这里时,请查看我的其他一些有关Android应用程序安全性的教程!