#HTTPS证书配置
搞过Android HTTPS抓包的开发者/爬虫er都懂,Android 7.0是个分水岭式的小坑——之前手动装个用户CA证书全搞定,之后99%的应用默认不信任用户凭证,抓包直接“红叉叉/HTTPS连接重置”。
今天这篇就是专门解决这个问题的保姆级干货:从OpenSSL生成自签名CA、转Android系统要求的哈希命名格式,到推送到/system/etc/security/cacerts/(需要ROOT权限),最后给你封装好一键Python管理脚本,完全解放双手!
#证书安装到系统分区(ROOT版,最稳定)
Android把证书分为两类:
- 用户证书:手动装就行,但7.0+应用默认不信任;
- 系统证书:存放在
/system/etc/security/cacerts/,所有应用无条件信任——这是我们的目标。
操作前请确认:
- 你的设备已获取ROOT权限;
- 电脑已安装OpenSSL并加入PATH;
- 设备已开启USB调试,通过adb正常连接。
#1. 电脑端生成自签名CA
先在本地准备信任根证书和私钥:
# 创建工作目录并进入
mkdir -p mobile_https_cert && cd mobile_https_cert
# 生成2048位RSA私钥(不带密码,方便代理工具自动加载)
openssl genrsa -out ca.key 2048
# 生成自签名CA证书(有效期365天,主题按需改)
openssl req -new -x509 -key ca.key -out ca.crt -days 365 -nodes -subj "/CN=MobileCrawler CA/O=MyApp/O=MobileDev/C=CN"#2. 转Android系统CA命名格式
Android系统CA文件名必须用「证书主题的旧版MD5哈希值 + .0」,用OpenSSL快速获取:
# 提取旧版MD5哈希
CERT_HASH=$(openssl x509 -inform PEM -subject_hash_old -in ca.crt | head -1)
# 重命名证书
mv ca.crt ${CERT_HASH}.0#3. 推送到系统分区并生效
通过adb的ROOT权限修改只读的system分区:
# 重启adb到ROOT模式
adb root
# 重新挂载system为可读写(注意:部分设备分区挂载路径不同,比如用/vendor,但大多数通用/system)
adb remount
# 推送重命名后的证书
adb push ${CERT_HASH}.0 /system/etc/security/cacerts/
# 设置正确的文件权限(644,系统CA的默认权限)
adb shell chmod 644 /system/etc/security/cacerts/${CERT_HASH}.0
# 重启设备让证书生效
adb reboot#4. 验证安装
设备重启后,打开adb shell检查目录:
adb shell ls -la /system/etc/security/cacerts/ | grep ${CERT_HASH}如果输出了刚才的.0文件,说明安装成功!
#Python一键证书管理脚本
为了避免每次手动敲一堆命令,我写了个轻量级的脚本,封装了生成、转换、推送、验证的全流程,带友好的错误提示。
#完整脚本
import os
import subprocess
import shutil
from typing import Optional, Tuple
class AndroidCertManager:
"""Android HTTPS抓包/爬虫CA证书管理器"""
def __init__(self, work_dir: str = "mobile_cert"):
self.work_dir = work_dir
self.ca_key: Optional[str] = None
self.ca_crt: Optional[str] = None
self.android_crt: Optional[str] = None
self.cert_hash: Optional[str] = None
os.makedirs(self.work_dir, exist_ok=True)
def generate_ca(self) -> Tuple[Optional[str], Optional[str]]:
"""生成自签名CA证书和私钥"""
try:
key_path = os.path.join(self.work_dir, "ca.key")
crt_path = os.path.join(self.work_dir, "ca.crt")
# OpenSSL生成私钥
subprocess.run(
["openssl", "genrsa", "-out", key_path, "2048"],
capture_output=True,
check=True,
timeout=30
)
# OpenSSL生成自签名证书
subprocess.run(
[
"openssl", "req", "-new", "-x509",
"-key", key_path,
"-out", crt_path,
"-days", "365", "-nodes",
"-subj", "/CN=MobileCrawler CA/O=MobileDev/C=CN"
],
capture_output=True,
check=True,
timeout=30
)
self.ca_key, self.ca_crt = key_path, crt_path
print(f"✅ CA生成成功!")
print(f" 私钥:{self.ca_key}")
print(f" 证书:{self.ca_crt}")
return self.ca_key, self.ca_crt
except subprocess.CalledProcessError as e:
print(f"❌ OpenSSL执行失败:{e.stderr.decode('utf-8', errors='ignore')}")
return None, None
except FileNotFoundError:
print("❌ 未找到OpenSSL,请先安装并加入PATH")
return None, None
def convert_to_android(self) -> Optional[str]:
"""转换为Android系统CA格式"""
if not self.ca_crt:
print("❌ 请先生成CA证书!")
return None
try:
# 提取旧版MD5哈希
hash_result = subprocess.run(
["openssl", "x509", "-inform", "PEM", "-subject_hash_old", "-in", self.ca_crt],
capture_output=True,
check=True,
text=True,
timeout=10
)
self.cert_hash = hash_result.stdout.strip().split("\n")[0]
# 重命名证书
android_crt_path = os.path.join(self.work_dir, f"{self.cert_hash}.0")
shutil.copy2(self.ca_crt, android_crt_path)
self.android_crt = android_crt_path
print(f"✅ Android格式转换成功!")
print(f" 文件:{self.android_crt}")
return self.android_crt
except subprocess.CalledProcessError as e:
print(f"❌ 哈希提取失败:{e.stderr}")
return None, None
def install_to_system(self) -> bool:
"""推送并安装到Android系统分区(需ROOT)"""
if not self.android_crt:
print("❌ 请先转换Android格式证书!")
return False
try:
# 检查adb连接
conn_result = subprocess.run(
["adb", "devices"],
capture_output=True,
text=True,
timeout=10
)
if "device" not in conn_result.stdout.split("\n")[1]:
print("❌ 未找到正常连接的Android设备!")
return False
# ROOT模式准备
print("🔐 正在尝试进入adb ROOT模式...")
subprocess.run(["adb", "root"], capture_output=True, timeout=10)
subprocess.run(["adb", "wait-for-device"], timeout=10)
# 挂载system为可读写
print("📂 正在重新挂载system为可读写...")
remount_result = subprocess.run(
["adb", "remount"],
capture_output=True,
text=True,
timeout=10
)
if "remount succeeded" not in remount_result.stdout:
print(f"⚠️ 挂载可能失败,请手动执行:adb shell su -c 'mount -o rw,remount /system'")
# 推送证书
print("📡 正在推送证书到设备...")
remote_temp = f"/sdcard/{os.path.basename(self.android_crt)}"
subprocess.run(
["adb", "push", self.android_crt, remote_temp],
capture_output=True,
check=True,
timeout=10
)
# 移动到system分区并设权限
print("🔧 正在安装到系统证书目录...")
remote_system = f"/system/etc/security/cacerts/{os.path.basename(self.android_crt)}"
install_cmd = (
f"su -c 'cp {remote_temp} {remote_system} && "
f"chmod 644 {remote_system} && "
f"rm {remote_temp}'"
)
subprocess.run(
["adb", "shell", install_cmd],
capture_output=True,
check=True,
timeout=10
)
# 验证安装
print("✅ 验证安装中...")
check_cmd = f"ls -la /system/etc/security/cacerts/ | grep {self.cert_hash}"
check_result = subprocess.run(
["adb", "shell", check_cmd],
capture_output=True,
text=True,
timeout=10
)
if self.cert_hash in check_result.stdout:
print("🎉 系统证书安装成功!请重启设备生效!")
return True
else:
print("❌ 证书验证失败!")
return False
except subprocess.CalledProcessError as e:
print(f"❌ 执行失败:{e.stderr.decode('utf-8', errors='ignore')}")
return False
except Exception as e:
print(f"❌ 未知错误:{e}")
return False
def setup_full(self) -> bool:
"""一键完成生成-转换-安装全流程"""
print("🚀 开始一键配置Android HTTPS证书...")
if not self.generate_ca():
return False
if not self.convert_to_android():
return False
return self.install_to_system()
if __name__ == "__main__":
# 直接运行一键配置
manager = AndroidCertManager()
manager.setup_full()#脚本使用方法
- 确保电脑满足前置条件(OpenSSL、adb、ROOT设备);
- 复制脚本保存为
cert_manager.py; - 直接运行:
python cert_manager.py - 脚本完成后手动重启设备即可。
#后续配置提醒
证书生效后,记得:
- 配置代理工具(Fiddler/Charles/Mitmproxy)使用我们刚才生成的
ca.crt和ca.key; - 在设备上设置代理指向电脑的IP和代理工具端口;
- 就可以正常抓取HTTPS流量啦!

