iOS移動端的安全架構(gòu)設(shè)計

伴隨著移動產(chǎn)品廣泛應(yīng)用與快速發(fā)展次慢,移動客戶端的安全問題越來越受重視。我這里主要談?wù)刬OS移動端的安全架構(gòu)設(shè)計今布。

一经备、前言

移動端的安全一般可以理解為兩個方面:本地安全通信安全部默。

1侵蒙、本地安全:
本地安全主要指客戶端本地環(huán)境與數(shù)據(jù)的安全,以及代碼被破解獲得所導(dǎo)致的安全問題傅蹂,如:明文存儲問題纷闺,惡意二次打包問題,越權(quán)操作問題等份蝴。

2犁功、通信安全:
通信安全主要指客戶端與服務(wù)端進(jìn)行數(shù)據(jù)交互時被攔截破獲導(dǎo)致的安全問題。如采取明文進(jìn)行密碼或者數(shù)據(jù)傳輸?shù)葐栴}婚夫。

關(guān)于一些移動端安全的認(rèn)識還有web安全等等浸卦,請參考文章:移動端本地安全解決方案

二、安全加密基礎(chǔ)的快速認(rèn)識

加密分為對稱加密非對稱加密案糙。
1限嫌、對稱加密
加密使用的密鑰和解密使用的密鑰是相同的靴庆。也就是說,加密和解密都是使用的同一個密鑰怒医,也就是共享密鑰密碼炉抒。(ps:這個很好理解吧) 常用的對稱加密算法:

名稱 英文
DES Data Encryption Standard
3DES Triple DES
AES dvanced Encryption Standard

2、非對稱加密
加密使用的密鑰和解密使用的密鑰是不相同的稚叹。 (ps:這個不好理解焰薄?不好理解請好好看看非對稱加密算法原理) 簡單來說就是有一套算法可以實(shí)現(xiàn)你用公鑰加密的信息,對方用保留的私鑰進(jìn)行解密扒袖。

常說的公鑰密碼就是指非對稱密碼塞茅,公鑰加密就是一種非對稱加密。

最常用的是RSA算法僚稿。RSA的演算方法是:
1)用戶選擇2個夠大的保密質(zhì)數(shù)q凡桥、p(一般為100位以上十進(jìn)數(shù))   2)令n=pq,n是公開的蚀同,從n分解除qp是極其困難的缅刽。   n的歐拉函數(shù):Φ(n)=(p-1)(q-1)   Φ(n)小于等于n,并與n互質(zhì)   3)選擇一個相對大的整數(shù)e作為加密指數(shù)蠢络,使e與Φ(n)互質(zhì)衰猛,   4)解同等方程:   ed=1modΦ(n)   求出解密指數(shù)d   5)設(shè)M、C分別為要加密的明文和被加密的密文(M刹孔、C小于n)   則:加密運(yùn)算為:C=Memod n   解密運(yùn)算為:M=Cdmod n   6)每個用戶都有一組密鑰(e啡省、d、n)   (e髓霞,n)為PK'可以公開在手冊上的公鑰卦睹,e為加密指數(shù),   (d方库,n)為SK’(或PV)是用戶保密的私鑰   將p.q銷毀   7)要求明文X   舉例:   1) 選兩個質(zhì)數(shù): p=47 q=71   2)計算: n=pq=3337 Φ(n)=(47-1)(71-1)=3220   3) e必須與Φ(n)互質(zhì)结序,選e=79   4) 計算:ed=1modΦ(n)=1mod(3220)   d=1019   將e、n公布纵潦,d保密徐鹤,p.q消毀   如有一明文 M=6882326879666683要加密,則先將M分割成多塊:   m1=688,m2=232,m3=687,m4=966,m5=668,m6=3   將第1塊M1加密后得密文C1:   C1=m1e(mod3337)=68879(mod3337)=1570   依次對各區(qū)塊加密后得密文C:   C=15702756271422762423158   對C1解密得m1   M1=C1d(mod3337)=15701019(mod3337)=688   依次解密得原文M邀层。
  
  那么問題來了返敬,我們遇到的PBE(Password Based Encryption,基于口令加密)加密啊都是什么呢寥院。詳情可以去了解下劲赠,這里強(qiáng)調(diào)一點(diǎn),PBE算法的應(yīng)用還是在對稱加密范疇。至于哪種加密方案適合自己的場景凛澎,這也是我們今天iOS移動端安全架構(gòu)設(shè)計的時候需要考慮的泌绣。
知識點(diǎn)延伸:
1、對稱密碼與公鑰密碼對比预厌,消息認(rèn)證碼與數(shù)字簽名的對比

對象屬性 對稱密碼 公鑰密碼(非對稱密碼)
發(fā)送者 用共享密鑰加密-雙方持有 用公鑰加密
接收者 用共享密鑰加密-雙方持有 用私鑰解密
密鑰配送問題 存在 不存在,但公鑰需要另外認(rèn)證
機(jī)密性 ? ?
對象屬性 消息認(rèn)證碼 數(shù)字簽名
發(fā)送者 用共享密鑰計算MAC值 用私鑰生成簽名
接收者 用共享密鑰計算MAC值 用公鑰驗(yàn)證簽名
密鑰配送問題 存在 不存在元媚,但公鑰需要另外認(rèn)證
完整性 ? ?
認(rèn)證 ?(僅限通信對象雙方) ? (可適用于任何第三方)
防止否認(rèn) ? ?

2轧叽、公鑰密碼與數(shù)字簽名的密鑰適用方式

對象屬性 公鑰 私鑰
公鑰密碼 發(fā)送者加密時使用 接收者解密時使用
數(shù)字簽名 驗(yàn)證者驗(yàn)證簽名時使用 簽名者生成簽名時使用
誰持有密鑰? 只要需要刊棕,可任何人都可以持有 個人持有

數(shù)字簽名就是利用非對稱加密的原理炭晒,只是用法下不一樣,反著的甥角。另外為公鑰加上數(shù)字簽名就是證書网严。

二、iOS移動端設(shè)計的安全考量

移動客戶端設(shè)計時嗤无,除了上述寬泛的本地安全和通信安全需要考量震束,具體到模塊與業(yè)務(wù)需要開發(fā)者作哪些思考呢?本地密碼存儲安全怎么保證当犯,客戶端web頁面怎么防止被劫持垢村,客戶端在設(shè)計交易時如何考慮安全性等等問題。如今蘋果開始強(qiáng)制接口使用HTTPS協(xié)議也是為為了增強(qiáng)安全性嚎卫,但開發(fā)者在客戶端設(shè)計之初也需要考慮這些安全問題嘉栓,建立一些基礎(chǔ)的安全模塊。
(ps:至于涉及到金融類App考慮的安全問題就更多拓诸,如交易安全侵佃,私鑰如何存儲等)

1、安全需求分析

加密原則:

  1. App代碼安全奠支,包括代碼混淆馋辈,加密或者app加殼。
  2. App數(shù)據(jù)存儲安全胚宦,主要指在磁盤做數(shù)據(jù)持久化的時候所做的加密首有。
  3. App網(wǎng)絡(luò)傳輸安全,指對數(shù)據(jù)從客戶端傳輸?shù)絊erver中間過程的加密枢劝,防 止網(wǎng)絡(luò)世界當(dāng)中其他節(jié)點(diǎn)對數(shù)據(jù)的竊聽井联。

本地存儲安全:
1)、明文存儲您旁,過度依賴系統(tǒng)安全性(iOS:Keychain/UserDefault)
2)烙常、惡意二次打包
3)、容易被逆向,被調(diào)試
4)蚕脏、敏感信息寫入代碼

網(wǎng)絡(luò)通信安全:
1)侦副、HTTP傳輸被劫持(蘋果開始強(qiáng)制接口使用HTTPS協(xié)議)
2)、明文傳輸數(shù)據(jù)

另外由本地安全延伸出來:
1)驼鞭、本地自動登錄如何存儲私鑰秦驯,如何解決又方便用戶,又保證安全挣棕。
2)译隘、金融類、支付類App如何解決支付安全問題洛心,二維碼支付的安全問題等等固耘。

2、需求技術(shù)準(zhǔn)備

1)词身、針對本地明文存儲的安全漏洞厅目,自然是要本地進(jìn)行加密,本地加密只是增加了一些復(fù)雜度法严,但也是有效的损敷。比如利用對稱算法,通過簡單的URLENCODE + BASE64編碼防止數(shù)據(jù)明文傳輸

2)渐夸、對普通請求嗤锉、返回數(shù)據(jù),生成MD5校驗(yàn)(MD5中加入動態(tài)密鑰)墓塌,進(jìn)行數(shù)據(jù)完整性(簡單防篡改瘟忱,安全性較低,優(yōu)點(diǎn):快速)校驗(yàn)苫幢。發(fā)送請求也有PBE加密等等

3)访诱、對于重要數(shù)據(jù),使用RSA進(jìn)行數(shù)字簽名韩肝,起到防篡改作触菜。

4)、 對于比較敏感的數(shù)據(jù)哀峻,如用戶信息(登陸涡相、注冊等),客戶端發(fā)送使用RSA加密剩蟀,服務(wù)器返回使用DES(AES)加密催蝗。

類型 簡介
本地數(shù)據(jù)加密 對NSUserDefaults,sqlite存儲文件數(shù)據(jù)加密育特,保護(hù)帳號和關(guān)鍵信息丙号。
URL編碼加密 對程序中出現(xiàn)的URL進(jìn)行編碼加密,防止URL被靜態(tài)分析
網(wǎng)絡(luò)傳輸數(shù)據(jù)加密 對客戶端傳輸數(shù)據(jù)提供加密方案,有效防止通過網(wǎng)絡(luò)接口的攔截獲取
方法體犬缨,方法名高級混淆 對應(yīng)用程序的方法名和方法體進(jìn)行混淆喳魏,保證源碼被逆向后無法解析代碼
程序結(jié)構(gòu)混排加密 對應(yīng)用程序邏輯結(jié)構(gòu)進(jìn)行打亂混排,保證源碼可讀性降到最低

三怀薛、iOS移動端安全模塊設(shè)計

1刺彩、基礎(chǔ)模塊

1)、對稱加密工具類
提供iOS客戶端的單向散列和基礎(chǔ)對稱加密算法(MD5 \ SHA \ DES \ 3DES \ RC2和RC4 \ IDEA \ DSA \ AES)

//Base64加密
+(NSString *)encodeBase64:(NSString *)input {
    NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
    data = [GTMBase64 encodeData:data];
    NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"encodeBase64 == %@",base64String);
    return base64String;
}

//Base64編碼
+(NSString *)base64EncodeString:(NSString *)string {
    //1.先把字符串轉(zhuǎn)換為二進(jìn)制數(shù)據(jù)
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    //2.對二進(jìn)制數(shù)據(jù)進(jìn)行base64編碼枝恋,返回編碼后的字符串
    //這是蘋果已經(jīng)給我們提供的方法
    NSString *str = [data base64EncodedStringWithOptions:0];
    return str;
}

//Base64解密
+(NSString *)decodeBase64:(NSString *)input {
    NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
    data = [GTMBase64 decodeData:data];
    NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"decodeBase64 == %@",base64String);
    return base64String;
}

//對base64編碼后的字符串進(jìn)行解碼
+(NSString *)base64DecodeString:(NSString *)string {
    //1.將base64編碼后的字符串『解碼』為二進(jìn)制數(shù)據(jù)
    //這是蘋果已經(jīng)給我們提供的方法
    NSData *data = [[NSData alloc]initWithBase64EncodedString:string options:0];
    //2.把二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為字符串返回
    NSString *str =  [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
    return str;
}

//Base64 字符串解碼成 字符串
+(NSString *)decodeBase64ToHexString:(NSString *)input {
    //1.將base64編碼后的字符串『解碼』為二進(jìn)制數(shù)據(jù)
    //這是蘋果已經(jīng)給我們提供的方法
    NSData *myD = [[NSData alloc]initWithBase64EncodedString:input options:0];
    Byte *bytes = (Byte *)[myD bytes];
    //下面是Byte 轉(zhuǎn)換為16進(jìn)制迂苛。
    NSString *hexStr=@"";
    for(int i=0;i<[myD length];i++) {
        NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];///16進(jìn)制數(shù)
        if([newHexStr length]==1)
            hexStr = [NSString stringWithFormat:@"%@0%@",hexStr,newHexStr];
        else
            hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr];
    }
    return hexStr;
}

//DES 加密
+(NSData *)encryptUseDES:(NSData *)plainText key:(Byte *)key {
    NSData *textData = plainText;
    NSUInteger dataLength = [textData length];
    unsigned char buffer[1024];
    memset(buffer, 0, sizeof(char));
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
                                          kCCOptionECBMode,
                                          key, kCCKeySizeDES,
                                          nil,
                                          [textData bytes], dataLength,
                                          buffer, 1024,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
        return data;
    }
    return nil;
}

//DES 解密
+(NSData *)decrypUseDES:(NSData *)plainText key:(Byte *)key {
    NSData *cipherdata = plainText;
    unsigned char buffer[1024];
    memset(buffer, 0, sizeof(char));
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES,
                                          kCCOptionECBMode,
                                          key, kCCKeySizeDES,
                                          nil,
                                          [cipherdata bytes], [cipherdata length],
                                          buffer, 1024,
                                          &numBytesDecrypted);
    if(cryptStatus == kCCSuccess) {
        NSData *plaindata = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesDecrypted];
        return plaindata;
    }
    return nil;
}

/MD5加密返回Nsdata
+(NSData *)encodeMD5:(NSData *)input {
 unsigned char result[CC_MD5_DIGEST_LENGTH];
 CC_MD5(input.bytes, (CC_LONG)input.length, result);
 NSData *data =[[NSData alloc] initWithBytes:result length:CC_MD5_DIGEST_LENGTH];
 return data;
}

如下,生成是小寫的MD5的字符串鼓择,如果要生成大寫的,只需要把
[ret appendFormat:@"%02X",result[i]];中的 "%02X"的 X改成小寫的 x即可就漾。

//MD5加密返回Nsstring
+(NSString *)MD5HexDigest:(NSData *)input {
 unsigned char result[CC_MD5_DIGEST_LENGTH];
 CC_MD5(input.bytes, (CC_LONG)input.length, result);
 NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
 for (int i = 0; i<CC_MD5_DIGEST_LENGTH; i++)  {
     [ret appendFormat:@"%02X",result[i]];
 }
 return ret;
}

2)呐能、非對稱加密工具類
iOS中的Security.framework提供了對RSA算法的支持。這種方式需要對密匙對進(jìn)行處理抑堡,根據(jù)public key生成證書摆出,通過private key生成p12格式的密匙。
除了Secruty.framework首妖,也可以將openssl庫編譯到iOS工程中偎漫,這可以提供更靈活的使用方式。
開源的:OpenSSLRSAWrapper

2有缆、一些場景方案設(shè)計舉例:(登錄場景token)

1)象踊、一般的登陸:
客戶端第一次發(fā)出登錄請求時, 用戶密碼以明文的方式傳輸棚壁, 一旦被截獲杯矩, 后果嚴(yán)重。因此密碼需要加密袖外,例如可采用RSA非對稱加密史隆。具體流程如下:

  1. 客戶端向服務(wù)器第一次發(fā)起登錄請求(不傳輸用戶名和密碼)。
  2. 服務(wù)器利用RSA算法產(chǎn)生一對公鑰和私鑰曼验。并保留私鑰泌射, 將公鑰發(fā)送給客戶端。
  3. 客戶端收到公鑰后鬓照, 加密用戶密碼熔酷, 向服務(wù)器發(fā)起第二次登錄請求(傳輸用戶名和加密后的密碼)。
  4. 服務(wù)器利用保留的私鑰對密文進(jìn)行解密颖杏,得到真正的密碼纯陨。

2)、token加密:
再仔細(xì)核對上述登錄流程, 我們發(fā)現(xiàn)服務(wù)器判斷用戶是否登錄翼抠, 完全依賴于sessionId, 一旦其被截獲咙轩, 黑客就能夠模擬出用戶的請求。于是我們需要引入token的概念: 用戶登錄成功后阴颖, 服務(wù)器不但為其分配了sessionId, 還分配了token活喊, token是維持登錄狀態(tài)的關(guān)鍵秘密數(shù)據(jù)。在服務(wù)器向客戶端發(fā)送的token數(shù)據(jù)量愧,也需要加密钾菊。于是一次登錄的細(xì)節(jié)再次擴(kuò)展:

  1. 客戶端向服務(wù)器第一次發(fā)起登錄請求(不傳輸用戶名和密碼)。服務(wù)器利用RSA算法產(chǎn)生一對公鑰和私鑰偎肃。并保留私鑰煞烫, 將公鑰發(fā)送給客戶端。
  2. 客戶端收到公鑰后累颂, 加密用戶密碼滞详,向服務(wù)器發(fā)送用戶名和加密后的用戶密碼; 同時另外產(chǎn)生一對公鑰和私鑰紊馏,自己保留私鑰, 向服務(wù)器發(fā)送公鑰料饥; 于是第二次登錄請求傳輸了用戶名和加密后的密碼以及客戶端生成的公鑰。
  3. 服務(wù)器利用保留的私鑰對密文進(jìn)行解密朱监,得到真正的密碼岸啡。 經(jīng)過判斷, 確定用戶可以登錄后赫编,生成sessionId和token巡蘸, 同時利用客戶端發(fā)送的公鑰,對token進(jìn)行加密擂送。最后將sessionId和加密后的token返還給客戶端赡若。
  4. 客戶端利用自己生成的私鑰對token密文解密, 得到真正的token团甲。

圖示如下:


3)逾冬、登錄保持(也就是http/https數(shù)據(jù)請求階段)
引入token后,http/https請求被獲取問題便可得到解決躺苦。 客戶端將token和其它的一些變量身腻, 利用散列加密算法得到簽名后,連同sessionId一并發(fā)送給服務(wù)器匹厘; 服務(wù)器取出保存于服務(wù)器端的token嘀趟,利用相同的法則生成校驗(yàn)簽名, 如果客戶端簽名與服務(wù)器的校驗(yàn)簽名一致愈诚, 就認(rèn)為請求來自登錄的客戶端她按。(支付寶一樣的機(jī)制)結(jié)構(gòu)圖如下:

注:token失效的兩種情況:

 1牛隅、用戶登錄出系統(tǒng)
 2、token在后臺的規(guī)定時間內(nèi)失效(每個token都是有時間效應(yīng)的)

失效原理:在服務(wù)器端的redis中刪除相應(yīng)key為session的鍵值對酌泰。

四媒佣、總結(jié)

本文只是初步介紹了一些加密的基礎(chǔ)知識和iOS客戶端安全設(shè)計時的基本思路,為大家提供一種參考陵刹。當(dāng)然一些金融類和支付類的App對安全性的要求更高默伍,在支付、掃碼等環(huán)節(jié)的安全設(shè)計方案可能需要更加的完善衰琐,甚至離線支付時的私鑰分端保存等等也糊,這些都是需要思考的,也希望大家給出好的建議和方案羡宙。

附:

密碼安全知識學(xué)習(xí)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末狸剃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子狗热,更是在濱河造成了極大的恐慌捕捂,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斗搞,死亡現(xiàn)場離奇詭異,居然都是意外死亡慷妙,警方通過查閱死者的電腦和手機(jī)僻焚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來膝擂,“玉大人虑啤,你說我怎么就攤上這事〖懿觯” “怎么了狞山?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叉寂。 經(jīng)常有香客問我萍启,道長,這世上最難降的妖魔是什么屏鳍? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任勘纯,我火速辦了婚禮,結(jié)果婚禮上钓瞭,老公的妹妹穿的比我還像新娘驳遵。我一直安慰自己,他們只是感情好山涡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布堤结。 她就那樣靜靜地躺著唆迁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪竞穷。 梳的紋絲不亂的頭發(fā)上唐责,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機(jī)與錄音来庭,去河邊找鬼妒蔚。 笑死,一個胖子當(dāng)著我的面吹牛月弛,可吹牛的內(nèi)容都是我干的肴盏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼帽衙,長吁一口氣:“原來是場噩夢啊……” “哼菜皂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起厉萝,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤恍飘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谴垫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體章母,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年翩剪,在試婚紗的時候發(fā)現(xiàn)自己被綠了乳怎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡前弯,死狀恐怖蚪缀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情恕出,我是刑警寧澤询枚,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站浙巫,受9級特大地震影響金蜀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜的畴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一廉油、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧苗傅,春花似錦抒线、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抱慌。三九已至,卻和暖如春眨猎,著一層夾襖步出監(jiān)牢的瞬間抑进,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工睡陪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寺渗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓兰迫,卻偏偏與公主長得像信殊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子汁果,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

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