iOS 集成 SSL Pinning

一剿骨、SSL Pinning 簡(jiǎn)介

1覆旭、使用背景

在開(kāi)發(fā)手機(jī)應(yīng)用時(shí)铸屉,如何正確的使用HTTPS來(lái)提高網(wǎng)絡(luò)傳輸?shù)陌踩允怯葹橹匾亩て选TTPS協(xié)議本使用了SSL 加密傳輸,相比HTTP但依然存在極大的安全隱患----中間人攻擊彻坛。SSL解決了內(nèi)容的加密的問(wèn)題顷啼,但是SSL過(guò)程中是依靠證書(shū)進(jìn)行驗(yàn)證的,這就需要保證證書(shū)絕對(duì)的安全昌屉。先立一個(gè)小目標(biāo)(偽造證書(shū))钙蒙,萬(wàn)一實(shí)現(xiàn)了呢?在立一個(gè)小目標(biāo)(偽造服務(wù)器)间驮,萬(wàn)一實(shí)現(xiàn)了呢躬厌?事實(shí)證明目標(biāo)是可以實(shí)現(xiàn)的(SSL系統(tǒng)遭入侵發(fā)布虛假密鑰 微軟谷歌受影響 )。SSL Pinning技術(shù)就是基于SSL基礎(chǔ)上在添加一個(gè)本地證書(shū)竞帽,用來(lái)再次驗(yàn)證扛施!

2、中間人攻擊

中間人攻擊(Man-in-the-middle Attack抢呆,簡(jiǎn)稱(chēng)MITM煮嫌、MitM、MIM抱虐、MiM昌阿、MITMA)是一種由來(lái)已久的網(wǎng)絡(luò)入侵手段,并且在今天仍然有著廣泛的發(fā)展空間恳邀,如SMB會(huì)話劫持懦冰、DNS欺騙等攻擊都是典型的中間人攻擊。簡(jiǎn)而言之谣沸,所謂的中間人攻擊就是通過(guò)攔截正常的網(wǎng)絡(luò)通信數(shù)據(jù)刷钢,并進(jìn)行數(shù)據(jù)篡改和嗅探,而通信的雙方卻毫不知情乳附。

中間人攻擊

3内地、Charles抓包原理

Charles作為一個(gè)中間人代理,當(dāng)瀏覽器和服務(wù)器通信時(shí)赋除,Charles接收服務(wù)器的證書(shū)阱缓,但動(dòng)態(tài)生成一張證書(shū)發(fā)送給瀏覽器,也就是說(shuō)Charles作為中間代理在瀏覽器和服務(wù)器之間通信举农,所以通信的數(shù)據(jù)可以被Charles攔截并解密荆针。由于Charles更改了證書(shū),瀏覽器校驗(yàn)不通過(guò)會(huì)給出安全警告,必須安裝Charles的證書(shū)后才能進(jìn)行正常訪問(wèn)航背。

Charles抓包原理
  • 客戶(hù)端向服務(wù)器發(fā)起HTTPS請(qǐng)求
  • Charles攔截客戶(hù)端的請(qǐng)求喉悴,偽裝成客戶(hù)端向服務(wù)器進(jìn)行請(qǐng)求
  • 服務(wù)器向“客戶(hù)端”(實(shí)際上是Charles)返回服務(wù)器的CA證書(shū)
  • Charles攔截服務(wù)器的響應(yīng),獲取服務(wù)器證書(shū)公鑰玖媚,然后自己制作一張證書(shū)箕肃,將服務(wù)器證書(shū)替換后發(fā)送給客戶(hù)端。(這一步最盅,Charles拿到了服務(wù)器證書(shū)的公鑰)
  • 客戶(hù)端接收到“服務(wù)器”(實(shí)際上是Charles)的證書(shū)后突雪,生成一個(gè)對(duì)稱(chēng)密鑰,用Charles的公鑰加密涡贱,發(fā)送給“服務(wù)器”(Charles)
  • Charles攔截客戶(hù)端的響應(yīng)咏删,用自己的私鑰解密對(duì)稱(chēng)密鑰,然后用服務(wù)器證書(shū)公鑰加密问词,發(fā)送給服務(wù)器督函。(這一步,Charles拿到了對(duì)稱(chēng)密鑰)
  • 服務(wù)器用自己的私鑰解密對(duì)稱(chēng)密鑰激挪,向“客戶(hù)端”(Charles)發(fā)送響應(yīng)
  • Charles攔截服務(wù)器的響應(yīng)辰狡,替換成自己的證書(shū)后發(fā)送給客戶(hù)端
  • 至此,連接建立垄分,Charles拿到了 服務(wù)器證書(shū)的公鑰 和 客戶(hù)端與服務(wù)器協(xié)商的對(duì)稱(chēng)密鑰宛篇,之后就可以解密或者修改加密的報(bào)文了。

HTTPS抓包的原理還是挺簡(jiǎn)單的薄湿,簡(jiǎn)單來(lái)說(shuō)叫倍,就是Charles作為“中間人代理”,拿到了 服務(wù)器證書(shū)公鑰 和 HTTPS連接的對(duì)稱(chēng)密鑰豺瘤,前提是客戶(hù)端選擇信任并安裝Charles的CA證書(shū)吆倦,否則客戶(hù)端就會(huì)“報(bào)警”并中止連接。這樣看來(lái)坐求,HTTPS還是很安全的蚕泽。

4、SSL Pinning

SSL Pinning(又叫Certificate Pinning)可以理解為證書(shū)綁定桥嗤。在一些應(yīng)用場(chǎng)景中须妻,客戶(hù)端和服務(wù)器之間的通信是事先約定好的,既服務(wù)器地址和證書(shū)是預(yù)先知道的泛领,這種情況常見(jiàn)于CS(Client-Server)架構(gòu)的應(yīng)用中荒吏。這樣的話在客戶(hù)端事先保存好一份服務(wù)器的證書(shū)(含公鑰),每次請(qǐng)求服務(wù)器的時(shí)候师逸,將服務(wù)器返回的證書(shū)與客戶(hù)端保存的證書(shū)進(jìn)行對(duì)比司倚,如果證書(shū)不符,說(shuō)明受到中間人攻擊篓像,馬上可以中斷請(qǐng)求动知。這樣的話中間人就無(wú)法偽造證書(shū)進(jìn)行攻擊了。

我們需要將APP代碼內(nèi)置僅接受指定域名的證書(shū)员辩,而不接受操作系統(tǒng)或?yàn)g覽器內(nèi)置的CA根證書(shū)對(duì)應(yīng)的任何證書(shū)盒粮,通過(guò)這種授權(quán)方式,保障了APP與服務(wù)端通信的唯一性和安全性奠滑。但是CA簽發(fā)證書(shū)都存在有效期問(wèn)題丹皱,所以缺點(diǎn)是在證書(shū)續(xù)期后需要將證書(shū)重新內(nèi)置到APP中。

公鑰鎖定則是提取證書(shū)中的公鑰并內(nèi)置到移動(dòng)端APP中宋税,通過(guò)與服務(wù)器對(duì)比公鑰值來(lái)驗(yàn)證連接的合法性摊崭,我們?cè)谥谱髯C書(shū)密鑰時(shí),公鑰在證書(shū)的續(xù)期前后都可以保持不變(即密鑰對(duì)不變)杰赛,所以可以避免證書(shū)有效期問(wèn)題呢簸。

證書(shū)鎖定旨在解決移動(dòng)端APP與服務(wù)端通信的唯一性,實(shí)際通信過(guò)程中乏屯,如果鎖定過(guò)程失敗根时,那么客戶(hù)端APP將拒絕針對(duì)服務(wù)器的所有 SSL/TLS 請(qǐng)求,F(xiàn)aceBook/Twitter則通過(guò)證書(shū)鎖定以防止Charles/Fiddler等抓包工具中間人攻擊辰晕。

為什么直接對(duì)比就能保證證書(shū)沒(méi)問(wèn)題蛤迎?如果中間人從客戶(hù)端取出證書(shū),再偽裝成服務(wù)端跟其他客戶(hù)端通信含友,它發(fā)送給客戶(hù)端的這個(gè)證書(shū)不就能通過(guò)驗(yàn)證嗎替裆?確實(shí)可以通過(guò)驗(yàn)證,但后續(xù)的流程走不下去唱较,因?yàn)橄乱徊娇蛻?hù)端會(huì)用證書(shū)里的公鑰加密扎唾,中間人沒(méi)有這個(gè)證書(shū)的私鑰就解不出內(nèi)容,也就截獲不到數(shù)據(jù)南缓,這個(gè)證書(shū)的私鑰只有真正的服務(wù)端有胸遇,中間人偽造證書(shū)主要偽造的是公鑰。

為什么要用SSL Pinning汉形?正常的驗(yàn)證方式不夠嗎纸镊?如果服務(wù)端的證書(shū)是從受信任的的CA機(jī)構(gòu)頒發(fā)的,驗(yàn)證是沒(méi)問(wèn)題的概疆,但CA機(jī)構(gòu)頒發(fā)證書(shū)比較昂貴逗威,小企業(yè)或個(gè)人用戶(hù)可能會(huì)選擇自己頒發(fā)證書(shū),這樣就無(wú)法通過(guò)系統(tǒng)受信任的CA機(jī)構(gòu)列表驗(yàn)證這個(gè)證書(shū)的真?zhèn)瘟瞬砑剑孕枰猄SL Pinning這樣的方式去驗(yàn)證凯旭。

二、NSURLSession方式

1、獲取證書(shū)

客戶(hù)端需要證書(shū)(Certification file)罐呼, .cer格式的文件鞠柄。可以跟服務(wù)器端索取嫉柴。如果他們給個(gè).pem文件厌杜,要使用命令行轉(zhuǎn)換:
openssl x509 -inform PEM -in name.pem -outform DER -out name.cer

如果給了個(gè).crt文件,請(qǐng)這樣轉(zhuǎn)換:
openssl x509 -in name.crt -out name.cer -outform der

如果啥都不給你计螺,你只能自己動(dòng)手了夯尽,這里以github.com為例子,獲取證書(shū):
openssl s_client -connect github.com:443 </dev/null 2>/dev/null | openssl x509 -outform DER > github.com.cer

2登馒、NSURLSession實(shí)現(xiàn)

當(dāng)談到NSURLSession使用SSL pinning有點(diǎn)棘手匙握,因?yàn)樵贏FNetworking中,其本身已經(jīng)有封裝好的類(lèi)可以使用來(lái)進(jìn)行配置陈轿。這里沒(méi)有辦法去設(shè)置一組證書(shū)來(lái)自動(dòng)取消所有本地證書(shū)不匹配的response肺孤。我們需要手動(dòng)執(zhí)行檢查來(lái)實(shí)現(xiàn)在NSURLSession上的SSL pinning。我們很榮幸的是我們可以用Security's framework C API济欢。

創(chuàng)建默認(rèn)會(huì)話配置的NSURLSession對(duì)象赠堵,及發(fā)送請(qǐng)求,執(zhí)行任務(wù)

    // 設(shè)置地址
    NSURL *testURL = [NSURL URLWithString:@"https://github.com"];

    // 創(chuàng)建默認(rèn)會(huì)話配置的NSURLSession對(duì)象
    NSURLSessionConfiguration *seeConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    seeConfig.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
    NSURLSession *session = [NSURLSession sessionWithConfiguration:seeConfig
                                                          delegate:self
                                                     delegateQueue:nil];
    
    // NSURLSession使用NSURLSessionTask來(lái)發(fā)送一個(gè)請(qǐng)求法褥,
    // 我們使用dataTaskWithURL:completionHandler:方法來(lái)進(jìn)行SSL pinning 測(cè)試
    NSURLSessionDataTask *task =
    [session dataTaskWithURL:testURL
           completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
               if (!error) {
                   NSString *str =
                   [[NSString alloc]initWithData:data encoding:NSASCIIStringEncoding];
                   NSLog(@"str : %@", str);
               } else {
                   NSLog(@"error : %@", error);
               }
               
           }];
    [task resume];

在代理回調(diào)方法中茫叭,校驗(yàn)證書(shū)是否合法

// 代理回調(diào)
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
    
    // 得到遠(yuǎn)程證書(shū)
    SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
    SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0);
    
    // 設(shè)置ssl政策來(lái)檢測(cè)主域名
    NSMutableArray *policies = [NSMutableArray array];
    [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)challenge.protectionSpace.host)];
    
    // 驗(yàn)證服務(wù)器證書(shū)
    SecTrustResultType result;
    SecTrustEvaluate(serverTrust, &result);
    BOOL certificateIsValid =
    (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
    
    // 得到遠(yuǎn)程和本地證書(shū)data
    NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
    NSString *pathToCert = [[NSBundle mainBundle] pathForResource:@"github2018" ofType:@"cer"];
    NSData *localCertificate = [NSData dataWithContentsOfFile:pathToCert];
    
    // 檢查
    if (certificateIsValid && [remoteCertificateData isEqualToData:localCertificate]) {
        // 驗(yàn)證通過(guò)
        NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
    }else {
        // 驗(yàn)證不通過(guò)
        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,NULL);
    }
}

上述方法的開(kāi)始,我們使用SecTrustGetCertificateAtIndex來(lái)得到服務(wù)器的SSL證書(shū)數(shù)據(jù)半等。然后使用證書(shū)評(píng)估設(shè)置policies揍愁。證書(shū)使用SecTrustEvaluate評(píng)估,然后返回以下幾種認(rèn)證結(jié)果類(lèi)型之一:

typedef uint32_t SecTrustResultType;
enum {
    kSecTrustResultInvalid = 0,
    kSecTrustResultProceed = 1,
    kSecTrustResultConfirm SEC_DEPRECATED_ATTRIBUTE = 2,
    kSecTrustResultDeny = 3,
    kSecTrustResultUnspecified = 4,
    kSecTrustResultRecoverableTrustFailure = 5,
    kSecTrustResultFatalTrustFailure = 6,
    kSecTrustResultOtherError = 7
};

如果我們得到kSecTrustResultProceedkSecTrustResultUnspecified之外的類(lèi)型結(jié)果杀饵,我們可以認(rèn)為證書(shū)是無(wú)效的(不被信任的)莽囤。

至今為止我們除了檢測(cè)遠(yuǎn)程服務(wù)器證書(shū)評(píng)估外,還沒(méi)有做其他事情切距,對(duì)于SSL pinning 檢測(cè)我們需要通過(guò)SecCertificateRef來(lái)得到他的NSData朽缎。這個(gè)SecCertificateRef來(lái)自于challenge.protectionSpace.serverTrust。而本地的NSData來(lái)自本地的.cer證書(shū)文件谜悟。然后我們使用isEqual來(lái)進(jìn)行SSL pinning话肖。

如果遠(yuǎn)程服務(wù)器證書(shū)的NSData等于本地的證書(shū)data,那么就可以通過(guò)評(píng)估葡幸,我們可以驗(yàn)證服務(wù)器身份然后進(jìn)行通信最筒,而且還要使用completionHandler(NSURLSessionAuthChallengeUseCredential,credential)執(zhí)行request。

然而如果兩個(gè)data不相等蔚叨,我們使用completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,NULL)方法來(lái)取消dataTask的執(zhí)行床蜘,這樣就可以拒絕和服務(wù)器溝通辙培。

這就是在NSURLSession中使用SSL pinning。

三邢锯、AFNetworking方式

1虏冻、AFSecurityPolicy

安全模式設(shè)置

AFSecurityPolicy是AFNetworking中三種安全策略模塊,提供了證書(shū)鎖定模式

  • AFSSLPinningModeNone:
這個(gè)模式表示不做SSL pinning弹囚,只跟瀏覽器一樣在系統(tǒng)的信任機(jī)構(gòu)列表里驗(yàn)證服務(wù)端返回的證書(shū)。
若證書(shū)是信任機(jī)構(gòu)簽發(fā)的就會(huì)通過(guò)领曼,若是自己服務(wù)器生成的證書(shū)鸥鹉,這里是不會(huì)通過(guò)的。
  • AFSSLPinningModeCertificate:
這個(gè)模式表示用證書(shū)綁定方式驗(yàn)證證書(shū)庶骄,需要客戶(hù)端保存有服務(wù)端的證書(shū)拷貝毁渗,
這里驗(yàn)證分兩步,第一步驗(yàn)證證書(shū)的域名/有效期等信息单刁,
第二步是對(duì)比服務(wù)端返回的證書(shū)跟客戶(hù)端返回的是否一致灸异。
  • AFSSLPinningModePublicKey:
這個(gè)模式同樣是用證書(shū)綁定方式驗(yàn)證,客戶(hù)端要有服務(wù)端的證書(shū)拷貝羔飞,
只是驗(yàn)證時(shí)只驗(yàn)證證書(shū)里的公鑰肺樟,不驗(yàn)證證書(shū)的有效期等信息。
只要公鑰是正確的逻淌,就能保證通信不會(huì)被竊聽(tīng)么伯,
因?yàn)橹虚g人沒(méi)有私鑰,無(wú)法解開(kāi)通過(guò)公鑰加密的數(shù)據(jù)卡儒。

選擇那種模式呢?
AFSSLPinningModeCertificate最安全的比對(duì)模式田柔。但是也比較麻煩,因?yàn)樽C書(shū)是打包在APP中骨望,如果服務(wù)器證書(shū)改變或者到期硬爆,舊版本無(wú)法使用了,我們就需要用戶(hù)更新APP來(lái)使用最新的證書(shū)擎鸠。
AFSSLPinningModePublicKey只比對(duì)證書(shū)的Public Key缀磕,只要Public Key沒(méi)有改變,證書(shū)的其他變動(dòng)都不會(huì)影響使用劣光。
如果你不能保證你的用戶(hù)總是使用你的APP的最新版本虐骑,所以我們使用AFSSLPinningModePublicKey

屬性

/**
 服務(wù)器證書(shū)驗(yàn)證模式赎线,默認(rèn)是不驗(yàn)證
 */
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;

/**
 驗(yàn)證服務(wù)器的證書(shū)的集合廷没,默認(rèn)情況下,AFNetworking會(huì)搜索工程中所有.cer的證書(shū)文件垂寥,但不會(huì)將某個(gè)證書(shū)作為默認(rèn)颠黎。如果想創(chuàng)建AFSecurityPolicy對(duì)象另锋,就先調(diào)用certificatesInBundle方法加載證書(shū),然后調(diào)用policyWithPinningMode:withPinnedCertificates方法創(chuàng)建對(duì)象
 */
@property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates;

/**
 是否信任無(wú)效或者過(guò)期的證書(shū)狭归,默認(rèn)為否
 */
@property (nonatomic, assign) BOOL allowInvalidCertificates;

/**
 是否驗(yàn)證證書(shū)中的域名夭坪,默認(rèn)為是
 */
@property (nonatomic, assign) BOOL validatesDomainName;

2、AFNetworking實(shí)現(xiàn)

創(chuàng)建自定義安全策略

// 自定義安全策略
- (AFSecurityPolicy *)customSecurityPolicy {
    
    // 獲取證書(shū)
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"github2020" ofType:@"cer"];
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    NSSet *pinnedCertificates = [[NSSet alloc] initWithObjects:certData, nil];

    /*
     安全模式
     AFSSLPinningModeNone:完全信任服務(wù)器證書(shū)过椎;
     AFSSLPinningModePublicKey:只比對(duì)服務(wù)器證書(shū)和本地證書(shū)的Public Key是否一致室梅,如果一致則信任服務(wù)器證書(shū);
     AFSSLPinningModeCertificate:比對(duì)服務(wù)器證書(shū)和本地證書(shū)的所有內(nèi)容疚宇,完全一致則信任服務(wù)器證書(shū)
     */
    AFSecurityPolicy *securityPolicy =
    [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey
                     withPinnedCertificates:pinnedCertificates];
    
    // allowInvalidCertificates 是否允許無(wú)效證書(shū)(也就是自建的證書(shū))亡鼠,默認(rèn)為NO
    // 如果是需要驗(yàn)證自建證書(shū),需要設(shè)置為YES
    securityPolicy.allowInvalidCertificates = YES;
    
    /*
    validatesDomainName 是否需要驗(yàn)證域名敷待,默認(rèn)為YES间涵;
    假如證書(shū)的域名與你請(qǐng)求的域名不一致,需把該項(xiàng)設(shè)置為NO榜揖;
    如設(shè)成NO的話勾哩,即服務(wù)器使用其他可信任機(jī)構(gòu)頒發(fā)的證書(shū),也可以建立連接举哟,這個(gè)非常危險(xiǎn)思劳,建議打開(kāi)。
    置為NO妨猩,主要用于這種情況:客戶(hù)端請(qǐng)求的是子域名敢艰,而證書(shū)上的是另外一個(gè)域名。
    因?yàn)镾SL證書(shū)上的域名是獨(dú)立的册赛,假如證書(shū)上注冊(cè)的域名是www.google.com钠导,那么mail.google.com是無(wú)法驗(yàn)證通過(guò)的;
    當(dāng)然森瘪,有錢(qián)可以注冊(cè)通配符的域名*.google.com牡属,但這個(gè)還是比較貴的。
    如置為NO扼睬,建議自己添加對(duì)應(yīng)域名的校驗(yàn)邏輯逮栅。
     */
    securityPolicy.validatesDomainName = YES;
    
    return securityPolicy;
}

創(chuàng)建網(wǎng)絡(luò)會(huì)話管理

- (AFHTTPSessionManager *)manager {
    if (!_manager) {
        // 設(shè)置BaseUrl
        NSURL *baseUrl = [NSURL URLWithString:@"https://github.com"];
        AFHTTPSessionManager *manager =
        [[AFHTTPSessionManager manager] initWithBaseURL:baseUrl];
        
        manager.securityPolicy = [self customSecurityPolicy];
        
        manager.responseSerializer = [AFHTTPResponseSerializer serializer];
        manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];
        _manager = manager;
    }
    return _manager;
}

發(fā)送請(qǐng)求

// 發(fā)送請(qǐng)求
- (void)sendRequest {
    NSString *urlStr = @"https://github.com/AFNetworking/AFNetworking";
    [self.manager GET:urlStr
           parameters:nil
              headers:nil
             progress:nil
              success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                  NSString *str = [[NSString alloc] initWithData:responseObject
                                                        encoding:NSUTF8StringEncoding];
                  NSLog(@"%@",str);
              } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                  NSLog(@"%@", error);
              }];
}

附Demo鏈接:https://github.com/ZhangJingHao/ZJHSSLPinning

Charles對(duì)使用SSL Pinning前后抓包對(duì)比

使用SLL Pinning前
使用SLL Pinning后

參考鏈接:
如何使用SSL pinning來(lái)使你的iOS APP更加安全
證書(shū)鎖定SSL Pinning簡(jiǎn)介及用途
AFNetworking + SSL Pinning
SSL pinning using AFNetworking and NSURLSession
淺談HTTPS通信機(jī)制和Charles抓包原理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市窗宇,隨后出現(xiàn)的幾起案子措伐,更是在濱河造成了極大的恐慌,老刑警劉巖军俊,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侥加,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡粪躬,警方通過(guò)查閱死者的電腦和手機(jī)担败,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)昔穴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人提前,你說(shuō)我怎么就攤上這事吗货。” “怎么了狈网?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵宙搬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我拓哺,道長(zhǎng)勇垛,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任拓售,我火速辦了婚禮,結(jié)果婚禮上镶奉,老公的妹妹穿的比我還像新娘础淤。我一直安慰自己,他們只是感情好哨苛,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布鸽凶。 她就那樣靜靜地躺著,像睡著了一般建峭。 火紅的嫁衣襯著肌膚如雪玻侥。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天亿蒸,我揣著相機(jī)與錄音凑兰,去河邊找鬼。 笑死边锁,一個(gè)胖子當(dāng)著我的面吹牛姑食,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茅坛,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼音半,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了贡蓖?” 一聲冷哼從身側(cè)響起曹鸠,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斥铺,沒(méi)想到半個(gè)月后彻桃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晾蜘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年叛薯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浑吟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耗溜,死狀恐怖组力,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抖拴,我是刑警寧澤燎字,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站阿宅,受9級(jí)特大地震影響候衍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜洒放,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一蛉鹿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧往湿,春花似錦妖异、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至绒窑,卻和暖如春棕孙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背些膨。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工蟀俊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人订雾。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓欧漱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親葬燎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子误甚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345