25、安全与隐私:权限最小化、数据加密、安全通信
说实话,车载应用的安全问题,我以前也重视不够。
直到有一次,我在一个项目里发现某个音乐App竟然能读取车辆的GPS轨迹。用户只是想在车里听首歌,凭什么知道车开到了哪里?这其实是个典型的权限滥用问题。从那以后,我对安全这块就特别较真。
今天咱们聊聊车载多媒体应用里的三个安全核心:权限最小化、数据加密、安全通信。说白了,就是让你的App既好用,又不乱来。
一、权限最小化:够用就行,别多要
权限最小化,意思很直白:只申请你真正需要的权限。
我见过不少开发者,图省事,直接把所有权限都写上。结果呢?用户一看,听歌App要读取联系人,要访问位置,直接就不敢用了。
核心原则:
- 能用隐式Intent解决的,就别要权限
- 能用临时权限的,就别申请长期权限
- 能用单次授权的,就别让用户一直授权
举个例子。你的多媒体App要播放本地音乐文件。你只需要READ_EXTERNAL_STORAGE就够了,千万别顺手把ACCESS_FINE_LOCATION也加上。
// 好的做法:只申请必要的权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_CODE_STORAGE);
}
// 坏的做法:一次性申请一堆权限
// ActivityCompat.requestPermissions(this,
// new String[]{
// Manifest.permission.READ_EXTERNAL_STORAGE,
// Manifest.permission.ACCESS_FINE_LOCATION,
// Manifest.permission.READ_CONTACTS
// },
// REQUEST_CODE_ALL);
我的小技巧:
在车载系统里,很多权限其实可以通过CarPermissionManager来管理。比如播放控制、语音识别这些,用系统提供的API,比直接要底层权限安全得多。
二、数据加密:别让用户数据裸奔
车载系统里存着不少敏感数据:用户的歌单、收藏、登录Token,甚至还有语音助手录下的指令。这些数据如果明文存储,一旦被恶意App读取,后果很严重。
我个人习惯,所有本地存储的敏感数据,必须加密。
2.1 使用Android Keystore
Android Keystore 是个好东西。它把密钥存在硬件安全模块里,App本身都拿不到密钥原文。这就好比你把钥匙锁在保险柜里,别人想偷也偷不走。
// 生成密钥并存入Keystore
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"my_music_key",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build();
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(spec);
keyGenerator.generateKey();
// 加密数据
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] iv = cipher.getIV();
byte[] encryptedData = cipher.doFinal(plainText.getBytes());
注意:
加密时一定要保存好初始化向量(IV)。解密时需要同样的IV,否则数据解不出来。我建议把IV和密文一起存,比如用iv + encryptedData的格式。
2.2 数据库加密
如果你用Room或SQLite存数据,建议用SQLCipher。它给整个数据库加了一层壳,没有密码谁也读不了。
// 使用SQLCipher打开加密数据库
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(
"music.db", "your_password", null);
// 或者用Room + SQLCipher
SupportFactory factory = new SupportFactory("your_password".getBytes());
Room.databaseBuilder(context, MusicDatabase.class, "music.db")
.openHelperFactory(factory)
.build();
三、安全通信:别让数据在路上被劫持
车载多媒体App经常要联网:在线听歌、下载专辑、同步歌单。这些网络通信如果没做好安全措施,数据就像在街上裸奔,谁都能截获。
我记得有一次,我调试一个车载音乐App,发现它竟然用HTTP请求下载歌词。你想想看,歌词内容虽然不敏感,但请求里带着用户的Token啊!一旦被中间人攻击,账号就丢了。
3.1 强制使用HTTPS
这个不用多说,所有网络请求必须走HTTPS。Android 9以上默认禁止明文HTTP,但有些老项目可能还开着。我建议在AndroidManifest.xml里明确禁止明文流量:
<application
android:usesCleartextTraffic="false"
...>
3.2 证书锁定(Certificate Pinning)
光用HTTPS还不够。如果用户的设备被植入了恶意CA证书,中间人攻击照样能解密你的HTTPS流量。怎么办?用证书锁定。
说白了,就是你的App只信任你指定的那个服务器证书,其他证书一概不认。
// OkHttp + 证书锁定
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("api.mymusic.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
OkHttpClient client = new OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
避坑指南:
我曾经在证书锁定上栽过跟头。证书过期后,App直接连不上服务器,用户全炸了。所以一定要做好证书更新机制,比如在App启动时从服务器拉取最新的证书指纹。
3.3 使用安全的WebSocket
如果你的App需要实时通信(比如车载语音助手、在线歌词同步),建议用wss://而不是ws://。WSS就是WebSocket over TLS,相当于给实时通信也加了密。
// 安全的WebSocket连接
OkHttpClient client = new OkHttpClient.Builder()
.build();
Request request = new Request.Builder()
.url("wss://api.mymusic.com/lyrics")
.build();
WebSocket ws = client.newWebSocket(request, new WebSocketListener() {
@Override
public void onMessage(WebSocket webSocket, String text) {
// 处理加密后的消息
}
});
四、知识体系总览
下面这张图,把今天讲的内容串起来了。你可以看到,安全与隐私其实贯穿了数据存储、权限管理和网络通信三个维度。
五、总结一下
安全与隐私,说白了就是三个字:别乱来。
- 权限别乱要——够用就行
- 数据别乱存——加密再存
- 通信别乱发——加密再发
做到这三点,你的车载多媒体App就算在安全上及格了。当然,安全是个持续的过程,没有一劳永逸的方案。但至少,咱们不能在最基础的地方翻车。
一句话记住:
权限最小化、数据加密、安全通信——这三板斧,是车载应用安全的底线。