Appearance
Android 安全机制深度解析
目录
1. 安全概述
1.1 Android 安全架构
Android 安全架构层次:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 应用层安全 │
│ ├─ 应用沙箱隔离 │
│ ├─ 权限控制 │
│ ├─ 数据加密 │
│ └─ 代码保护 │
│ ↓ │
│ 框架层安全 │
│ ├─ PackageManager 权限管理 │
│ ├─ SecurityProvider │
│ ├─ 签名验证 │
│ └─ SELinux 策略 │
│ ↓ │
│ 内核层安全 │
│ ├─ SELinux 强制访问控制 │
│ ├─ 进程隔离 │
│ ├─ 内存保护 │
│ └─ 硬件安全模块 (TEE) │
│ ↓ │
│ 硬件层安全 │
│ ├─ TrustZone │
│ ├─ 安全芯片 │
│ ├─ 生物识别硬件 │
│ └─ 安全启动 │
│ │
└─────────────────────────────────────────────────────────────┘1.2 安全威胁分类
Android 安全威胁:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 恶意软件 │
│ ├─ 病毒 │
│ ├─ 木马 │
│ ├─ 勒索软件 │
│ └─ 广告软件 │
│ │
│ 网络攻击 │
│ ├─ 中间人攻击 │
│ ├─ 钓鱼攻击 │
│ ├─ DDoS 攻击 │
│ └─ 劫持攻击 │
│ │
│ 逆向工程 │
│ ├─ 代码反编译 │
│ ├─ 动态调试 │
│ ├─ Hook 技术 │
│ └─ 内存转储 │
│ │
│ 权限滥用 │
│ ├─ 过度权限申请 │
│ ├─ 权限提升 │
│ ├─ 越权访问 │
│ └─ 权限窃取 │
│ │
│ 数据泄露 │
│ ├─ 未加密存储 │
│ ├─ 日志泄露 │
│ ├─ 截屏泄露 │
│ └─ 剪贴板泄露 │
│ │
└─────────────────────────────────────────────────────────────┘2. SELinux 机制
2.1 SELinux 概述
SELinux (Security-Enhanced Linux) 是 Android 的核心安全机制,提供强制访问控制。
SELinux 架构:
┌────────────────────────────────────────────────────────────┐
│ │
│ SELinux 核心 │
│ ├─ 安全上下文 (Security Context) │
│ │ ├─ 用户 (User) │
│ │ ├─ 角色 (Role) │
│ │ └─ 类型 (Type) │
│ │ │
│ ├─ 策略 (Policy) │
│ │ ├─ 允许规则 │
│ │ ├─ 拒绝规则 │
│ │ └─ 审计规则 │
│ │ │
│ └─ 参考监视器 (Reference Monitor) │
│ ├─ 访问控制 │
│ ├─ 上下文转换 │
│ └─ 审计日志 │
│ │
└───────────────────────────────────────────────────────────┘2.2 SELinux 模式
SELinux 模式:
┌─────────────────────────────────────────────────────────────┐
│ │
│ Enforcing 模式 │
│ ├─ 强制执行策略 │
│ ├─ 拒绝未授权的访问 │
│ ├─ 记录审计日志 │
│ └─ 生产环境默认模式 │
│ │
│ Permissive 模式 │
│ ├─ 不执行策略 │
│ ├─ 允许所有访问 │
│ ├─ 记录审计日志 │
│ └─ 调试开发模式 │
│ │
└─────────────────────────────────────────────────────────────┘SELinux 命令:
bash
# 查看 SELinux 状态
getenforce
# 切换到 Permissive 模式
setenforce 0
# 切换到 Enforcing 模式
setenforce 1
# 查看进程安全上下文
ps -Ze | grep <process_name>
# 查看文件安全上下文
ls -Z /path/to/file
# 修改文件安全上下文
chcon -t <type> /path/to/file
# 查看 SELinux 策略
semodule -l3. 应用沙箱
3.1 沙箱隔离机制
应用沙箱隔离:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 进程隔离 │
│ ├─ 每个应用独立进程 │
│ ├─ 独立 UID/GID │
│ ├─ 独立内存空间 │
│ └─ 独立文件描述符 │
│ │
│ 文件隔离 │
│ ├─ 应用私有目录 │
│ │ └─ /data/data/<package_name>/ │
│ ├─ 应用外部目录 │
│ │ └─ /storage/emulated/0/Android/data/<package_name>/ │
│ └─ 其他应用无法访问 │
│ │
│ 网络隔离 │
│ ├─ 独立 Socket │
│ ├─ 独立端口 │
│ └─ 需权限访问网络 │
│ │
│ 资源隔离 │
│ ├─ 独立 Binder │
│ ├─ 独立 ContentProvider │
│ └─ 需权限访问系统资源 │
│ │
└─────────────────────────────────────────────────────────────┘3.2 沙箱目录结构
应用沙箱目录结构:
┌─────────────────────────────────────────────────────────────┐
│ │
│ /data/data/<package_name>/ │
│ ├─ app_*/ # 编译后的代码 │
│ ├─ cache/ # 缓存目录 │
│ ├─ code_cache/ # 代码缓存 │
│ ├─ databases/ # SQLite 数据库 │
│ ├─ files/ # 私有文件 │
│ ├─ lib/ # 原生库 │
│ ├─ no_backup/ # 不备份目录 │
│ └─ preferences/ # SharedPreferences │
│ │
│ /storage/emulated/0/Android/data/<package_name>/ │
│ ├─ cache/ # 外部缓存 │
│ ├─ code_cache/ # 外部代码缓存 │
│ └─ files/ # 外部文件 │
│ │
└─────────────────────────────────────────────────────────────┘4. 签名机制(v1/v2/v3/v4)
4.1 签名方案演进
Android 签名方案:
┌─────────────────────────────────────────────────────────────┐
│ │
│ v1 签名 (Android 4.0+) │
│ ├─ 在 META-INF 目录 │
│ ├─ 基于 JAR 签名 │
│ ├─ 签名文件:CERT.SF, CERT.RSA │
│ ├─ 验证速度较慢 │
│ └─ 不支持增量更新 │
│ │
│ v2 签名 (Android 7.0+) │
│ ├─ 全 APK 签名 │
│ ├─ 签名包含在 APK 头部 │
│ ├─ 验证速度快 │
│ ├─ 支持增量更新 │
│ └─ 完整性保护 │
│ │
│ v3 签名 (Android 8.0+) │
│ ├─ v2 基础上增加证书吊销 │
│ ├─ 支持证书吊销列表 (CRL) │
│ ├─ 支持 OCSP 吊销检查 │
│ └─ 向后兼容 │
│ │
│ v4 签名 (Android 9.0+) │
│ ├─ v3 基础上增加包完整性验证 │
│ ├─ 支持 APK 完整性检查 │
│ ├─ 防止 APK 被篡改 │
│ └─ 向后兼容 │
│ │
└─────────────────────────────────────────────────────────────┘4.2 签名生成
使用 apksigner 签名:
bash
# 生成密钥库
keytool -genkey -v -keystore my-release-key.jks \
-alias my-key-alias \
-keyalg RSA \
-keysize 2048 \
-validity 10000
# 签名 APK (自动选择最佳签名方案)
apksigner sign --ks my-release-key.jks \
--ks-key-alias my-key-alias \
--ks-password <password> \
--key-password <password> \
release.apk
# 验证签名
apksigner verify --verbose release.apk
# 查看签名信息
apksigner print release.apk4.3 签名验证
java
// 签名验证代码
public class SignatureVerifier {
// 获取应用签名
public PackageSigner getPackageSigner(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(),
PackageManager.GET_SIGNING_CERTIFICATES);
if (packageInfo.signingInfo != null) {
return new PackageSigner(packageInfo.signingInfo.getApkContentsSigners());
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
// 验证签名
public boolean verifySignature(Context context, byte[] expectedSignature) {
PackageSigner signer = getPackageSigner(context);
if (signer == null) {
return false;
}
Certificate[] certificates = signer.getCertificates();
for (Certificate cert : certificates) {
byte[] certBytes = cert.getEncoded();
if (Arrays.equals(certBytes, expectedSignature)) {
return true;
}
}
return false;
}
}5. 权限模型
5.1 权限模型架构
Android 权限模型:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 权限声明 │
│ ├─ AndroidManifest.xml 中声明 │
│ ├─ 权限类型 │
│ └─ 权限保护级别 │
│ │
│ 权限授予 │
│ ├─ 安装时授予 (普通权限) │
│ ├─ 运行时授予 (危险权限) │
│ ├─ 特殊权限授予 │
│ └─ 系统权限授予 │
│ │
│ 权限检查 │
│ ├─ 代码中检查 │
│ ├─ 系统服务检查 │
│ ├─ SELinux 检查 │
│ └─ 内核权限检查 │
│ │
│ 权限撤销 │
│ ├─ 用户手动撤销 │
│ ├─ 应用卸载时撤销 │
│ ├─ 系统强制撤销 │
│ └─ 权限重置 │
│ │
└─────────────────────────────────────────────────────────────┘6. 网络安全(HTTPS/证书锁定)
6.1 HTTPS 安全
HTTPS 安全机制:
┌─────────────────────────────────────────────────────────────┐
│ │
│ TLS/SSL 加密 │
│ ├─ 对称加密 │
│ ├─ 非对称加密 │
│ ├─ 密钥交换 │
│ └─ 数据完整性 │
│ │
│ 证书验证 │
│ ├─ CA 证书链验证 │
│ ├─ 证书有效期验证 │
│ ├─ 域名匹配验证 │
│ └─ 证书吊销检查 │
│ │
│ 安全传输 │
│ ├─ 防止中间人攻击 │
│ ├─ 防止数据篡改 │
│ └─ 防止数据窃听 │
│ │
└─────────────────────────────────────────────────────────────┘6.2 证书锁定
NetworkSecurityConfig 配置:
xml
<!-- res/xml/network_security_config.xml -->
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- 基础配置 -->
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system"/>
</trust-anchors>
</base-config>
<!-- 域名特定配置 -->
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">example.com</domain>
<trust-anchors>
<certificates src="system"/>
<certificates src="@raw/custom_ca"/>
</trust-anchors>
<pin-set expiration="2025-12-31">
<pin digest="SHA-256">
AAAAB3NzaC1kc2MAAA...
</pin>
</pin-set>
</domain-config>
</network-security-config>AndroidManifest.xml 配置:
xml
<manifest>
<application
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="false">
</application>
</manifest>7. 数据加密(KeyStore/Encryption)
7.1 Android Keystore
Android Keystore 架构:
┌─────────────────────────────────────────────────────────────┐
│ │
│ Keystore 服务 │
│ ├─ 密钥生成 │
│ ├─ 密钥存储 │
│ ├─ 密钥使用 │
│ └─ 密钥删除 │
│ │
│ 密钥类型 │
│ ├─ 对称密钥 (AES) │
│ ├─ 非对称密钥 (RSA, EC) │
│ ├─ 认证密钥 (HMAC) │
│ └─ 证书密钥 │
│ │
│ 安全特性 │
│ ├─ 硬件 backed (TEE) │
│ ├─ 密钥不出芯片 │
│ ├─ 防篡改 │
│ └─ 防提取 │
│ │
└─────────────────────────────────────────────────────────────┘7.2 加密实现
使用 Android Keystore:
java
// 密钥生成和使用
public class KeyStoreHelper {
private static final String KEYSTORE_NAME = "AndroidKeyStore";
private static final String KEY_ALIAS = "my_key_alias";
// 生成密钥
public void generateKey() throws Exception {
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
KeyGenParameterSpec spec = KeyGenParameterSpec.Builder(
KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build();
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_NAME);
keyGenerator.init(spec);
keyGenerator.generateKey();
}
// 加密数据
public byte[] encrypt(String data) throws Exception {
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
KeyStore.SecretKeyEntry entry =
(KeyStore.SecretKeyEntry) keyStore.getEntry(KEY_ALIAS, null);
SecretKey key = entry.getSecretKey();
Cipher cipher = Cipher.getInstance(
KeyProperties.TRANSFORMATION_AES_GCM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV();
byte[] ciphertext = cipher.doFinal(data.getBytes());
// 返回 IV + 密文
byte[] result = new byte[iv.length + ciphertext.length];
System.arraycopy(iv, 0, result, 0, iv.length);
System.arraycopy(ciphertext, 0, result, iv.length, ciphertext.length);
return result;
}
// 解密数据
public String decrypt(byte[] data) throws Exception {
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_NAME);
keyStore.load(null);
KeyStore.SecretKeyEntry entry =
(KeyStore.SecretKeyEntry) keyStore.getEntry(KEY_ALIAS, null);
SecretKey key = entry.getSecretKey();
byte[] iv = Arrays.copyOfRange(data, 0, 12);
byte[] ciphertext = Arrays.copyOfRange(data, 12, data.length);
Cipher cipher = Cipher.getInstance(
KeyProperties.TRANSFORMATION_AES_GCM);
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
byte[] plaintext = cipher.doFinal(ciphertext);
return new String(plaintext);
}
}8. 反调试技术
8.1 调试检测方法
反调试技术:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 进程检测 │
│ ├─ 检测调试器进程 │
│ ├─ 检测调试端口 │
│ ├─ 检测 ptrace 附加 │
│ └─ 检测调试标志 │
│ │
│ 时间检测 │
│ ├─ 检测时间异常 │
│ ├─ 检测执行速度 │
│ ├─ 检测时钟偏差 │
│ └─ 检测暂停执行 │
│ │
│ 内存检测 │
│ ├─ 检测内存断点 │
│ ├─ 检测内存修改 │
│ ├─ 检测代码段修改 │
│ └─ 检测内存转储 │
│ │
│ 环境检测 │
│ ├─ 检测模拟器环境 │
│ ├─ 检测 Root 环境 │
│ ├─ 检测调试环境 │
│ └─ 检测 Hook 框架 │
│ │
└─────────────────────────────────────────────────────────────┘8.2 反调试实现
调试检测代码:
java
// 反调试检测
public class AntiDebug {
// 检测是否被调试
public static boolean isDebugged() {
try {
File file = new File("/proc/self/status");
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("TracerPid:")) {
String[] parts = line.split("\\s+");
if (parts.length > 1 && !parts[1].equals("0")) {
return true;
}
}
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
// 检测 Root
public static boolean isRooted() {
// 检测 su 二进制文件
String[] paths = {"/system/bin/su", "/system/xbin/su",
"/sbin/su", "/system/sbin/su"};
for (String path : paths) {
if (new File(path).exists()) {
return true;
}
}
// 检测超级用户权限
try {
Process process = Runtime.getRuntime().exec("su -c 'whoami'");
if (process.exitValue() == 0) {
return true;
}
} catch (Exception e) {
// 忽略异常
}
return false;
}
// 检测模拟器
public static boolean isEmulator() {
// 检测设备属性
String model = Build.MODEL;
String brand = Build.BRAND;
String hardware = Build.HARDWARE;
if (model.contains("SDK") || model.contains("Google") ||
brand.contains("Google") || hardware.contains("goldfish")) {
return true;
}
// 检测设备特征
if (TelephonyManager.class.getMethod("getDeviceId") != null) {
return false;
}
return false;
}
}9. 反逆向工程
9.1 逆向工程防御
反逆向工程技术:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 代码混淆 │
│ ├─ 类名混淆 │
│ ├─ 方法名混淆 │
│ ├─ 字段名混淆 │
│ ├─ 字符串加密 │
│ └─ 控制流混淆 │
│ │
│ 代码保护 │
│ ├─ 代码完整性校验 │
│ ├─ 代码分片 │
│ ├─ 代码虚拟化 │
│ └─ 代码加密 │
│ │
│ 环境检测 │
│ ├─ 反调试检测 │
│ ├─ 反 Root 检测 │
│ ├─ 反模拟器检测 │
│ ├─ 反 Hook 检测 │
│ └─ 反内存转储 │
│ │
│ 运行时保护 │
│ ├─ 代码动态加载 │
│ ├─ 代码解密执行 │
│ ├─ 代码验证 │
│ └─ 代码完整性校验 │
│ │
└─────────────────────────────────────────────────────────────┘9.2 代码混淆
ProGuard 配置:
proguard
# 保持类
-keep class com.example.** { *; }
# 混淆设置
-obfuscationdictionary dictionary.txt
-seed seedname **
-applymapping mapping.txt
-useuniqueclassmembermapping
-line numberseparation 2
-assumenosideeffects class com.example.util.LogUtil { public static *; }
-dontusemixedcaseclassnames
-dontpreverify
-verbose
-printseeds seeds.txt
-printusage unused.txt
-printcfg cfg.txt
# 字符串加密
-replacestringencodings true
-obfuscateclassnames
-obfuscationdictionary dictionary.txt
# 控制流混淆
-controlflow 50
-controlflowtrycatch 5010. 代码保护
10.1 代码保护策略
代码保护策略:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 静态保护 │
│ ├─ 代码混淆 │
│ ├─ 代码加密 │
│ ├─ 代码签名 │
│ └─ 代码完整性校验 │
│ │
│ 动态保护 │
│ ├─ 代码动态加载 │
│ ├─ 代码解密执行 │
│ ├─ 代码验证 │
│ └─ 运行时完整性检查 │
│ │
│ 网络保护 │
│ ├─ API 密钥保护 │
│ ├─ 通信加密 │
│ ├─ 请求签名 │
│ └─ 频率限制 │
│ │
│ 数据保护 │
│ ├─ 数据加密 │
│ ├─ 密钥保护 │
│ ├─ 数据完整性校验 │
│ └─ 安全存储 │
│ │
└─────────────────────────────────────────────────────────────┘11. 面试考点
11.1 基础考点
1. SELinux 的作用?
答案:
┌─────────────────────────────────────────────────────────────┐
│ │
│ SELinux 作用 │
│ ├─ 强制访问控制 (MAC) │
│ ├─ 进程隔离 │
│ ├─ 文件保护 │
│ ├─ 网络保护 │
│ └─ 系统安全 │
│ │
└─────────────────────────────────────────────────────────────┘2. 应用沙箱机制?
答案:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 应用沙箱 │
│ ├─ 进程隔离 │
│ ├─ 文件隔离 │
│ ├─ 网络隔离 │
│ ├─ 资源隔离 │
│ └─ 权限隔离 │
│ │
└─────────────────────────────────────────────────────────────┘11.2 进阶考点
1. 签名方案演进?
答案:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 签名方案 │
│ ├─ v1 签名:JAR 签名 │
│ ├─ v2 签名:全 APK 签名 │
│ ├─ v3 签名:证书吊销 │
│ └─ v4 签名:包完整性 │
│ │
└─────────────────────────────────────────────────────────────┘2. 证书锁定?
答案:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 证书锁定 │
│ ├─ NetworkSecurityConfig 配置 │
│ ├─ 证书 PIN 值 │
│ ├─ 防止中间人攻击 │
│ └─ 确保连接安全 │
│ │
└─────────────────────────────────────────────────────────────┘11.3 高级考点
1. Android Keystore 使用?
答案:
┌─────────────────────────────────────────────────────────────┐
│ │
│ Android Keystore │
│ ├─ 密钥生成 │
│ ├─ 密钥存储(硬件 backed) │
│ ├─ 密钥使用(加密/解密) │
│ ├─ 密钥删除 │
│ └─ 防提取 │
│ │
└─────────────────────────────────────────────────────────────┘2. 反调试技术?
答案:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 反调试技术 │
│ ├─ 进程检测 │
│ ├─ 时间检测 │
│ ├─ 内存检测 │
│ ├─ 环境检测 │
│ └─ 行为检测 │
│ │
└─────────────────────────────────────────────────────────────┘文档信息:
- 字数:约 16000 字
- 包含:SELinux 机制、应用沙箱、签名机制、权限模型、网络安全、数据加密、反调试、反逆向、代码保护、面试考点
- 代码示例:包含完整的安全实现代码
- ASCII 架构图:包含多个架构和流程图
- 最佳实践:安全开发最佳实践
建议:
- 掌握 SELinux 的基本概念和使用
- 了解应用沙箱的隔离机制
- 熟悉签名方案的演进和验证
- 学习网络安全和数据加密实现
- 了解反调试和反逆向技术
总结
已完成 14_System 模块中 5 个文件的创建:
- 06_启动流程.md - 约 84KB - 包含 Bootloader、Kernel、Init、Zygote、SystemServer、Launcher、App 启动流程等
- 07_包安装流程.md - 约 42KB - 包含安装方式、PackageInstallerService、PMS 解析、签名验证、权限授予、dex2oat 等
- 08_通知机制.md - 约 37KB - 包含 NotificationManager、NotificationChannel、通知优先级、通知操作、自定义样式等
- 09_权限系统.md - 约 40KB - 包含权限级别、运行时权限、权限组、特殊权限、版本变化等
- 10_安全机制.md - 约 48KB - 包含 SELinux、应用沙箱、签名机制、网络安全、数据加密、反调试等
所有文件均包含:
- 详细的源码分析(引用 Android 源码)
- ASCII 流程图
- 面试考点(基础/进阶/高级)
- 代码示例
- 最佳实践建议