Https實現(xiàn)機制詳解

Https請求

一掉房、訪問HTTPS站點

兩種方法來模擬發(fā)送HTTP請求茧跋,訪問HTTP站點。一種方式是通過java.net自帶的HttpURLConnection卓囚,另一種方式是通過Apache的HttpClient瘾杭,這兩種方式各有各的優(yōu)勢。這里也使用這兩種方式來訪問HTTPS站點哪亿,從下面的代碼可以看到粥烁,和前面訪問HTTP站點幾乎完全一樣。

1.1使用HttpURLConnection

@Test

public void basicHttpsGet() throws

Exception {

String url =? "https://www.baidu.com";

URL obj = new

URL(url);

HttpsURLConnection

con = (HttpsURLConnection) obj.openConnection();

con.setRequestProperty("User-Agent",

"Mozilla/5.0 (Windows NT 6.1; WOW64) ...");

con.setRequestProperty("Accept-Language",

"en-US,en;q=0.5");

con.setRequestMethod("GET");

String

responseBody = readResponseBody(con.getInputStream());

System.out.println(responseBody);

}

1.2使用HttpClient

@Test

public void basicHttpsGet() throws

Exception {

String url =? "https://www.baidu.com";

HttpGet request =

new HttpGet(url);

request.setHeader("User-Agent",

"Mozilla/5.0 (Windows NT 6.1; WOW64) ...");

CloseableHttpClient

httpclient = HttpClients.createDefault();

CloseableHttpResponse

response = httpclient.execute(request);

String

responseBody = readResponseBody(response);

System.out.println(responseBody);

}

具體的代碼解釋參見第一篇博客蝇棉,這里不再贅述讨阻。一般情況下,訪問HTTPS站點就和訪問HTTP站點一樣簡單篡殷,無論是HttpURLConnection還是HttpClient变勇,都將底層的實現(xiàn)細節(jié)封裝了起來,給我們提供了一致的對外接口贴唇,所以我們不用關(guān)心HTTPS的實現(xiàn)原理搀绣。

二、Java里的證書

上面所介紹的是瀏覽器對證書進行驗證的過程戳气,瀏覽器保存了一個常用的CA證書列表链患,在驗證證書鏈的有效性時,直接使用保存的證書里的公鑰進行校驗瓶您,如果在證書列表中沒有找到或者找到了但是校驗不通過麻捻,那么瀏覽器會警告用戶纲仍,由用戶決定是否繼續(xù)。與此類似的贸毕,操作系統(tǒng)也一樣保存有一份可信的證書列表郑叠,譬如在Windows系統(tǒng)下,你可以運行certmgr.msc打開證書管理器查看明棍,這些證書實際上是存儲在Windows的注冊表中乡革,一般情況下位于:\SOFTWARE\Microsoft\SystemCertificates\路徑下。那么在Java程序中是如何驗證證書的呢摊腋?

和瀏覽器操作系統(tǒng)類似沸版,Java在JRE的安裝目錄下也保存了一份默認可信的證書列表,這個列表一般是保存在$JRE/lib/security/cacerts文件中兴蒸。要查看這個文件视粮,可以使用類似KeyStore Explorer這樣的軟件,當然也可以使用JRE自帶的keytool工具(后面再介紹)橙凳,cacerts文件的默認密碼為changeit(但是我保證蕾殴,大多數(shù)人都不會change it)。

我們知道岛啸,證書有很多種不同的存儲格式区宇,譬如CA在發(fā)布證書時,常常使用PEM格式值戳,這種格式的好處是純文本议谷,內(nèi)容是BASE64編碼的,證書中使用"-----BEGIN CERTIFICATE-----"和"-----END CERTIFICATE-----"來標識堕虹。另外還有比較常用的二進制DER格式卧晓,在Windows平臺上較常使用的PKCS#12格式等等。當然赴捞,不同格式的證書之間是可以相互轉(zhuǎn)換的逼裆,我們可以使用openssl這個命令行工具來轉(zhuǎn)換,參考SSL

Converter赦政,另外胜宇,想了解更多證書格式的,可以參考這里:Various

SSL/TLS Certificate File Types/Extensions恢着。

在Java平臺下桐愉,證書常常被存儲在KeyStore文件中,上面說的cacerts文件就是一個KeyStore文件掰派,KeyStore不僅可以存儲數(shù)字證書从诲,還可以存儲密鑰,存儲在KeyStore文件中的對象有三種類型:Certificate靡羡、PrivateKey和SecretKey系洛。Certificate就是證書俊性,PrivateKey是非對稱加密中的私鑰,SecretKey用于對稱加密描扯,是對稱加密中的密鑰定页。KeyStore文件根據(jù)用途,也有很多種不同的格式:JKS绽诚、JCEKS典徊、PKCS12、DKS等等憔购,PixelsTech上有一系列文章對KeyStore有深入的介紹宫峦,可以學習下:Different

types of keystore in Java岔帽。

到目前為止玫鸟,我們所說的KeyStore其實只是一種文件格式而已,實際上在Java的世界里KeyStore文件分成兩種:KeyStore和TrustStore犀勒,這是兩個比較容易混淆的概念屎飘,不過這兩個東西從文件格式來看其實是一樣的。KeyStore保存私鑰贾费,用來加解密或者為別人做簽名钦购;TrustStore保存一些可信任的證書,訪問HTTPS時對被訪問者進行認證褂萧,以確保它是可信任的押桃。所以準確來說,上面的cacerts文件應(yīng)該叫做TrustStore而不是KeyStore导犹,只是它的文件格式是KeyStore文件格式罷了唱凯。

除了KeyStore和TrustStore,Java里還有兩個類KeyManager和TrustManager與此息息相關(guān)谎痢。JSSE的參考手冊中有一張示意圖磕昼,說明了各個類之間的關(guān)系:


可以看出如果要進行SSL會話,必須得新建一個SSLSocket對象节猿,而SSLSocket對象是通過SSLSocketFactory來管理的票从,SSLSocketFactory對象則依賴于SSLContext,SSLContext對象又依賴于keyManager滨嘱、TrustManager和SecureRandom峰鄙。我們這里最關(guān)心的是TrustManager對象,另外兩個暫且忽略太雨,因為正是TrustManager負責證書的校驗先馆,對網(wǎng)站進行認證,要想在訪問HTTPS時通過認證躺彬,不報sun.security.validator.ValidatorException異常煤墙,必須從這里開刀梅惯。

三、Java客戶端訪問https時證書驗證處理規(guī)則

客戶端的TrustStore文件中保存著被客戶端所信任的服務(wù)器的證書信息仿野∠臣酰客戶端在進行SSL連接時,JSSE將根據(jù)這個文件中的證書決定是否信任服務(wù)器端的證書脚作。在SunJSSE中葫哗,有一個信任管理器類負責決定是否信任遠端的證書,這個類有如下的處理規(guī)則:

1)

若系統(tǒng)屬性javax.net.sll.trustStore指定了TrustStore文件球涛,那么信任管理器就去jre安裝路徑下的lib/security/目錄中尋找并使用這個文件來檢查證書劣针。

2)

若該系統(tǒng)屬性沒有指定TrustStore文件,它就會去jre安裝路徑下尋找默認的TrustStore文件亿扁,這個文件的相對路徑為:lib/security/jssecacerts捺典。

3)

若jssecacerts不存在,但是cacerts存在(它隨J2SDK一起發(fā)行从祝,含有數(shù)量有限的可信任的基本證書)襟己,那么這個默認的TrustStore文件就是lib/security/cacerts

四牍陌、自定義TrustManager繞過證書檢查進行https訪問

我們知道了TrustManager是專門負責校驗證書的擎浴,那么最容易想到的方法應(yīng)該就是改寫TrustManager類,讓它不要對證書做校驗毒涧,這種方法雖然粗暴贮预,但是卻相當有效,而且Java中的TrustManager也確實可以被重寫契讲,下面是示例代碼:

@Test

public void

basicHttpsGetIgnoreCertificateValidation() throws Exception {

String url =? "https://kyfw.12306.cn/otn/";

// Create a trust

manager that does not validate certificate chains

TrustManager[]

trustAllCerts = new TrustManager[] {

new

X509TrustManager() {

public

X509Certificate[] getAcceptedIssuers() {

return

null;

}

public

void checkClientTrusted(X509Certificate[] certs, String authType) {

//

don't check

}

public

void checkServerTrusted(X509Certificate[] certs, String authType) {

//

don't check

}

}

};

SSLContext ctx =

SSLContext.getInstance("TLS");

ctx.init(null,

trustAllCerts, null);

LayeredConnectionSocketFactory

sslSocketFactory = new SSLConnectionSocketFactory(ctx);

CloseableHttpClient

httpclient = HttpClients.custom()

.setSSLSocketFactory(sslSocketFactory)

.build();

HttpGet request =

new HttpGet(url);

request.setHeader("User-Agent",

"Mozilla/5.0 (Windows NT 6.1; WOW64) ...");

CloseableHttpResponse

response = httpclient.execute(request);

String responseBody

= readResponseBody(response);

System.out.println(responseBody);

}

我們新建了一個匿名類仿吞,繼承自X509TrustManager接口,這個接口提供了三個方法用于驗證證書的有效性:getAcceptedIssuers怀泊、checkClientTrusted茫藏、checkServerTrusted,我們在驗證的函數(shù)中直接返回霹琼,不做任何校驗务傲,這樣在訪問HTTPS站點時,就算是證書不可信枣申,也不會拋出異常售葡,可以繼續(xù)執(zhí)行下去。

這種方法雖然簡單忠藤,但是卻有一個最嚴重的問題挟伙,就是不安全。因為不對證書做任何合法性校驗模孩,而且這種處理是全局性的尖阔,不管青紅皂白贮缅,所有的證書都不會做驗證,所以就算遇到不信任的證書介却,代碼依然會繼續(xù)與之通信谴供,至于通信的數(shù)據(jù)安全不安全就不能保證了。所以如果你只是想在測試環(huán)境做個實驗齿坷,那沒問題桂肌,但是如果你要將代碼發(fā)布到生產(chǎn)環(huán)境,請慎重永淌。

五崎场、使用證書進行https訪問

對于有些證書,我們基本上確定是可以信任的遂蛀,但是這些證書又不在Java的cacerts文件中谭跨,譬如12306網(wǎng)站,或者使用了Let's Encrypt證書的一些網(wǎng)站答恶,對于這些網(wǎng)站饺蚊,我們可以將其添加到信任列表中萍诱,而不是使用上面的方法統(tǒng)統(tǒng)都相信悬嗓,這樣程序的安全性仍然可以得到保障。

5.1使用keytool導(dǎo)入證書

簡單的做法是將這些網(wǎng)站的證書導(dǎo)入到cacerts文件中裕坊,這樣Java程序在校驗證書的時候就可以從cacerts文件中找到并成功校驗這個證書了包竹。上面我們介紹過JRE自帶的keytool這個工具,這個工具小巧而強悍籍凝,擁有很多功能周瞎。首先我們可以使用它查看KeyStore文件,使用下面的命令可以列出KeyStore文件中的所有內(nèi)容(包括證書饵蒂、私鑰等):

$ keytool -list -keystore cacerts

然后通過下面的命令声诸,將證書導(dǎo)入到cacerts文件中:

$ keytool -import -alias 12306 -keystore cacerts

-file 12306.cer

要想將網(wǎng)站的證書導(dǎo)入cacerts文件中,首先要獲取網(wǎng)站的證書退盯,譬如上面命令中的12306.cer文件彼乌,它是使用瀏覽器的證書導(dǎo)出向?qū)П4娴摹H缦聢D所示:


關(guān)于keytool的更多用法渊迁,可以參考keytool的官網(wǎng)手冊慰照,SSLShopper上也有一篇文章列出了常用的keytool命令

5.2使用KeyStore動態(tài)加載證書

使用keytool導(dǎo)入證書琉朽,這種方法不僅簡單毒租,而且保證了代碼的安全性,最關(guān)鍵的是代碼不用做任何修改箱叁。所以我比較推薦這種方法墅垮。但是這種方法有一個致命的缺陷惕医,那就是你需要修改JRE目錄下的文件,如果你的程序只是在自己的電腦上運行算色,那倒沒什么曹锨,可如果你的程序要部署在其他人的電腦上或者公司的服務(wù)器上,而你沒有權(quán)限修改JRE目錄下的文件剃允,這該怎么辦沛简?如果你的程序是一個分布式的程序要部署在成百上千臺機器上,難道還得修改每臺機器的JRE文件嗎斥废?好在我們還有另一種通過編程的手段來實現(xiàn)的思路椒楣,在代碼中動態(tài)的加載KeyStore文件來完成證書的校驗,抱著知其然知其所以然的態(tài)度牡肉,我們在最后也實踐下這種方法捧灰。通過編寫代碼可以更深刻的了解KeyStore、TrustManagerFactory统锤、SSLContext以及SSLSocketFactory這幾個類之間的關(guān)系毛俏。

@Test

public void

basicHttpsGetUsingSslSocketFactory() throws Exception {

String

keyStoreFile = "D:\\code\\ttt.ks";

String password =

"poiuyt";

KeyStore ks =

KeyStore.getInstance(KeyStore.getDefaultType());

FileInputStream

in = new FileInputStream(keyStoreFile);

ks.load(in,

password.toCharArray());

System.out.println(KeyStore.getDefaultType().toString());

System.out.println(TrustManagerFactory.getDefaultAlgorithm().toString());

TrustManagerFactory

tmf =

TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

tmf.init(ks);

SSLContext ctx =

SSLContext.getInstance("TLS");

ctx.init(null,

tmf.getTrustManagers(), null);

LayeredConnectionSocketFactory

sslSocketFactory = new SSLConnectionSocketFactory(ctx);

String url =? "https://ttt.aneasystone.com";

/**

* Return

the page with content:

*? 401

Authorization Required

*/

CloseableHttpClient

httpclient = HttpClients.custom()

.setSSLSocketFactory(sslSocketFactory)

.build();

HttpGet request =

new HttpGet(url);

request.setHeader("User-Agent",

"Mozilla/5.0 (Windows NT 6.1; WOW64) ...");

CloseableHttpResponse

response = httpclient.execute(request);

String

responseBody = readResponseBody(response);

System.out.println(responseBody);

}

上面的代碼使用了HttpClient,如果是使用HttpsURLConnection只需要改動下面兩行即可:

HttpsURLConnection con =

(HttpsURLConnection) obj.openConnection();

con.setSSLSocketFactory(ctx.getSocketFactory());

最后的最后饲窿,我們還可以通過下面的屬性來指定trustStore煌寇,這樣也不需要編寫像上面那樣大量繁瑣的代碼,另外逾雄,參考我前面的博客阀溶,這些屬性還可以通過JVM的參數(shù)來設(shè)置。

System.setProperty("javax.net.ssl.trustStore",

"D:\\code\\ttt.ks");

System.setProperty("javax.net.ssl.trustStorePassword",

"poiuyt");

若沒有通過設(shè)置JVM參數(shù)來指定要加載的證書庫文件鸦泳,則使用jdk默認的jre\\lib\\cacerts證書庫文件來驗證請求站點的證書是否合法银锻。

5.3 Java請求https服務(wù)(真?zhèn)尾樵儗嵗?/p>

publicstaticJSONObject SetSystsHttpsSSLPost(Stringurl, Stringargs, Stringappkey, Stringiv)throwsException {

JSONObjectresult=newJSONObject();

Stringargs= SSLPostTest.encryption(querydata);

Stringiv=newBase64().encodeToString(IV.getBytes());

StringkeyStoreFile="C:\\Users\\Gufung\\nubiacsm.keystore";

/***方式一:使用keystore加載證書庫文件****/

/*String keyStoreFile = System.getProperty("java.home")+ "\\lib\\security\\cacerts";

Stringpassword = "changeit";

KeyStoreks= KeyStore.getInstance(KeyStore.getDefaultType());

FileInputStreamin = new FileInputStream(keyStoreFile);

ks.load(in,password.toCharArray());

TrustManagerFactorytmf= TrustManagerFactory

.getInstance(TrustManagerFactory.getDefaultAlgorithm());

tmf.init(ks);

SSLContextctx= SSLContext.getInstance("TLS");

ctx.init(null,tmf.getTrustManagers(), null);

URL myURL = new URL(url);

HttpsURLConnectioncon= (HttpsURLConnection) myURL.openConnection();

con.setSSLSocketFactory(ctx.getSocketFactory());*/

/***方式一:使用keystore加載證書庫文件****/

/***方式二:通過設(shè)置JVM參數(shù)來指定要加載的證書庫文件****/

System.setProperty("javax.net.ssl.trustStore",keyStoreFile);

System.setProperty("javax.net.ssl.trustStorePassword","changeit");

URLmyURL=newURL(url);

HttpsURLConnectioncon= (HttpsURLConnection)myURL.openConnection();

/***方式二:通過設(shè)置JVM參數(shù)來指定要加載的證書庫文件****/

con.setDoOutput(true);

con.setDoInput(true);

con.setRequestMethod("POST");

con.setUseCaches(false);

con.connect();

DataOutputStreamout=newDataOutputStream(con.getOutputStream());

Stringcontent="args="+ URLEncoder.encode(args,"UTF-8");

content+="&appkey="+ URLEncoder.encode(appkey,"UTF-8");

content+="&iv="+ URLEncoder.encode(iv,"UTF-8");

out.writeBytes(content);

out.flush();

out.close();

intresultCode=con.getResponseCode();

System.out.println(resultCode);

if(HttpURLConnection.HTTP_OK==resultCode) {

StringreadLine=newString();

BufferedReaderresponseReader=newBufferedReader(

newInputStreamReader(con.getInputStream(),"UTF-8"));

while((readLine=responseReader.readLine()) !=null) {

result=newJSONObject(readLine);

}

responseReader.close();

}

con.disconnect();

System.out.println(result.toString());

returnresult;

}

參考

SSL如何工作

SSL/TLS協(xié)議簡介與實例分析

SSL/TLS原理詳解

TLS握手優(yōu)化詳解

三種解密HTTPS流量的方法介紹

圖解SSL/TLS協(xié)議

SSL/TLS協(xié)議運行機制的概述

HTTPS從原理到實戰(zhàn)

HTTPS工作原理和TCP握手機制

掃盲HTTPS和SSL/TLS協(xié)議

HTTPS那些事(一)HTTPS原理

理解HTTPS協(xié)議

SSL/TLS協(xié)議安全系列:SSL/TLS概述

Different types of keystore in Java -- Overview

Different types of keystore in Java -- JKS

Java中用HttpsURLConnection訪問Https鏈接的問題

Where is the certificate folder in Windows 7?

數(shù)字證書及CA的掃盲介紹

數(shù)字證書原理

數(shù)字證書

Java使用自簽證書訪問https站點

12306的證書問題

數(shù)字簽名是什么?

在線買火車票為什么要安裝根證書做鹰?

Java加密技術(shù)(八)——數(shù)字證書

Java加密技術(shù)(九)——初探SSL

常見的數(shù)字證書格式

keyStore vs trustStore

Difference between trustStore and keyStore in Java - SSL

Java Secure Socket Extension (JSSE) Reference Guide

Disable Certificate Validation in Java SSL Connections

javax.net.ssl.SSLHandshakeException:

sun.security.validator.ValidatorException: PKIX path building failed

How to solve javax.net.ssl.SSLHandshakeException?

SSL Converter

The Most Common Java Keytool Keystore Commands

keytool - Key and Certificate Management Tool

原文鏈接:http://www.aneasystone.com/archives/2016/04/java-and-https.html

參考資料:Java安全通信:HTTPS與SSL

http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html

http://www.aneasystone.com/archives/2016/04/java-and-https.html

http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html

https://my.oschina.net/zhlmmc/blog/42111

https://www.sslshopper.com/article-most-common-java-keytool-keystore-commands.html

http://blog.csdn.net/csdnbenbenchong/article/details/7388260

http://blog.csdn.net/u011042133/article/details/51671801

http://snowolf.iteye.com/blog/397693

http://www.iamlbk.com/blog/20160731/tomcat-https/?utm_source=tuicool&utm_medium=referral

http://blog.chenxiaosheng.com/posts/2013-12-26/java-use-self_signed_certificate.html

http://www.zhixing123.cn/jsp/49937.html

http://www.cnblogs.com/JeffreySun/archive/2010/06/24/1627247.html

https://publib.boulder.ibm.com/tividd/td/TRM/SC23-4822-00/zh_CN/HTML/user276.htm

http://op.baidu.com/2015/04/https-s01a01/

http://lukejin.iteye.com/blog/605634

http://ln-ydc.iteye.com/blog/1335213

https://blog.cnbluebox.com/blog/2014/03/24/shu-zi-zheng-shu/

http://blog.csdn.net/sfdev/article/details/2957240

https://segmentfault.com/a/1190000002554673#articleHeader0

http://www.cnblogs.com/devinzhang/archive/2012/02/28/2371631.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末击纬,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子钾麸,更是在濱河造成了極大的恐慌更振,老刑警劉巖淹父,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渗勘,死亡現(xiàn)場離奇詭異,居然都是意外死亡孝扛,警方通過查閱死者的電腦和手機芋肠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門乎芳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事奈惑】跃唬” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵肴甸,是天一觀的道長寂殉。 經(jīng)常有香客問我,道長原在,這世上最難降的妖魔是什么友扰? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮庶柿,結(jié)果婚禮上村怪,老公的妹妹穿的比我還像新娘。我一直安慰自己浮庐,他們只是感情好甚负,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著审残,像睡著了一般梭域。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上搅轿,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天病涨,我揣著相機與錄音,去河邊找鬼介时。 笑死没宾,一個胖子當著我的面吹牛凌彬,可吹牛的內(nèi)容都是我干的沸柔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼铲敛,長吁一口氣:“原來是場噩夢啊……” “哼褐澎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起伐蒋,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤工三,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后先鱼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俭正,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年焙畔,在試婚紗的時候發(fā)現(xiàn)自己被綠了掸读。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖儿惫,靈堂內(nèi)的尸體忽然破棺而出澡罚,到底是詐尸還是另有隱情,我是刑警寧澤肾请,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布留搔,位于F島的核電站,受9級特大地震影響铛铁,放射性物質(zhì)發(fā)生泄漏隔显。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一饵逐、第九天 我趴在偏房一處隱蔽的房頂上張望荣月。 院中可真熱鬧,春花似錦梳毙、人聲如沸哺窄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萌业。三九已至,卻和暖如春奸柬,著一層夾襖步出監(jiān)牢的瞬間生年,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工廓奕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留抱婉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓桌粉,卻偏偏與公主長得像蒸绩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子铃肯,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容