Http基础原理
目的是对https和相关依赖的安全技术 有一个概括的认识,在判断一些事儿的时候头脑更清晰。由于是基础理论方面的,都是理论,所以并没有太多代码相关的。大家如果觉得自己的理解与我所描述的不同,非常欢迎提出来,我们一起确认下。
内容目录:
为什么? 内容 对称加密 非对称加密 散列函数 (Base64编码) 数字签名 数字证书
Pinning
开发中的常见错误写法
为什么?
回答一部分同学心里的如下的问题:
与使用http相比,使用https之后会有哪些好处?证书是什么?QA:Https的抓包要怎么抓?为什么?贝勒爷:平时上一些“非正规网站”(比如xxx网【12306有进步了】)有的那个警告提示,点了“确定,继续前往” 意味着什么?开发:为什么有时候会遇到证书校验失败?少见的:为什么有时候我们也会遇到,明明我们已经把证书的签发者加到信任列表了,一些三方支付sdk的请求还是失败?
对于开发同学,各种资讯、博客、博客上的理解 等 整体的现状很残酷:
之前遇到的一些问题:
- 发到play上的app,下架;
- App(手机令牌)版本发现部分2.x的手机上出现证书无法验证通过。
- 一些大陆版app的实现的问题
其他: 博客上随处可见的错误导向: http://zhidao.baidu.com/link?url=uYegvR3uuNuwlkpkNwZhgNZBgJUGQpE_0UGEg9ynV_aRkYJM_685K-d9ro3tTH9JFhXx5mL19-aA30qLYlzrVa http://drops.wooyun.org/tips/3296
乌云上的报告:国内绝大部分Android APP存在信任所有证书漏洞 http://www.wooyun.org/bugs/wooyun-2014-079358
以及 之前一篇论文指出,在Google Play 上 13500 个免费热门应用程序当中,共有 1074 个 (8%) 应用程序因错误的 SSL 处理而导致使用者陷入 MITM攻击【中间人攻击】的风险中。
对称加密:(私钥加密)
一种加密算法,加密与解密使用同一个密钥。
对称加密是依照19世纪一位密码破解专家Auguste Kerckhoffs的观察结果而来的: 即使攻击者知晓了整个密码系统除密钥外的所有情报,系统仍然应当能保证安全。
如果加密算法优秀,攻击者只有一种方法,就是尝试所有可能的解码密钥,俗称穷举密钥搜索。基于此,密文的安全性完全取决于密钥,主要就是密钥长度(当然,还要假设密钥本质上是随机的)。128位的密钥,有34*1037种可能的组合。
常见的对称加密算法有:DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK、AES
对称加密大规模应用的问题:
随着使用对称加密的团体的增加,产生了更多的无法满足的需求: 1. 相同团体的成员必须共享相同的密钥,越多人加入,团体密钥出现问题的次数就越多。 2. 为了更好的安全性,可以在每两个人之间使用不同的密钥,但是这个方法不可扩展,虽然3个人只需要3个密钥,但是10个人就需要45个密钥,1000个人就需要499500个密钥! 3. 对称加密不能用于访问安全数据的无人系统,因为使用相同的密钥可以反转整个过程,系统出现任何问题都会影响存储在系统中的所有数据。
非对称加密
非对称加密:又称为公钥加密。不同于对称加密,非对称加密使用两个密钥,而不是一个;其中一个密钥是私密的,用于私人,另一个是公开的,将会被所有人共享。
两个密钥之间存在一些特殊的数学关系,使得: 利用公钥加密的数据,只有对应的私钥能够解密 。 (机密性) 如果用私钥加密数据,那么,任何人都可以利用对应的公钥解开消息。(这种操作不具有机密性,但可以用作数字签名。)
RSA是目前最普遍使用的非对称加密算法,现在推荐的RSA强度是2048位(强度等同于112位的对称密钥)。
非对称加密的问题:
慢
对称加密和非对称机密的区别:
对称加密算法,加密解密使用的是同一个密钥,如果要保证信息的安全,就要保证密钥的安全。但是涉及到一个密钥分发的问题。 加密解密速度快。
非对称加密算法,加密解密使用的是不同的密钥,其中一个是可以公开的,非对称加密算法能够保证,即使是在获知公钥、加密算法和加密算法源代码的情况下,也无法获得公钥对应的私钥,因此也无法对公钥加密的密文进行解密。非对称加密算法复杂,加解密速度慢。
所以,广泛使用对称与非对称加密算法结合的办法,对称加密算法速度快,用它来加密较长的文件,然后用非对称加密算法来加密文件密钥,解决了对称加密算法的密钥分发问题。
思考:MD5是一个什么加密算法?
散列函数:
散列函数(hash function) 是将任意长度的输入转化为定长输出的算法。散列函数的结果经常被简称为散列(hash)。适用于密码学的散列函数必须无法通过散列找到生成它的消息,也不能通过计算找到两条散列相同的消息等。散列函数最常使用的场合是以紧凑的方式表示并比较大量数据。散列函数经常被称为指纹、消息摘要。
有的同学可能会想必然会存在Hash碰撞,当然, 碰撞是肯定存在的【Hash碰撞:k1!=k2 为true,但是 hash(k1)== hash(k2) 为true ,那么就是发生了hash碰撞。】),但是,由于散列函数的输出结果很长,所以发生hash碰撞的概率非常低。
特点: 1. 长度固定:无论输入的消息有多长,计算出来的摘要长度是固定的。 2. 稳定性:一般情况下,只要输入消息不同,对其摘要后产生的摘要也不同,但相同的输入必定产生相同的输出。 3. 不可恢复:消息摘要并不包含原文的完整信息,所以只能进行正向的信息摘要,而无法仅仅从摘要中恢复出来原来的消息。
散列函数的常见应用: 文件校验–国外网站上的软件下载处,给出下载地址,同时给出该软件的md5指纹,sha-1指纹,供下载者来验证是否下载完成以及所下载的软件是否被篡改。
山东大学王小云教授《维基百科》 04年国际密码讨论年会上,末尾时发表md5/sha-0等哈希函数的冲撞,即两个完全不同的消息计算出完全相同的哈希值。 2005年2月,王小云与其同事提出SHA-1杂凑函数的杂凑冲撞。由于SHA-1杂凑函数被广泛应用于现今的主流电脑安保产品,其影响可想而知。王小云所提的杂凑冲撞算法只需少于2的69次方步骤(之前是2的80次方步。),同年8月,与其他人联手,又提出了SHA-1哈希函数哈希冲撞算法的改良版,将步骤缩短到2的63次方步;
目前md5还安全吗?
常见算法: MD5 ,摘要长度为128位。 SHA-1 , 摘要信息长度160位。比md5慢,但是更安全。 SHA256 算法摘要长度为 256 位。
现在使用最广泛的散列函数是SHA1,它的输出是160位。因为SHA1已经变弱,所以建议升级为SHA256。
**Base64
Base64是一种什么算法?
Base64不是一种加密算法!Base64仅仅是一种编码算法,任何人拿到base64的编码内容都可以通过固定的方法恢复出来原始内容。
Base64编码是从二进制到字符的过程。是一种基于64个可打印字符来表示二进制数据的方法。
Base64有自己的一个编码索引表,将原来的数据表示的每3个字节(24位)用4个Base64中的可打印字符来表示。(实际上就是把3个8位分成4个6位,每6位再分别对应上可打印字符,再处理不能整除的情况)
如果要编码的字节数不能被3整除,最后会多出1个或2个字节,那么可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行base64的编码。在编码后的base64文本后加上一个或两个’=’号,代表补足的字节数。
也就是:如果最后剩下一个字节,那么,末尾增加4个0再转换,Base64编码表示的末尾增加两个=;如果最后剩下两个字节,那么,末尾增加2个0再转换,Base64编码的末尾增加一个=。
数值 | ... read more
---|
数值 | 字符 | 数值 | 字符 | 数值 | 字符 | 数值 | 字符 | |||
---|---|---|---|---|---|---|---|---|---|---|
0 | A | 16 | Q | 32 | g | 48 | w | |||
1 | B | 17 | R | 33 | h | 49 | x | |||
2 | C | 18 | S | 34 | i | 50 | y | |||
3 | D | 19 | T | 35 | j | 51 | z | |||
4 | E | 20 | U | 36 | k | 52 | 0 | |||
5 | F | 21 | V | 37 | l | 53 | 1 | |||
6 | G | 22 | W | 38 | m | 54 | 2 | |||
7 | H | 23 | X | 39 | n | 55 | 3 | |||
8 | I | 24 | Y | 40 | o | 56 | 4 | |||
9 | J | 25 | Z | 41 | p | 57 | 5 | |||
10 | K | 26 | a | 42 | q | 58 | 6 | |||
11 | L | 27 | b | 43 | r | 59 | 7 | |||
12 | M | 28 | c | 44 | s | 60 | 8 | |||
13 | N | 29 | d | 45 | t | 61 | 9 | |||
14 | O | 30 | e | 46 | u | 62 | + | |||
15 | P | 31 | f | 47 | v | 63 | / |
例子: 字符串 “张33” ,按照gbk编码的二进制表示为:11010101110001010011001100110011
110101 53 1 011100 28 c 010100 20 U 110011 51 z 001100 12 M 110000 48 w 由于最后是 一个单独的字节,所以需要补两个=
所以,“张33”的gbk编码的Base64编码表示为 :1cUzMw==
Base64编码后会比原来占用的空间要多大约33%。 Base64的用途: Base64编码可用于在HTTP环境下传递较长的标识信息。Hibernate中使用base64把128bit的uuid编码为一个字符串。 在MIME格式的电子邮件中,base64可以用来将二进制字节序列数据编码成ASCII字符序列构成的文本。 … 但是,标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。有其他改进的Base64.
数字签名
数字签名:数字签名是非对称密钥加密技术与数字摘要技术的应用,是一个密码学方案。它使得验证一条电子消息或者一篇电子文档的真实性成为可能。
数字签名的签名方式:
数字签名的校验方式:
作用: 数字签名 可以验证发送者的身份和数据完整性。
算法: 区别于 不同的摘要算法,不同的非对称加密方式,数字签名算法也不尽相同。常见的数字签名算法包括MD5withRSA 、SHA1withRSA 等。正如签名算法的名称那样,MD5withRSA表示采用MD5算法生成需要发送正文的数字摘要,并使用RSA算法来对摘要进行加密和解密。同理,SHA1withRSA …
思考:
现实世界中我们是怎么样识别一个人的身份的呢?
那么,根据数字签名的原理和作用,思考下,网络世界中,我们应该如何识别一个用户或者服务器的身份?
数字证书
数字证书 也称为 电子证书,类似于身份证,也是另外一种形式的身份认证,用于标识网络中的用户身份。
数字证书通常会包含如下内容: 对象的名称(人、服务器、组织); 证书的过期时间; 证书的颁发机构(谁为证书担保); 证书颁发机构对证书信息的数字签名; 签名算法; 对象的公钥。
对象的名称指的是证书所代表的的用户,可以是人、服务器、组织等。
证书的过期时间用来确定证书是否仍然有效。
颁发机构将为证书的真实性与有效性做担保,确保证书所携带的信息是经过校验的。
数字签名用来鉴别证书的颁发机构,以及证书的内容是否完整。颁发机构用私钥对证书进行签名,而校验方使用颁发机构的公钥来解密签名,并与其用同一个摘要算法生成的摘要进行比较,便可以验证证书是否由该机构所颁发,信息是否完整。
对象的公钥用来对信息进行加密,信息传输到接收方,接收方将使用公钥对应的私钥进行解密。(ssl)
证书的通用存储格式: 不同的数字证书所包含的内容信息和格式可能不尽相同,因此,需要有一种标准格式来规范数字证书的存储和校验。大多数的数字证书都以一种标准的格式—X.509 来存储他们的信息。X.509提供了一种标准的方式,将证书信息规范的存储到一系列可解析的字段当中,X.509 V3是X.509标准目前使用最为广泛的版本。
英文 | 中文 | 备注 |
---|---|---|
Version | 版本 | 当前证书的X.509标准的版本号 |
Serial Number | 序列号 | 证书颁发机构(CA)生成的唯一序列号 |
Certificate Signature Algorithm | 证书签名算法 | 签名使用的签名算法,如SHA1withRSA |
Issuer | 证书颁发者 | 发布并对该证书进行签名的组织名称 |
Validity | 有效期 | 此证书有效的开始时间和结束时间 |
Subject | 对象名称 | 证书所代表的的实体,比如一个人或者一个组织 |
Subject Public Key Info | 对象的公钥信息 | 证书对象的公钥,生成公钥的算法,以及附加参数。 |
Issuer Unique Identifier (Optional) | 发布者ID(可选) | 证书颁发者的唯一标识符 |
Subject Unique Identifier (Optional) | 对象ID(可选) | 证书所代表的对象的唯一标识符 |
Extensions (Optional) | 扩展字段 | 可选的扩展字段集,每个扩展字段都可以被标识为关键或者是非关键的字段,关键的扩展字段非常重要,证书使用者一定要能够理解。如果证书使用者无法识别出关键扩展字段,就必须拒绝该证书! 目前常用的扩展字段包括: 基本约束——- 对象与证书颁发机构的关系 证书策略——-授予证书的策略 密钥使用——-对公开密钥的使用限制 |
…… | ….. | ….. |
Certificate Signature | 证书颁发机构数字签名 | 证书的颁发机构使用指定的签名算法及颁发机构的私钥对上述所有字段生成的数字签名 |
下面看下百度的数字证书:
颁发者?verisign
证书签发: 现实生活中,只有公安局签发的身份证才可以被公众所信任,自己制作的不行。
网络世界中,用户的数字证书需要由数字证书认证机构(Certificate Authority ,CA)来颁发,只有经过CA颁发的数字证书在网络中才具备可认证性。
数字证书的签发过程实际上就是对数字证书的内容,包括证书所代表对象的公钥进行数字签名,而验证证书的过程,实际上是校验数字证书的签名,包含了对证书有效期的验证。
证书签发的过程:
证书校验的过程:
证书验证
验证数字证书时(常见的情况是客户端(浏览器)校验):首先会检查证书的认证机构,如果该机构是权威的证书认证机构,则通过该权威认证机构的根证书获得证书颁发者的公钥,通过该公钥,对证书的数字签名进行校验(包括对有效时间的校验)。
观察下当当网的证书链:
要验证当当网登录页面的证书是否可信需要这样验证:
这样就形成了一条信任的依赖链,最后终结于根证书。根证书是一份特殊的证书,它的签发者是它本身,下载安装根证书就标明对该根证书及其所签发的证书都表示信任。所以,用户在使用数字证书前必须先安装颁发该证书的根证书。
大多数操作系统都会预先安装一些较为权威的证书认证机构的根证书,如VeriSign、GeoTrust等。如果证书是非权威认证机构的证书,用户需要自行下载安装该证书认证机构的根证书,并且保证该根证书的合法性!因为一旦安装该机构的根证书,表示信任该根证书所颁发的所有证书! 同理,Android上也会内置一些顶级CA的根证书,但是不同版本的android系统,内置的根证书数量可能不同,所以,可能会出现一些小的CA的证书在低版本系统上无法信任的问题。 多数浏览器会以操作系统内置的CA证书来作为自己的可信集合,但是,有的浏览器会自带证书库,比如 firefox.
常见的顶级CA: CFCA,GlobalSign,VeriSign ,Geotrust ,Thawte
Windows 7上受信任的根证书列表如下
常见的SSL证书种类
域名型 https 证书(DVSSL):信任等级一般,CA只会检查申请人是否具有使用特定域名的权利。浏览器显示与OV型的证书相同。 企业型 https 证书(OVSSL):信任等级强,须要验证企业的身份,审核严格,安全性更高; 增强型 https 证书(EVSSL):信任等级最高,一般用于银行证券等金融机构,审核严格,安全性最高,同时可以激活绿色网址栏(不同浏览器的支持不同)。 例如:https://member.icbc.com.cn/commlog/logon.jsp
为什么要信任CA?
CA作为可信第三方的重要条件之一就是CA的行为具有非否认性。作为第三方而不是简单的上级,就必须能让信任者有追究自己责任的能力。CA通过证书证实他人的公钥信息,证书上有CA的签名。用户如果因为信任证书而导致了损失,证书可以作为有效的证据用于追究CA的法律责任。正是因为CA愿意给出承担责任的承诺,所以也被称为可信第三方。 说白了,就是信任CA,假如你被骗了,最后查明是CA的责任,是CA的工作没做好,CA会赔钱。
案例: 荷兰的DigiNotar本来是负责发放证书的公司,但是在 2011年7月份就已经出现泄密的情况,但一直没有披露,后来,直到8月底,包括CIA、Google、微软和Twitter都陆续探测到黑客的假证书后,这一罪魁祸首才被发现。包括微软、苹果、Adobe等主要的科技公司均已经从信任域中删除了DigiNotar的证书,可以说,这家公司作为证书颁发机构已经完全没有存在的意义,所以破产倒闭也是情理之中。
思考:
- 想象下目前目前 证书 or https这块儿 整体大致是如何运转的。
- 开头的问题,大家都有答案了吗?
Pinning
相信大家已经都知道如何抓包了。 那么,有人遇到过接某个支付相关的SDK的时候,为了分析问题,做了抓包,但是发现请求竟然不成功了 如果能成功,这也是比较细思极恐的一件事儿~~ 任意一个CA都可以签发任意一个域名的证书 ;对于一般的网站和服务倒是还好,但是对于支付相关、金融、知名度高的网站或者服务,则风险很高;
答案:Pinning(钉扎 or 证书固定)
常见的错误写法
网络请求库中的错误写法:
X509TrustManager
`DefaultHttpClient httpclient = (DefaultHttpClient) getNewHttpClient();
try {
//Secure Protocol implementation.
SSLContext ctx = SSLContext.getInstance("SSL");
//Implementation of a trust manager for X509 certificates
X509TrustManager tm = new X509TrustManager() {`
public void checkClientTrusted(X509Certificate[] xcs,
String string) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] xcs,
String string) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ClientConnectionManager ccm = httpclient.getConnectionManager();
//register https protocol in httpclient's scheme registry
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", 443, ssf));
} catch (Exception e) {
e.printStackTrace();
}
HttpGet httpGet = new HttpGet(httpGetUrl);
HttpResponse response = httpclient.execute(httpGet, localContext);
new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
WebView的相关使用时的错误写法:
private class MyWebViewClient extends WebViewClient {
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed();
}
}
国内的App市场管理和检测相对更加松散,而Google play和App store则会更加正规,对App安装文件、代码等的检测相对更加严格,所以,之前做过Google Play上的App发布的应该都有遇到很多相似的因为代码不合规被下架或者退回的情况,对HTTPS的原理的理解恰恰就是避免这些HTTPS相关问题的基础,并且,对开发来说,可以让我们写的代码在我们头脑中有个更加清楚的理解;对QA来说,可以在抓包测试时更加有的放矢,甚至可以避免被开发“欺骗”;😺
Comments