「这是我参与2022首次更文挑战的第30天,活动详情查看:2022首次更文挑战」
一、前言
(1)Ubuntu
安装
下载后:
# 1. 解压
$ sudo tar zxvf charles-proxy-4.2.8_amd64.tar.gz
# 2. 移动
$ sudo mv charles /opt/charles
# 3. 使其可以命令启动
$ sudo vi /etc/profile
# 在最后一行加入
export PATH=$PATH:/opt/charles/bin
# 4. 使当前终端生效,可启动
$ sudo source /etc/profile
复制代码
**激活码生成:**www.zzzmode.com/mytools/cha…
打开
charles
->Help
->Register Charles
# 例如
Registered Name: ddd
License Key: fa1b27097ca4845676
复制代码
证书
- 下载
Charles
的SSL
根证书:Help -> SSL Proxying -> Install Charles Root Certificate
# 1. 在 home 下 .charles/ca/ 能找到这两个文件
$ ~/.charles/ca$ ll
-rw-r--r-- 1 donald donald 1344 Feb 15 16:03 charles-proxy-ssl-proxying-certificate.cer
-rw-r--r-- 1 donald donald 1893 Feb 15 16:03 charles-proxy-ssl-proxying-certificate.pem
# 2. 再执行执行格式转换
openssl x509 -outform der -in charles-proxy-ssl-proxying-certificate.pem -out charles-proxy-ssl-proxying-certificate.crt
# 发现多出一个文件 crt
$ ll
total 24
drwxr-xr-x 2 donald donald 4096 Feb 15 16:12 ./
drwxr-xr-x 6 donald donald 4096 Feb 16 04:00 ../
-rw-r--r-- 1 donald donald 1344 Feb 15 16:03 charles-proxy-ssl-proxying-certificate.cer
-rw-r--r-- 1 donald donald 1344 Feb 15 16:12 charles-proxy-ssl-proxying-certificate.crt
-rw-r--r-- 1 donald donald 1893 Feb 15 16:03 charles-proxy-ssl-proxying-certificate.pem
复制代码
- 在
/usr/share/ca-certificates
文件夹下新建一个目录charles
,复制刚才转化的证书
$ cd /usr/share/ca-certificates
$ sudo mkdir charles
$ sudo cp ~/.charles/ca/charles-proxy-ssl-proxying-certificate.crt /usr/share/ca-certificates/charles/
# 查看
/usr/share/ca-certificates/charles$ ll
-rw-r--r-- 1 root root 1344 Feb 16 10:32 charles-proxy-ssl-proxying-certificate.crt
复制代码
- 在
/etc/ca-certificates.conf
这个配置文件的最后追加charles/charles-proxy-ssl-proxying-certificate.crt
$ sudo vi /etc/ca-certificates.conf
复制代码
- 更新证书
$ sudo update-ca-certificates
$ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
rehash: skipping charles-proxy-ssl-proxying-certificate.pem,it does not contain exactly one certificate or CRL
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
Adding debian:charles-proxy-ssl-proxying-certificate.pem
done.
Updating Mono key store
Linux Cert Store Sync - version 4.6.2.0
Synchronize local certs with certs from local Linux trust store.
Copyright 2002, 2003 Motus Technologies. Copyright 2004-2008 Novell. BSD licensed.
I already trust 133, your new list has 133
Import process completed.
Done
done.
# 查看
/etc/ssl/certs$ ll | grep "charles"
lrwxrwxrwx 1 root root 77 Feb 16 10:42 charles-proxy-ssl-proxying-certificate.pem -> /usr/share/ca-certificates/charles/charles-proxy-ssl-proxying-certificate.crt
复制代码
(2)移动端
(1) 连接配置
- 手机需要与
PC
/ 服务器在同一个网络。 - 启动
Charles
,设置一个监听端口,默认为8888
。 - 手机一般使用
Wifi
接入,因此在Wifi
接入配置时候,在高级配置中设置,服务器地址,配置为Charles
所在机器的IP
地址,端口为Charles
监听端口。 - 此时在
Charles
上可以看到抓取到的手机网络包。
(2)HTTPS
配置
Charles
可以抓到所有的网络包,但是只能解开 HTTP/HTTPS
的包。对于 HTTPS
协议,需要配置 Charles
证书。
-
在
PC
/ 服务器,安装Charles
的CA
证书,到操作系统的信任证书链中:Help->SSL Proxying->Install Charls root certificate
。 -
在手机端,安装
Charles
的CA
证书,到操作系统的信任证书链中: 打开浏览器,输入chls.pro/ssl
,下载证书,并安装证书。
(3)Java
程序
官网:www.charlesproxy.com/documentati…
将 Charles
根证书添加到 Java
中的根证书信任库中,然后所有 Java
应用程序都将信任 Charles
颁发的证书:
# 在 Charles 中,转到 Help 菜单并选择 SSL Proxying > Save Charles Root Certificate
# 将根证书作为 Base 64 编码证书 (.pem) 保存到 home
$ sudo keytool -import -alias charles -file ~/charles-ssl-proxying-certificate.pem -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
# 然后输入:yes
# 查询
$ keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit | grep "charles"
复制代码
有三种方法:
- 在代码里加上:
System.setProperty("http.proxyHost", "127.0.0.1");
System.setProperty("http.proxyPort", "8888");
复制代码
- 在
IDEA
中加入参数
# VM options 中加入:
-DproxySet=true -DproxyHost=127.0.0.1 -DproxyPort=8888
复制代码
- 在
IDEA
里开启
(4)Java
证书
没有配置证书的时候,报的异常:
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
复制代码
- 问题的根本是:
缺少安全证书时出现的异常
- 解决问题方法:
安全认证证书导入到客户端即可
执行步骤:
javac InstallCert.java
java InstallCert baidu.com
- 输入1然后回车,然后当前目录下就会生成名为:
jssecacerts
的证书
Enter certificate to add to trusted keystore or 'q' to quit: [1]
1
复制代码
- 将刚才生成的证书
jssecacerts
放置到$JAVA_HOME/jre/lib/security
目录下,必须确认该JDK
的jre
是项目所用的JDK
$ sudo cp jssecacerts $JAVA_HOME/jre/lib/security/
复制代码
- 重启应用
InstallCert.java
如下,通过以下程序获取安全证书::
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class InstallCert {
public static void main(String[] args) throws Exception {
String host ;
int port ;
char[] passphrase;
if ((args.length == 1) || (args.length == 2)) {
String[] c = args[0].split(":");
host = c[0];
port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
String p = (args.length == 1) ? "changeit" : args[1];
passphrase = p.toCharArray();
} else {
System.out.println("Usage: java InstallCert <host>[:port] [passphrase]");
return;
}
File file = new File("jssecacerts");
if (file.isFile() == false) {
char SEP = File.separatorChar;
File dir = new File(System.getProperty("java.home") + SEP + "lib"
+ SEP + "security");
file = new File(dir, "jssecacerts");
if (file.isFile() == false) {
file = new File(dir, "cacerts");
}
}
System.out.println("Loading KeyStore " + file + "...");
InputStream in = new FileInputStream(file);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, passphrase);
in.close();
SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager) tmf
.getTrustManagers()[0];
SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
context.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory factory = context.getSocketFactory();
System.out
.println("Opening connection to " + host + ":" + port + "...");
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.setSoTimeout(10000);
try {
System.out.println("Starting SSL handshake...");
socket.startHandshake();
socket.close();
System.out.println();
System.out.println("No errors, certificate is already trusted");
} catch (SSLException e) {
System.out.println();
e.printStackTrace(System.out);
}
X509Certificate[] chain = tm.chain;
if (chain == null) {
System.out.println("Could not obtain server certificate chain");
return;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
System.out.println();
System.out.println("Server sent " + chain.length + " certificate(s):");
System.out.println();
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
MessageDigest md5 = MessageDigest.getInstance("MD5");
for (int i = 0; i < chain.length; i++) {
X509Certificate cert = chain[i];
System.out.println(" " + (i + 1) + " Subject "
+ cert.getSubjectDN());
System.out.println(" Issuer " + cert.getIssuerDN());
sha1.update(cert.getEncoded());
System.out.println(" sha1 " + toHexString(sha1.digest()));
md5.update(cert.getEncoded());
System.out.println(" md5 " + toHexString(md5.digest()));
System.out.println();
}
System.out
.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");
String line = reader.readLine().trim();
int k;
try {
k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
} catch (NumberFormatException e) {
System.out.println("KeyStore not changed");
return;
}
X509Certificate cert = chain[k];
String alias = host + "-" + (k + 1);
ks.setCertificateEntry(alias, cert);
OutputStream out = new FileOutputStream("jssecacerts");
ks.store(out, passphrase);
out.close();
System.out.println();
System.out.println(cert);
System.out.println();
System.out
.println("Added certificate to keystore 'jssecacerts' using alias '"
+ alias + "'");
}
private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
private static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 3);
for (int b : bytes) {
b &= 0xff;
sb.append(HEXDIGITS[b >> 4]);
sb.append(HEXDIGITS[b & 15]);
sb.append(' ');
}
return sb.toString();
}
private static class SavingTrustManager implements X509TrustManager {
private final X509TrustManager tm;
private X509Certificate[] chain;
SavingTrustManager(X509TrustManager tm) {
this.tm = tm;
}
public X509Certificate[] getAcceptedIssuers() {
throw new UnsupportedOperationException();
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throw new UnsupportedOperationException();
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
this.chain = chain;
tm.checkServerTrusted(chain, authType);
}
}
}
复制代码
二、弱网测试
一些概念:
Bandwidth
(带宽)Utilistation
(利用百分比)Round-trip
(往返延迟)MTU
(最大传输单元)
网络情况:
- 3G:300k-2Mbps左右
- 2.5G(GPRS)一般在100kbps
- 2G(GSM)一般在5-9kbps
网络 | 上行 | 下行 |
---|---|---|
弱网 | 10 | 30 |
2G | 15 | 50 |
3G | 384 | 2800 |
参数参考:数据来源
在 IDEA
里执行程序,发出网络连接: