阻止安卓手机连接到WiFi网络,除非我的应用程序批准?

我想开发一个可以阻止连接到WiFi网络的应用程序,除非我批准它。我希望能够查询接入点的 MAC 地址,并将其与与 SSID 对应的已知地址列表进行比较。该应用程序的目标是保护用户免受意外连接到恶意接入点,例如菠萝设备可能产生的类型。

从我的研究中我不清楚我将如何实现这一目标。诸如如何在wifi网络状态更改时收到通知之类的问题,解释了如何检测已发生的连接,但对于我的用例来说,这已经为时已晚。

两者似乎都没有提供添加可能中断正在进行的连接的侦听器的方法。ConnectivityManagerWifiManager

我对解决方案有一些想法:

  • 将自己安装为代理,并决定是否允许数据通过。但是,这似乎不是基于Android代理设置是否适用于设备上的所有应用程序的选项?(提示:答案是“否”)。

  • 用我自己创建的东西替换现有的WiFi管理器。但是,我真的很难在Android开发人员指南中找到有关更换系统组件的任何信息。因此,我不确定这在非root手机上是否可能。

  • 将网络密码存储在我的应用程序中,并将WiFi管理器中的密码设置为无意义值。然后捕获一条警告连接失败的广播消息(大概是WifiManager.WPS_AUTH_FAILURE),并有选择地决定重新连接到该网络。这可能是一个可能的(如果丑陋的)解决方案,但是我可以在网络仍然连接时将密码设置回无意义的值,以确保我们不会悄悄地连接到另一个同名的SSID?我不确定。在我看来,菠萝设备可能会接受任何密码,从而使这种方法无效。

  • 找到一些方法来防止Android自动连接到已知网络(即以前使用过的网络或与它们一起存储密码的网络)。然后,我可以管理来自我的应用程序的所有连接/断开连接。但是,我无法看到如何在手机上手动执行此操作,因此我怀疑这在编程方式上是否可行。

任何人都可以建议一种适用于无根手机的方法吗?


答案 1

如果不生根设备,就无法实现非常强大的系统。这是你能得到的最接近的,我想:

  1. 使用 getConfiguredNetworks() 获取用户设备上当前配置的网络列表
  2. 对于列表中的每个WifiConfiguration,将公共字段BSSID设置为所需的“安全”MAC地址
  3. 调用 saveConfiguration() 以保留更改

或者,对于步骤(2.),您可以为每个配置的网络调用 disableNetwork(),并根据BSSID有选择地启用它们。请注意,MAC地址仍然很容易被欺骗。


答案 2

您可以收听wifi的连接更改,并根据该事件采取行动以禁用wifi

private ConnectivityManager connectionManager;
boolean previousConnectivityStatus;
private WifiManager wifiManager;

/* Register Connectivity Receiver */
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
context.registerReceiver(networkBroadcastReceiver, intentFilter);

/* Register Wifi State Listener */
IntentFilter wifiStateIntentFilter = new IntentFilter();
wifiStateIntentFilter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
context.registerReceiver(wifiStateReceiver, wifiStateIntentFilter);

connectionManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

private BroadcastReceiver wifiStateReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        Utility.traceM("NetworkController.wifiStateReceiver.new BroadcastReceiver() {...}::onReceive");
        int extraWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
        switch (extraWifiState)
            {
            case WifiManager.WIFI_STATE_DISABLED:
                {
                    Utility.trace("Broadcast Wifi State Disabled");
                    if(isWifiStateEventsEnabled)
                    {
                        EventBus.getDefault().post(new NetworkEvent(NetworkEventType.WIFI_DISABLED));
                    }
                    break;
                }
            case WifiManager.WIFI_STATE_ENABLED:
                {
                    Utility.trace("Broadcast Wifi State Enabled");
                    if(isWifiStateEventsEnabled)
                    {
                        EventBus.getDefault().post(new NetworkEvent(NetworkEventType.WIFI_ENABLED));
                    }
                    break;
                }
            }
    }
};

private BroadcastReceiver networkBroadcastReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        Utility.traceM("NetworkController.networkBroadcastReceiver.new BroadcastReceiver() {...}::onReceive");
        boolean connectivityStatus = isInternetConnectivityAvailable();
        if (previousConnectivityStatus != connectivityStatus)
        {
            if (connectivityStatus)
            {
                previousConnectivityStatus = true;
                Utility.trace("Broadcast Internet Available");
                EventBus.getDefault().post(new NetworkEvent(NetworkEventType.INTERNET_CONNECTED));
            }
            else
            {
                previousConnectivityStatus = false;
                Utility.trace("Broadcast Internet Disconnected");
                EventBus.getDefault().post(new NetworkEvent(NetworkEventType.INTERNET_DISCONNECTED));
            }
        }
    }
};