Android _实现SSL解决不受信任的证书问题

本文转自:http://blog.csdn.net/shenyongjun1209/article/details/52780898

介绍

网络安全已成为大家最关心的问题. 如果你利用服务器存储客户资料, 那你应该考虑使用 SSL 加密客户跟服务器之间的通讯. 随着这几年手机应用迅速崛起. 黑客也开始向手机应用转移, 原因有下列3点:

手机系统各式各样, 缺乏统一的标准.

许多程序员缺乏手机应用开发经验.

更严重的是, 通过手机应用, 黑客可以得到手机用户的隐私数据, 如:日程安排, 联系人信息, 网页浏览历史记录, 个人资料, 社交数据, 短信或者手机用户所在的地理位置.

最为一个网络安全爱好者的我, 最近花了几个月的时间对50到60安卓应用进行安全分析, 结果发现这些应用存在许多安全漏洞.

下面我主要讲一讲, 怎样才能写出比较安全的安卓代码.

背景

从最基本的开始讲.

阅读本文前, 最好先看下 Ranjan.D article 写的一篇跟安卓连接有关的文章:(http://www.codeproject.com/Articles/818734/Article-Android-Connectivity).

下列代码用来打开一个 http 连接.

?

1

2

3

URL urlConnection =newURL("http://www.codeproject.com/");

HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

不要在 http连接中打开:登陆页面, 或是传递用户名, 密码, 银行卡之类的重要个人资料. 这些重要个人数据应该通过 HTTPS 传输. (具体参看HTTPS).

HTTPS是什么?

HTTPS 其实就是个安全版的 http.HTTPS能保证电子商务的交易安全. 如:网上银行.

像 IE 或者火狐浏览器, 如果出现下面的挂锁图标.

同时, 在浏览器的地址栏中以 https:// 开头, 这表示, 你的浏览器跟这个网站的数据往来都是安全的.

https 跟 http 的最大区别在于 https 多加了一个保障通讯安全的层.

像下列代码这样打开一个 https 连接, 可以保障这个连接的数据通讯安全.

?

1

2

3

4

5

URL urlConnection =newURL("https://www.codeproject.com/");

HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();

InputStream in =newBufferedInputStream(urlConnection.getInputStream());

HTTPS 通过 SSL/TLS 传递数据.

回到顶部

SSL/TLS:

SSL (Secure Sockets Layer) 是一种在客户端跟服务器端建立一个加密连接的安全标准. 一般用来加密网络服务器跟浏览器, 或者是邮件服务器跟邮件客户端(如: Outlook)之间传输的数据.

SSL 能保障敏感信息(如:银行卡号, 社保卡号, 登陆凭证等)的传输安全. 一般情况下, 数据在浏览器跟服务器之间的传输使用的是明文格式, 这种方式存在资料被窃取的风险. 如果黑客能拦截浏览器跟服务器之间的通讯数据, 就能看到通讯的内容.

回到顶部

SSL/HTTPS and X.509 证书概述

你要是对 SSL 或 X.509 证书一无所知, 那我大概解释下. 对于那些打算用自签名证书(self-signed certificate)的人来说, 需要了解自签名证书跟花钱购买机构颁发的证书有什么区别.

首先我们需要了解下 SSL 证书究竟是个什么东东? 其实它就包含俩部分: 1) 一个身份标识, 一个用来识别身份的东西, 有点类似警察叔叔通过护照或驾照查你的身份; 2) 一个公共密钥, 这个用来给数据加密, 而且只有证书的持有者才能解密. 简而言之, SSL 证书就俩个功能, 身份验证跟保障通讯过程中的数据安全.

另外还有一点很重要. 那就是一个证书可以给另外一个证书“签字”. 用 layman 的话说就是 Bob 用他自己的证书在别的证书上盖上 “同意” 两个红红的大字. 如果你信任 Bob (当然还有他的证书), 那么你也可以信任由他签发的证书. 在这个例子中, Bob 摇身一变, 成了证书颁发机构(Certificate Authority). 现在主流的浏览器都自带一大堆受信任证书颁发机构(trusted Certificate Authorities)(比如:Thawte,Verisign等).

最后我们讲一讲浏览器是怎么使用证书的. 笼统的讲, 当你打开下列连接的时候 “https://www.yoursite.com” :

服务器会给浏览器发一个证书.

浏览器会对比证书中的“common name”(有时也叫 “subject”) 跟服务器的域名是否一样. 例如, 一个从“www.yoursite.com” 网站发过来的证书就应该有一个内容是 “www.yoursite.com” 的 common name, 否则浏览器就会提示该证书有问题.

浏览器验证证书真伪, 有点像门卫通过证件上的全息图辨别你的证件是不是真的.  既然在现实生活中有人伪造别人的身份. 那么在网络世界也就有人造假, 比如用你的域名“www.yoursite.com” 来伪造一个安全证书.  浏览器在验证的时候, 会检查这个证书是否是它信任机构颁发的, 如果不是, 那么浏览器就会提示这个证书可能有问题.当然, 用户可以选择无视警告, 继续使用.

一旦证书通过验证 (或是用户无视警告, 继续使用有问题的证书), 浏览器就开始利用证书中的公开密钥加密数据并传给服务器.

回到顶部

回到顶部

TLS (SSL)中的加密

一旦服务器发过来的证书通过验证, 浏览器就会利用证书中包含的公共密钥加密某个指定的共享密钥, 然后发给服务器. 这个加密过的共享密钥只能用服务器的私有密钥才能解密(非对称加密), 别人无法解密出其中的内容. 服务器把解密出来的共享密钥保存起来, 供本次连接会话专用. 从现在开始, 服务器跟浏览器之间的所有通讯信息都用这个共享密钥加密解密(对称加密).

理论部分就这么多, 下面我们来看几个例子.

在浏览器中打开网站 mail.live.com , 地址栏中会出现一个绿色图标, http 也会变成 https.

单击这个绿色图标, 然后点证书信息连接, 就能看到下列内容.

这是个 SSL 证书, 该证书是 Verisign 给 mail.live.cm 颁发的.

Verisign 是一个证书颁发机构, 它提示你的浏览器正在连接的网站是: mail.live.com, 需要跟这个网站的服务器建立一条安全连接进行通讯, 避免他人拦截或篡改浏览器跟服务器之间传递的数据.

回到顶部

MITM 攻击

MITM 攻击(MITMA)是指: 黑客拦截篡改网络中的通讯数据

被动 MITMA 是指黑客只能窃取通讯数据, 而在主动 MITMA 中, 黑客除了窃取数据, 还能篡改通讯数据. 黑客利用 MITMA 方式攻击手机要比攻击台式电脑容易的多. 这主要是因为使用手机的环境在不固定, 有些地方用手机连接上网并不安全, 尤其是那些对公众免费开放的无线网络热点.

证书颁发机构(CA)

·Symantec(which boughtVeriSign's SSL interests and owns Thawte and Geotrust) 38.1% 市场份额

·Comodo SSL29.1%

·Go Daddy13.4%

·GlobalSign10%

Jelly bean 版本的安卓系统中, 你可以在下列路径中找到证书颁发机构:

设置 -> 安全 -> 受信任的凭证.

Https 连接

?

1

2

3

URL url =newURL("https://www.example.com/");

HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();

InputStream in = urlConnection.getInputStream();

如果你连接的服务器(www.example.com)传过来的证书是由机构颁发的, 这段代码就能正常运行.

但是如果你连的服务器用的是自己颁发的证书(self-singed certificate), 那就会出现错误.

回到顶部

什么是自签名证书( self-signed certicates)

自签名证书就是没有通过受信任的证书颁发机构, 自己给自己颁发的证书.

SSL 证书大致分三类:

由安卓认可的证书颁发机构(如: VeriSign), 或这些机构的下属机构颁发的证书.

没有得到安卓认可的证书颁发机构颁发的证书.

自己颁发的证书, 分临时性的(在开发阶段使用)或在发布的产品中永久性使用的两种.

只有第一种, 也就是那些被安卓系统认可的机构颁发的证书, 在使用过程中不会出现安全提示.

为什么有人喜欢用自签名证书

免费. 购买受信任机构颁发的证书每年要交 100 到 500 美元不等的费用. 自签名证书不花一分钱.

自签名证书在手机应用中的普及率较高 (跟用电脑浏览网页不同, 手机的应用一般就固定连一台服务器.).

在开发阶段写的代码,  测试跟发布的时候也可以用.

最近一项调查表明, 810万个证书中, 只有 320万个是由受信任机构颁发的. 剩余490万证书中, 自签名的占48%, 未知机构颁发的占33%, 而不被信任的机构颁发的证书占19%.

无独有偶, 我的分析结果也表明, 起码有 60% 安卓应用使用自签证书.

个人以为, 在手机应用中使用自签名证书没什么不好, 既不需要花钱, 也不需要修改代码.(注:如果你用的是机构颁发的证书, 在产品发布阶段, 需要修改代码).

但是下面的戏法的一般性的https代码

?

1

2

3

4

URL url =newURL("https://www.example.com/");

HttpsURLConnection urlConnection = (HttpsURLConnection)

url.openConnection();

InputStream in = urlConnection.getInputStream();

如果你使用上述的代代码去验证你的自己签署的证书,由于在Android操作系统中自己签署的不能通过验证的,所以安卓应用软件将会抛出错误。因此你需要书写你自己的代码来检查你的自己签署的证书。

但是在这个领域中,安卓开发者犯了一个很大的错误,自己签署的证书在web开发中不是常见的,同时大多数安卓开发者来自于web开发者,所以开发者缺失在密码学的概念的知识。

在我分析中,我发现开发者仅仅是简单的复制、粘贴Stack Overflow和其他博客中允许你的应用默认信任所以证书的答案。即使大多说的答案表述仅仅在测试模式下可以使用,但是开发者简单地复制代码,将会导致应用软件在遭到中间件攻击和session黑客攻击是,表现的非常的脆弱!

例子:

http://stackoverflow.com/questions/2703161/how-to-ignore-ssl-certificate-errors-in-apache-httpclient-4-0

http://stackoverflow.com/questions/2012497/accepting-a-certificate-for-https-on-android?lq=1

http://www.caphal.com/android/using-self-signed-certificates-in-android/#toc_3

http://stackoverflow.com/questions/2642777/trusting-all-certificates-using-httpclient-over-https

回到顶部

回到顶部

在使用自己签署的证书时一般性的错误

信任所以的证书

TrustManager的主要责任是去决定提出的认证证书应该是可信任的。如果证书是不可信任的,那么连接将会被终止。去认证远程的安全套接字识别,你需要用一个或者多个TrustManager(s)初始化SSLContext对象。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

importorg.apache.http.conn.ssl.SSLSocketFactory;

publicclassMySSLSocketFactoryextendsSSLSocketFactory {

SSLContext sslContext = SSLContext.getInstance("TLS");

publicMySSLSocketFactory(KeyStore truststore)throwsNoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {

super(truststore);

TrustManager tm =newX509TrustManager() {

publicvoidcheckClientTrusted(X509Certificate[] chain, String authType)throwsCertificateException {

}

publicvoidcheckServerTrusted(X509Certificate[] chain, String authType)throwsCertificateException {

}

publicX509Certificate[] getAcceptedIssuers() {

returnnull;

}

};

sslContext.init(null,newTrustManager[] { tm },null);

}

@Override

publicSocket createSocket(Socket socket, String host,intport,booleanautoClose)throwsIOException, UnknownHostException {

returnsslContext.getSocketFactory().createSocket(socket, host, port, autoClose);

}

@Override

publicSocket createSocket()throwsIOException {

returnsslContext.getSocketFactory().createSocket();

}

}

我发现,80到100个应用软件中,在20到25个应用中实现了上述的代码。

在上述的TrustManager接口中,可以实现信任所以的证书,不论是谁签署的或者即使他们发布的任何主题。这个接口将会允许接受ANY证书。接受任何的证书将会危害数据的完整性、安全性等等。

在上述的例子中,检查客户端可信任性,获得接受事件,检查服务器端可信任性是三点重要的功能。每一位开发者都应该留意这三点功能的实现上。但是却很少有开发者从不同的网站中搜索、负责上述的功能。

允许所有的主机名。

忘记检查证书是否在这个地址发布是有可能的。当证书接受了example.com的服务器,那么另外的一个域名也将被接受。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

DefaultHttpClient client =newDefaultHttpClient();

SchemeRegistry registry =newSchemeRegistry();

SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();

socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);

registry.register(newScheme("https", socketFactory,443));

SingleClientConnManager mgr =newSingleClientConnManager(client.getParams(), registry);

DefaultHttpClient httpClient =newDefaultHttpClient(mgr, client.getParams());

// Set verifier

HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

// Example send http request

finalString url = "https://www.paypal.com”

HttpPost httpPost =newHttpPost(url);

HttpResponse response = httpClient.execute(httpPost);

HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

?

1HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

上述的代码中,即使是错误的实现,也将会接受对任何域名的任何CA证书声明。

Mixed-Mode/No SSL.

应用软件开发者在相同的应用中使用最大安全、不安全的连接,或者不使用SSL将是免费的。这不是直接的SSL声明,但是和提到的没有向外的签署个有关,同时对于一般软件的使用者,检查是否使用一个安全的连接是不可能的。这将会为例如SSL剥离,或者像FireSheep这样的攻击开后门。

SSL剥离是另外的一种可以使MITMA登陆并抵制SSL连接方式。利用使用最大HTTP和HTTPS应用。SSL剥离依赖大量建立在点击链接、或者来自于没有SSL重定向保护的网站SSL连接。在SSL剥离中,Mallory用HTTPS://取代了没有保护的网站中http:// 链接中。因此,除非使用者注意到了链接被篡改了,Mallory可以完全地规避SSL保护。这样的攻击主要与浏览器应用、或者原生使用安卓WebView应用有关。

更多关于SSL剥离的信息:

http://security.stackexchange.com/questions/41988/how-does-sslstrip-work

http://www.thoughtcrime.org/software/sslstrip/

回到顶部

证书锁定

直接在代码中固定写死使用某个服务器的证书. 然后在应用中使用自己定义的信任存储(trust store)代替手机系统自带的那个, 去连接指定的服务器.

这样做的好处是, 我们既能使用自签名证书, 又不需要额外安装其他证书.

优势

安全性提升- 采用这种方式, 应用不再依赖系统自带的信任存储(trust store). 使得破解这种应用变得复杂: 首先你要反编译, 修改完后, 还要重新编译.  关键是你不可能使用应用作者原先用的那个 keystore 文件重新颁发证书.

成本降低- 证书锁定方式让我们可以在自己的服务器上使用免费的自签名证书,  调用自己写的 API. 虽说复杂了点, 可是像这种既不花钱, 还能提高应用安全的好事上哪找去?

缺点

适应性较差- 一旦 SSL 证书出现变动, 应用也要跟着升级. 再发布到 Google Play. 然后祈祷用户能都升级到最新版本.

安卓的 SSLContext 自带的TrustManager无法让本文示例中提到的自签名证书通过验证. 解决的办法是自己定义一个 TrustManager 类. 然后用这个类去验证自签名证书.

先把证书加载到 KeyStore, 然后用 KeyStore 生成一个TrustManager 数组, 最后再用这个 TrustManager 数组创建SSLContext.

本文的应用把服务器的证书直接存进应用的资源.(毕竟这个文件是所有用户都共用的, 而且也不会经常改动), 当然你可以把它存到别的地方.

回到顶部

实现的步骤

回到顶部

第1步: 创建自签名证书和.bks 文件

1)

创建 BKS 或者 keystore, 需要用到下面这个文件,bcprov-jdk15on-146.jar, 版本很多, 我用的是这个:http://www.bouncycastle.org/download/bcprov-jdk15on-146.jar, 下载后, 把文件存到 C:\codeproject.

然后用 Keytool 生成 keystore 文件.(keytool 是JavaSDK 自带的文件, 跟javac 放在同一个目录下)在命令提示符窗口中输入 keytool 就能看到这个工具的各种选项说明. 或者输入下列路径运行.

"C:\Program Files (x86)\Java\jre7\bin>keytool".

2)

下面是用 keytool 生成 keysotre 文件的命令.  要是这个文件已经存在, 这一步可以忽略.

keytool -genkey -alias codeproject -keystore C:\codeproject\codeprojectssl.keystore -validity 365

这行命令创建一个别名为 code project 的密钥(key), 生成的文件名是 codeprojectssl.keystore. 执行文件生成过程中会要求输入密钥(key)跟keystore的密码诸如此类的东东. 这里需要注意下, 当要求你录入 Common name 的时候, 要填你的主机名. 本文例子用的是: codeproject.com

3)

keytool -export -alias codeproject -keystore C:\codeproject\codeprojectssl.keystore -file C:\codeproject\codeprojectsslcert.cer

这行命令将密钥(key)从 .keystore 文件导入 .cer 文件.

4)

keytool -import -alias codeproject -file C:\codeproject\codeprojectsslcert.cer -keystore C:\codeproject\codeprojectssl.bks -storetype BKS -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath C:\codeproject\bcprov-jdk15on-146.jar

搞定! 现在, 全部 .bks 文件都生成了. 稍后将这些文件复制到安卓应用中. 连接那些使用自签名证书的服务器的时候会用到.

回到顶部

第2步

把 .keystore 文件复制到/androidappdir/res/raw/

回到顶部

第3步

创建一个新类: MyHttpClient,  继承 DefaultHttpClient 类. 这个新类在验证SSL 证书的时候, 会自动加载我们自己创建的 keystore 文件, 而不是安卓自带的那个. 只要证书跟服务器匹配上了就没问题. 代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

importjava.io.InputStream;

importjava.security.KeyStore;

importandroid.content.Context;

publicclassMyHttpClientextendsDefaultHttpClient {

privatestaticContext context;

publicstaticvoidsetContext(Context context) {

MyHttpClient.context = context;

}

publicMyHttpClient(HttpParams params) {

super(params);

}

publicMyHttpClient(ClientConnectionManager httpConnectionManager, HttpParams params) {

super(httpConnectionManager, params);

}

@Override

protectedClientConnectionManager createClientConnectionManager() {

SchemeRegistry registry =newSchemeRegistry();

registry.register(newScheme("http", PlainSocketFactory.getSocketFactory(),80));

// 用我们自己定义的 SSLSocketFactory 在 ConnectionManager 中注册一个 443 端口

registry.register(newScheme("https", newSslSocketFactory(),443));

returnnewSingleClientConnManager(getParams(), registry);

}

privateSSLSocketFactory newSslSocketFactory() {

try{

// Get an instance of the Bouncy Castle KeyStore format

KeyStore trusted = KeyStore.getInstance("BKS");

// 从资源文件中读取你自己创建的那个包含证书的 keystore 文件

InputStream in = MyHttpClient.context.getResources().openRawResource(R.raw.codeprojectssl);//这个参数改成你的 keystore 文件名

try{

// 用 keystore 的密码跟证书初始化 trusted

trusted.load(in,"这里是你的 keystore 密码".toCharArray());

}finally{

in.close();

}

// Pass the keystore to the SSLSocketFactory. The factory is responsible

// for the verification of the server certificate.

SSLSocketFactory sf =newSSLSocketFactory(trusted);

// Hostname verification from certificate

// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506

sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);// 这个参数可以根据需要调整, 如果对主机名的验证不需要那么严谨, 可以将这个严谨程度调低些.

returnsf;

}catch(Exception e) {

thrownewAssertionError(e);

}

}

}

MyHttpClient 类的调用代码如下:

?

1

2

3

4

5

6

// Instantiate the custom HttpClient

DefaultHttpClient client =newMyHttpClient(getApplicationContext());

HttpGet get =newHttpGet("https://www.google.com");

// 以 GET 方式读取服务器返回的数据

HttpResponse getResponse = client.execute(get);

HttpEntity responseEntity = getResponse.getEntity();

这是我在 CodeProject 上的发布的处女作.

祝大家开心编程, 安全第一

.

参考文献

http://www.thoughtcrime.org/blog/authenticity-is-broken-in-ssl-but-your-app-ha/

http://security.stackexchange.com/questions/29988/what-is-certificate-pinning

https://www.owasp.org/index.PHP/Certificate_and_Public_Key_Pinning

https://tools.ietf.org/html/draft-ietf-websec-key-pinning-20

https://media.blackhat.com/bh-us12/Turbo/Diquet/BH_US_12_Diqut_Osborne_Mobile_Certificate_Pinning_Slides.pdf

http://docs.Oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#HowSSLWorks

本文地址:http://www.oschina.net/translate/android-security-implementation-of-self-signed-ssl

原文地址:http://www.codeproject.com/Articles/826045/Android-security-Implementation-of-Self-signed-SSL

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 根证书含义 - 孤舟蓑笠翁,独钓寒江雪 - 博客频道 - CSDN.NET 本文想简单谈谈那个所谓的...
    拉肚阅读 2,378评论 0 1
  • 一、作用 不使用SSL/TLS的HTTP通信,就是不加密的通信。所有信息明文传播,带来了三大风险。 (1)窃听风险...
    XLsn0w阅读 10,496评论 2 44
  • 文/断断 1.推开门后,发现自己没了妈妈。 “妈,我放学回来啦,今天做的什么饭啊?” 坐在院子里的男人没看到人,就...
    爱读书的断断阅读 230评论 0 2
  • 随着时间的推移,我们在子宫(妈妈的肚子)里养精蓄锐了十个月,今天,是小爷(老娘)我重生的日子:哈哈哈。 不...
    遇见_b723阅读 255评论 1 1