添加Fiddler/Mitmproxy证书为安卓系统证书

Android证书分为“用户证书”和“系统证书”两种,在设置->安全->"查看安全证书"列表中,可以看到“系统”和“用户”两个Tab。用户通过浏览器下载安装或者通过WLAN高级设置安装的证书均为用户证书。


安装为系统证书有什么好处呢?

(1)安装用户证书必须要设置开机密码,而且设置后就不能取消,除非先删掉所有的用户证书。如果安装为系统证书就不需要设置开机密码,自动化操作时更方便。

(2)Android 7以上版本APP默认不信任用户证书,只信任系统证书,安装为用户证书,对APP的HTTPS抓包会失败。安装为全局证书才能被所有APP信任,方可进行HTTPS抓包。


怎么将Fiddler或Mitmproxy的证书安装为安卓系统证书呢?

Android的系统证书的存储位置是/system/etc/security/cacerts,证书文件必须是PEM格式,而且文件命名必须符合系统证书规范。


下面是具体的步骤(注意:设备必须先ROOT):

view plaincopy to clipboardprint?

# 第一步,先下载好Fiddler或Mitmproxy的证书文件,PEM或者DER格式均可。  


# 第二步,获取有效的系统证书文件名。  

# 如果是PEM格式的:  

openssl x509 -inform PEM -subject_hash_old -in mitmproxy-ca-cert.pem -noout  

# 如果是DER格式的:  

openssl x509 -inform der -subject_hash_old -in FiddlerRoot.cer  -noout  

# 例如,输出8bbe0e8d  


# 第三步,转换证书格式为PEM格式,并重命名证书为有效的系统证书名。  

# 如果是PEM格式的:  

openssl x509 -inform PEM -in mitmproxy-ca-cert.pem -out 8bbe0e8d.0  

# 如果是DER格式的:  

openssl x509 -inform der -in FiddlerRoot.cer -out 8bbe0e8d.0  


# 第四步,上传准备好的证书文件到设备,例如  

adb push8bbe0e8d.0 /sdcard/  


# 第五步  

# 以下进入adb shell后操作  

adb shell  

# 获取root权限  

su  

# 重新挂载系统,以可以写入文件到系统目录  

mount -o rw,remount /system  

# 复制证书到Android系统证书目录  

cp /sdcard/8bbe0e8d.0 /system/etc/security/cacerts  

# 修改证书权限  

chmod644 /system/etc/security/cacerts/8bbe0e8d.0  

# 上述可整合为一句  

adb shell"su -c 'mount -o rw,remount /system;cp /sdcard/8bbe0e8d.0 /system/etc/security/cacerts;chmod 644 /system/etc/security/cacerts/8bbe0e8d.0;'"  

# 重启设备  

adb reboot  

操作完成之后,我们就能在系统证书列表中看到,如下图所示:

上述步骤很繁琐。下面给出一个我们APP数据采集项目中用到的自动化脚本,能够自动完成系统证书的安装全过程。支持PEM和DER两种格式。

view plaincopy to clipboardprint?

# coding: utf-8  

# install_as_android_system_ca.py  

# 添加证书为证书为安卓系统证书  

# 要求:  

# (1)本地OpenSSL版本 > 1.0;  

# (2)目标设备已ROOT;  

# 已测试验证:  

# Android 5.1测试验证通过;  

# Android 7.0测试验证通过;  

# 注意:Android 6.0尚未验证通过,原因尚不知;  


import sys  

import os  

import subprocess  


def install(local_ca_path, device=None):  

"""安装证书为安卓系统证书

    local_ca_path - 证书的本地路径,支持CER格式和PEM格式;

    device - 目标设备序列号,若不指定则为默认设备;

    """  

# 判断本地证书是否为PEM格式  

    with open(local_ca_path) as f:  

if '--BEGIN CERTIFICATE--' in f.read():  

# PEM格式的  

is_pem =True  

else:  

# 非PEM格式的  

is_pem =False  


print 'CA file "{}" is {} format.'.format(local_ca_path, 'PEM' if is_pem else 'CER')  


# 获取有效的系统证书文件名  

print 'Generate valid android system CA file name for "{}"...'.format(local_ca_path)  

if is_pem:  

cmd ='openssl x509 -inform PEM -subject_hash_old -in {} -noout'.format(local_ca_path)  

else:  

cmd ='openssl x509 -inform der -subject_hash_old -in {}  -noout'.format(local_ca_path)  

print cmd  

android_system_ca_name = subprocess.check_output(cmd, shell=True).strip() + '.0'  

print 'Android system CA file name for "{}" is: {}'.format(local_ca_path, android_system_ca_name)  


# 准备传输到安卓系统的证书,本地路径  

android_system_ca_filepath = os.path.join(os.path.dirname(sys.argv[0]), android_system_ca_name)  


# 如果是CER格式,转为PEM格式  

if local_ca_path.lower().endswith('.cer'):  

print 'Convert CER "{}" into PEM "{}"...'.format(local_ca_path, android_system_ca_filepath)  

if is_pem:  

cmd ='openssl x509 -inform PEM -in {} -out {}'.format(local_ca_path, android_system_ca_filepath)  

else:  

cmd ='openssl x509 -inform der -in {} -out {}'.format(local_ca_path, android_system_ca_filepath)  

print cmd  

print subprocess.check_output(cmd, shell=True)  


# 上传到SD卡根路径  

adb_cmd_prefix ='adb ' if not device else 'adb -s "{}" '.format(device)  

print 'Push "{}" onto device /sdcard/...'.format(android_system_ca_filepath)  

cmd = adb_cmd_prefix +'push "{}" /sdcard/'.format(android_system_ca_filepath)  

print cmd  

print subprocess.check_output(cmd, shell=True)  


# 将证书复制到系统证书目录下  

print 'Move /sdcard/{} to /system/etc/security/cacerts, and set permission.'.format(android_system_ca_name)  

cmd = adb_cmd_prefix +'''''shell "su -c 'mount -o rw,remount /system;cp /sdcard/{} /system/etc/security/cacerts;chown root:root /system/etc/security/cacerts/{};chmod 644 /system/etc/security/cacerts/{};'"'''.format(android_system_ca_name, android_system_ca_name, android_system_ca_name)  

print cmd  

print subprocess.check_output(cmd, shell=True)  


# 把刚复制到安卓系统证书目录下的证书内容打印出来,看看是否复制成功了  

cmd = adb_cmd_prefix +'shell cat /system/etc/security/cacerts/{}'.format(android_system_ca_name)  

if '--BEGIN CERTIFICATE--' in subprocess.check_output(cmd, shell=True):  

# 完成,提示重启设备  

print 'Successed. Need to reboot the device now!'  

else:  

# 失败了,应该是权限不足,目标设备没ROOT  

print 'Failed. Please root the device first!'  


if __name__ == '__main__':  

try:  

local_ca_path = sys.argv[1]  

except IndexError:  

print 'Usage: python install_as_android_system_ca.py "Local ca path(support .cer and .pem)" [Device]'  


try:  

device = sys.argv[2]  

except IndexError:  

device =None  


    install(local_ca_path=local_ca_path, device=device)  

你可能感兴趣的:(添加Fiddler/Mitmproxy证书为安卓系统证书)