实现https信任所有证书的方法
android平台上经常有使用https的需求,对于https服务器使用的根证书是受信任的证书的话,实现https是非常简单的,直接用httpclient库就行了,与使用http几乎没有区别。但是在大多数情况下,服务器所使用的根证书是自签名的,或者签名机构不在设备的信任证书列表中,这样使用httpclient进行https连接就会失败。解决这个问题的办法有两种,一是在发起https连接之前将服务器证书加到httpclient的信任证书列表中,这个相对来说比较复杂一些,很容易出错;另一种办法是让httpclient信任所有的服务器证书,这种办法相对来说简单很多,但安全性则差一些,但在某些场合下有一定的应用场景。这里要举例说明的就是后一种方法:实例化httpclinet对象时要进行一些处理主要是绑定https连接所使用的端口号,这里绑定了443和8443:
[java] view
plaincopy
schemeregistry schemeregistry = new schemeregistry();
schemeregistry.register(new scheme("https",
new easysslsocketfactory(), 443));
new easysslsocketfactory(), 8443));
clientconnectionmanager connmanager = new threadsafeclientconnmanager(params, schemeregistry);
httpclient httpclient = new defaulthttpclient(connmanager, params);
上面的easysslsocketfactory类是我们自定义的,主要目的就是让httpclient接受所有的服务器证书,能够正常的进行https数据读取。相关代码如下:
public class easysslsocketfactory implements socketfactory,
layeredsocketfactory {
private sslcontext sslcontext = null;
private static sslcontext createeasysslcontext() throws ioexception {
try {
sslcontext context = sslcontext.getinstance("tls");
context.init(null, new trustmanager[] { new easyx509trustmanager(
null) }, null);
return context;
} catch (exception e) {
throw new ioexception(e.getmessage());
}
}
private sslcontext getsslcontext() throws ioexception {
if (this.sslcontext == null) {
this.sslcontext = createeasysslcontext();
return this.sslcontext;
public socket connectsocket(socket sock, string host, int port,
inetaddress localaddress, int localport, httpparams params)
throws ioexception, unknownhostexception, connecttimeoutexception {
int conntimeout = httpconnectionparams.getconnectiontimeout(params);
int sotimeout = httpconnectionparams.getsotimeout(params);
inetsocketaddress remoteaddress = new inetsocketaddress(host, port);
sslsocket sslsock = (sslsocket) ((sock != null) ? sock : createsocket());
if ((localaddress != null) || (localport > 0)) {
// we need to bind explicitly
if (localport < 0) {
localport = 0; // indicates "any"
}
inetsocketaddress isa = new inetsocketaddress(localaddress,
localport);
sslsock.bind(isa);
sslsock.connect(remoteaddress, conntimeout);
sslsock.setsotimeout(sotimeout);
return sslsock;
public socket createsocket() throws ioexception {
return getsslcontext().getsocketfactory().createsocket();
public boolean issecure(socket socket) throws illegalargumentexception {
return true;
public socket createsocket(socket socket, string host, int port,
boolean autoclose) throws ioexception, unknownhostexception {
return getsslcontext().getsocketfactory().createsocket(socket, host,
port, autoclose);
// -------------------------------------------------------------------
// javadoc in org.apache.http.conn.scheme.socketfactory says :
// both object.equals() and object.hashcode() must be overridden
// for the correct operation of some connection managers
public boolean equals(object obj) {
return ((obj != null) && obj.getclass().equals(
easysslsocketfactory.class));
public int hashcode() {
return easysslsocketfactory.class.hashcode();
}
public class easyx509trustmanager implements x509trustmanager {
private x509trustmanager standardtrustmanager = null;
public easyx509trustmanager(keystore keystore)
throws nosuchalgorithmexception, keystoreexception {
super();
trustmanagerfactory factory = trustmanagerfactory
.getinstance(trustmanagerfactory.getdefaultalgorithm());
factory.init(keystore);
trustmanager[] trustmanagers = factory.gettrustmanagers();
if (trustmanagers.length == 0) {
throw new nosuchalgorithmexception("no trust manager found");
this.standardtrustmanager = (x509trustmanager) trustmanagers[0];
public void checkclienttrusted(x509certificate[] certificates,
string authtype) throws certificateexception {
standardtrustmanager.checkclienttrusted(certificates, authtype);
public void checkservertrusted(x509certificate[] certificates,
if ((certificates != null) && (certificates.length == 1)) {
certificates[0].checkvalidity();
} else {
standardtrustmanager.checkservertrusted(certificates, authtype);
public x509certificate[] getacceptedissuers() {
return this.standardtrustmanager.getacceptedissuers();
}
plaincopyprint?
schemeregistry.register(new scheme("http", plainsocketfactory
.getsocketfactory(), 80));
sslsocketfactory sf = sslsocketfactory.getsocketfactory();
keystore truststore = keystore.getinstance(keystore
.getdefaulttype());
truststore.load(null, null);
sf = new sslsocketfactoryex(truststore);
sf.sethostnameverifier(sslsocketfactory.allow_all_hostname_verifier);
// 允许所有主机的验证
log.e("erro", "sslsocketfactory error");
schemeregistry.register(new scheme("https", sf, 443));
threadsafeclientconnmanager cm = new threadsafeclientconnmanager(
httpparams, schemeregistry);
defaulthttpclient httpclient = new defaulthttpclient(cm, httpparams);
上面的sslsocketfactoryex类主要目的就是让httpclient接受所有的服务器证书,能够正常的进行https数据读取。相关代码如下:
class sslsocketfactoryex extends sslsocketfactory {
sslcontext sslcontext = sslcontext.getinstance("tls");
public sslsocketfactoryex(keystore truststore)
throws nosuchalgorithmexception, keymanagementexception,
keystoreexception, unrecoverablekeyexception {
super(truststore);
trustmanager tm = new x509trustmanager() {
@override
public java.security.cert.x509certificate[] getacceptedissuers() {
return null;
}
public void checkclienttrusted(
java.security.cert.x509certificate[] chain,
string authtype)
throws java.security.cert.certificateexception {
public void checkservertrusted(
};
sslcontext.init(null, new trustmanager[] { tm }, null);
@override
public socket createsocket(socket socket, string host, int port,
boolean autoclose) throws ioexception, unknownhostexception {
return sslcontext.getsocketfactory().createsocket(socket, host,
port, autoclose);
public socket createsocket() throws ioexception {
return sslcontext.getsocketfactory().createsocket();
添加http头信息token认证
有时候服务器端需要传递token来验证请求来源是否是受信任的,以增强安全性:
重点是有些服务器要求将token转化成base64编码。
于是 string token ="basic " +
base64.encodetostring("your token".getbytes(), base64.no_wrap);
注意,参数是 base64.no_wrap,而不是base64.default
。而否则会返回 “400 bad request”,而得不到数据。