iOS源碼補(bǔ)完計(jì)劃--AFNetworking(三)

目錄

  • 前言
  • AFSecurityPolicy.h
    • 對(duì)服務(wù)器證書的驗(yàn)證策略
    • 屬性
    • 獲取證書
    • 自定義安全策略
    • 核心方法
  • AFSecurityPolicy.m
    • SecTrustRef
    • 從證書中提取公鑰
    • 將公鑰轉(zhuǎn)化成NSData
    • 比對(duì)兩個(gè)公鑰是否相同
    • 返回服務(wù)器是否可以被信任
    • 取出所有服務(wù)器返回的證書
    • 取出服務(wù)器返回的所有證書中的公鑰
    • AFSecurityPolicy對(duì)象方法
    • 核心方法- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain
  • API注釋Demo
  • 參考資料

前言

AFNetworking源碼第三篇
主要看了看AFSecurityPolicy的內(nèi)容
負(fù)責(zé)網(wǎng)絡(luò)安全策略(證書)的驗(yàn)證

作為一個(gè)輔助模塊人灼、代碼量和文件都比較少
一行一行讀下來(lái)就可以了
但是最好把HTTP/HTTPS好好理解一下辨泳、這里就先不提了。將來(lái)看網(wǎng)絡(luò)協(xié)議的時(shí)候好好補(bǔ)一下喊崖。

AFN概述:《iOS源碼補(bǔ)完計(jì)劃--AFNetworking 3.1.0源碼研讀》

AFSecurityPolicy.h

對(duì)服務(wù)器證書的驗(yàn)證策略

typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
    AFSSLPinningModeNone,//無(wú)條件信任服務(wù)器的證書
    AFSSLPinningModePublicKey,//對(duì)服務(wù)器返回的證書中的PublicKey進(jìn)行驗(yàn)證
    AFSSLPinningModeCertificate,//對(duì)服務(wù)器返回的證書同本地證書全部進(jìn)行校驗(yàn)
};

屬性

/**
    SSLPinning 默認(rèn) `AFSSLPinningModeNone`
 */
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;

/**
    本地證書合集

    默認(rèn)腿箩、將會(huì)從整個(gè)工程目錄下加載所有(.cer)的證書文件
    如果想定制證書豪直、可以使用`certificatesInBundle`來(lái)加載證書
    然后調(diào)用`policyWithPinningMode:withPinnedCertificates`來(lái)創(chuàng)建一個(gè)新`AFSecurityPolicy`對(duì)象用于驗(yàn)證
 
    如果證書合集中任何一個(gè)被校驗(yàn)通過(guò)、那么`evaluateServerTrust:forDomain:`都將返回true
 */
@property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates;

/**
    使用允許無(wú)效或過(guò)期的證書 默認(rèn)`NO`
 */
@property (nonatomic, assign) BOOL allowInvalidCertificates;

/**
    是否驗(yàn)證域名 默認(rèn)`YES`
 */
@property (nonatomic, assign) BOOL validatesDomainName;

獲取證書

/**
    從指定`bundle`中獲取證書合集
    然后調(diào)用`policyWithPinningMode:withPinnedCertificates`來(lái)創(chuàng)建一個(gè)新`AFSecurityPolicy`對(duì)象用于驗(yàn)證
 */
+ (NSSet <NSData *> *)certificatesInBundle:(NSBundle *)bundle;

自定義安全策略

/**
    默認(rèn)的安全策略
    1珠移、不允許無(wú)效或過(guò)期的證書
    2弓乙、驗(yàn)證域名
    3末融、不對(duì)證書和公鑰進(jìn)行驗(yàn)證
 */
+ (instancetype)defaultPolicy;

///---------------------
/// @name Initialization
///---------------------

/**
    通過(guò)指定的驗(yàn)證策略`AFSSLPinningMode`來(lái)創(chuàng)建
 */
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;

/**
    通過(guò)指定的驗(yàn)證策略`AFSSLPinningMode`、以及證書合集來(lái)創(chuàng)建
 */
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;

核心方法

/**
    根據(jù)具體配置唆貌、確定是否接受指定服務(wù)器的信任

    服務(wù)器驗(yàn)證時(shí)會(huì)返回`NSURLCredential`challenge對(duì)象
    @param serverTrust 使用challenge.protectionSpace.serverTrust參數(shù)即可
    @param domain 使用challenge.protectionSpace.host即可

 */
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                  forDomain:(nullable NSString *)domain;

AFSecurityPolicy.m

其實(shí)整個(gè).m文件也太多可以研究的地方滑潘、因?yàn)槎际枪潭ǖ姆椒āD阒荒苓@么寫~
不過(guò)锨咙、一行一行看一看语卤。iOS的證書到底是如何驗(yàn)證的、也不錯(cuò)酪刀。

  • SecTrustRef

整個(gè)驗(yàn)證都是基于SecTrustRef的粹舵、和.cer文件的關(guān)系大概是:
NSData格式的證書=>SecCertificateRef=>SecTrustRef對(duì)象
這個(gè)SecTrustRef通過(guò)

CFDataRef SecCertificateCopyData(SecCertificateRef certificate)
SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)

的方式又可以取出證書和公鑰可見。
SecTrustRef就是一個(gè)內(nèi)部至少攜帶了證書與公鑰的結(jié)構(gòu)體骂倘。

  • 從證書中提取公鑰
static id AFPublicKeyForCertificate(NSData *certificate) {
    id allowedPublicKey = nil;
    SecCertificateRef allowedCertificate;
    SecCertificateRef allowedCertificates[1];
    CFArrayRef tempCertificates = nil;
    SecPolicyRef policy = nil;
    SecTrustRef allowedTrust = nil;
    SecTrustResultType result;

    //將二進(jìn)制證書轉(zhuǎn)化成`SecCertificateRef`
    allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
    //如果allowedCertificate為空眼滤,則執(zhí)行標(biāo)記_out后邊的代碼
    //__Require_Quiet&&_out和if&&else的意思差不多、好處是可以很多入口历涝、然后統(tǒng)一出口
    __Require_Quiet(allowedCertificate != NULL, _out);
    //給allowedCertificates賦值
    allowedCertificates[0] = allowedCertificate;
    //新建CFArra: tempCertificates
    tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
    //新建policy為X.509
    policy = SecPolicyCreateBasicX509();
    //創(chuàng)建SecTrustRef(`&allowedTrust`)對(duì)象诅需。如果出錯(cuò)就跳到_out標(biāo)記處 
    __Require_noErr_Quiet(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out);
    //校驗(yàn)證書。這個(gè)不是異步的荧库。如果出錯(cuò)也會(huì)調(diào)到_out標(biāo)記處
    __Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
    //在SecTrustRef對(duì)象中取出公鑰
    allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);

_out:
    //釋放使用過(guò)的對(duì)象
    if (allowedTrust) {
        CFRelease(allowedTrust);
    }

    if (policy) {
        CFRelease(policy);
    }

    if (tempCertificates) {
        CFRelease(tempCertificates);
    }

    if (allowedCertificate) {
        CFRelease(allowedCertificate);
    }

    return allowedPublicKey;
}

具體代碼沒(méi)啥可深究的堰塌、有需要的時(shí)候再去查查資料就行了
但有一點(diǎn)很有意思__Require_Quiet__Require_noErr_Quiet
作用其實(shí)和if-esle差不多、但是可以從多個(gè)入口跳到統(tǒng)一的出口分衫、相關(guān)函數(shù)__Require_XXX基本都是這個(gè)意思场刑。寫了幾個(gè)小方法、想看的自己可以copy運(yùn)行一下


#import <AssertMacros.h>


    //斷言為假則會(huì)執(zhí)行一下第三個(gè)action蚪战、拋出異常牵现、并且跳到_out
    __Require_Action(1, _out, NSLog(@"直接跳"));
    //斷言為真則往下、否則跳到_out
    __Require_Quiet(1,_out);
    NSLog(@"111");
    
    //如果不注釋邀桑、從這里直接就會(huì)跳到out
//    __Require_Quiet(0,_out);
//    NSLog(@"222");
    
    //如果沒(méi)有錯(cuò)誤瞎疼、也就是NO、繼續(xù)執(zhí)行
    __Require_noErr(NO, _out);
    NSLog(@"333");
    
    //如果有錯(cuò)誤壁畸、也就是YES贼急、跳到_out、并且拋出異常定位
    __Require_noErr(YES, _out);
    NSLog(@"444");
_out:
    NSLog(@"end");

2018-05-17 14:18:12.656703+0800 AFNetWorkingDemo[4046:313255] 111
2018-05-17 14:18:12.656944+0800 AFNetWorkingDemo[4046:313255] 333
AssertMacros: YES == 0 ,  file: /Users/kiritoSong/Desktop/博客/KTAFNetWorkingDemo/AFNetWorkingDemo/AFNetWorkingDemo/ViewController.m, line: 39, value: 1
2018-05-17 14:18:12.657097+0800 AFNetWorkingDemo[4046:313255] end
  • 將公鑰轉(zhuǎn)化成NSData
static NSData * AFSecKeyGetData(SecKeyRef key) {
    CFDataRef data = NULL;

    __Require_noErr_Quiet(SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data), _out);

    return (__bridge_transfer NSData *)data;

_out:
    if (data) {
        CFRelease(data);
    }

    return nil;
}
  • 比對(duì)兩個(gè)公鑰是否相同
static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {
#if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
    return [(__bridge id)key1 isEqual:(__bridge id)key2];
#else
    return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)];
#endif
}
  • 返回服務(wù)器是否可以被信任
static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) {
    BOOL isValid = NO;
    SecTrustResultType result;
    //校驗(yàn)證書
    __Require_noErr_Quiet(SecTrustEvaluate(serverTrust, &result), _out);
    //kSecTrustResultUnspecified:由非用戶證書校驗(yàn)通過(guò)
    //kSecTrustResultProceed:由用戶證書校驗(yàn)通過(guò)
    isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);

_out:
    return isValid;
}
  • 取出所有服務(wù)器返回的證書
static NSArray * AFCertificateTrustChainForServerTrust(SecTrustRef serverTrust) {
    CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
    NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];

    for (CFIndex i = 0; i < certificateCount; i++) {
        SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
        [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
    }

    return [NSArray arrayWithArray:trustChain];
}

SecTrustRef:對(duì)象通過(guò)NSURLCredential傳遞進(jìn)來(lái)的challenge.protectionSpace.serverTrust
也就是在外面通過(guò)- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(nullable NSString*)domain; 函數(shù)傳遞進(jìn)來(lái)供我們校驗(yàn)的證書

  • 取出服務(wù)器返回的所有證書中的公鑰
static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
    SecPolicyRef policy = SecPolicyCreateBasicX509();
    CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
    NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];
    for (CFIndex i = 0; i < certificateCount; i++) {
        SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);

        SecCertificateRef someCertificates[] = {certificate};
        CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL);

        SecTrustRef trust;
        __Require_noErr_Quiet(SecTrustCreateWithCertificates(certificates, policy, &trust), _out);

        SecTrustResultType result;
        __Require_noErr_Quiet(SecTrustEvaluate(trust, &result), _out);

        [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)];

    _out:
        if (trust) {
            CFRelease(trust);
        }

        if (certificates) {
            CFRelease(certificates);
        }

        continue;
    }
    CFRelease(policy);

    return [NSArray arrayWithArray:trustChain];
}
  • AFSecurityPolicy對(duì)象方法
@interface AFSecurityPolicy()
@property (readwrite, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
@property (readwrite, nonatomic, strong) NSSet *pinnedPublicKeys;
@end

@implementation AFSecurityPolicy

//取出某個(gè)bundle下所有的證書
+ (NSSet *)certificatesInBundle:(NSBundle *)bundle {
    NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];

    NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]];
    for (NSString *path in paths) {
        NSData *certificateData = [NSData dataWithContentsOfFile:path];
        [certificates addObject:certificateData];
    }

    return [NSSet setWithSet:certificates];
}

/**
    取當(dāng)前包內(nèi)所有的證書
 */
+ (NSSet *)defaultPinnedCertificates {
    static NSSet *_defaultPinnedCertificates = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //根據(jù)當(dāng)前類取出所在包位置
        NSBundle *bundle = [NSBundle bundleForClass:[self class]];
        _defaultPinnedCertificates = [self certificatesInBundle:bundle];
    });

    return _defaultPinnedCertificates;
}


#pragma mark  <#               工廠方法             #>
+ (instancetype)defaultPolicy {
    AFSecurityPolicy *securityPolicy = [[self alloc] init];
    securityPolicy.SSLPinningMode = AFSSLPinningModeNone;

    return securityPolicy;
}

+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
    return [self policyWithPinningMode:pinningMode withPinnedCertificates:[self defaultPinnedCertificates]];
}

+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet *)pinnedCertificates {
    AFSecurityPolicy *securityPolicy = [[self alloc] init];
    securityPolicy.SSLPinningMode = pinningMode;

    [securityPolicy setPinnedCertificates:pinnedCertificates];

    return securityPolicy;
}

- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }

    self.validatesDomainName = YES;

    return self;
}
//將證書的合集轉(zhuǎn)化成公鑰的合集并且賦值給self.pinnedPublicKeys持有備用
- (void)setPinnedCertificates:(NSSet *)pinnedCertificates {
    _pinnedCertificates = pinnedCertificates;

    if (self.pinnedCertificates) {
        NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[self.pinnedCertificates count]];
        for (NSData *certificate in self.pinnedCertificates) {
            id publicKey = AFPublicKeyForCertificate(certificate);
            if (!publicKey) {
                continue;
            }
            [mutablePinnedPublicKeys addObject:publicKey];
        }
        self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys];
    } else {
        self.pinnedPublicKeys = nil;
    }
}
  • 核心方法
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                  forDomain:(NSString *)domain
{
    //驗(yàn)證不通過(guò)
    //host存在 && 允許使用過(guò)期證書(通常都是NO) && 驗(yàn)證域名 && (無(wú)條件信任服務(wù)器證書 || 沒(méi)有證書)
    if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
        // https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html
        //  According to the docs, you should only trust your provided certs for evaluation.
        //  Pinned certificates are added to the trust. Without pinned certificates,
        //  there is nothing to evaluate against.
        //
        //  From Apple Docs:
        //          "Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors).
        //           Instead, add your own (self-signed) CA certificate to the list of trusted anchors."
        NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
        return NO;
    }
    
    //證書數(shù)組
    NSMutableArray *policies = [NSMutableArray array];
    
    if (self.validatesDomainName) {
        //驗(yàn)證域名
        [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
    } else {
        //不驗(yàn)證域名
        [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
    }

    //設(shè)置需要驗(yàn)證的策略
    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);

    if (self.SSLPinningMode == AFSSLPinningModeNone) {
        //無(wú)條件信任服務(wù)器的證書
        //允許使用過(guò)期或無(wú)效證書 || 服務(wù)器返回的證書可以信任 則返回YES否則NO
        return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
    } else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
        //服務(wù)器返回的證書不通過(guò) && 不允許使用過(guò)期或無(wú)效證書 則不通過(guò)
        return NO;
    }

    
    /*
        代碼走到這里瓤摧、有兩個(gè)條件
        1、驗(yàn)證策略并不是無(wú)條件信任服務(wù)器的證書
        2玉吁、服務(wù)器證書通過(guò)了信任并且不允許使用過(guò)期或無(wú)效的證書
     
        也就是說(shuō)證書沒(méi)問(wèn)題照弥、但是需要進(jìn)一步驗(yàn)證(公鑰或者本地證書)
     */
    
    
    switch (self.SSLPinningMode) {
        case AFSSLPinningModeNone:
        default:
            return NO;
        case AFSSLPinningModeCertificate: {
            //全部檢查
            NSMutableArray *pinnedCertificates = [NSMutableArray array];
            for (NSData *certificateData in self.pinnedCertificates) {
                //將本地的二進(jìn)制證書轉(zhuǎn)化成SecCertificateRef證書并且加入數(shù)組
                [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
            }
            
            //把本地的證書設(shè)為根證書、即服務(wù)器應(yīng)該信任的證書
            SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);

            //看看能否被信任
            if (!AFServerTrustIsValid(serverTrust)) {
                return NO;
            }

            // 取出所有服務(wù)器返回的證書
            NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
            
            //遍歷看看本地證書是否和服務(wù)器證書相同
            for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
                if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
                    return YES;
                }
            }
            
            return NO;
        }
        case AFSSLPinningModePublicKey: {
            NSUInteger trustedPublicKeyCount = 0;
            //取出所有服務(wù)器返回證書的公鑰
            NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);

            for (id trustChainPublicKey in publicKeys) {
                for (id pinnedPublicKey in self.pinnedPublicKeys) {
                    if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
                        trustedPublicKeyCount += 1;
                    }
                }
            }
            //如果有相同的公鑰就通過(guò)
            return trustedPublicKeyCount > 0;
        }
    }
    
    return NO;
}

API注釋Demo

把注釋的源碼放在了github上进副、有興趣可以自取这揣。

GitHub


最后

本文主要是自己的學(xué)習(xí)與總結(jié)悔常。如果文內(nèi)存在紕漏、萬(wàn)望留言斧正给赞。如果不吝賜教小弟更加感謝机打。


參考資料

AFNetworking 3.0 源碼解讀(二)之 AFSecurityPolicy
IOS 條件判斷的幾種形式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市片迅,隨后出現(xiàn)的幾起案子残邀,更是在濱河造成了極大的恐慌,老刑警劉巖柑蛇,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芥挣,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡耻台,警方通過(guò)查閱死者的電腦和手機(jī)空免,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)盆耽,“玉大人蹋砚,你說(shuō)我怎么就攤上這事∩阍樱” “怎么了坝咐?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)匙姜。 經(jīng)常有香客問(wèn)我畅厢,道長(zhǎng),這世上最難降的妖魔是什么氮昧? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任框杜,我火速辦了婚禮,結(jié)果婚禮上袖肥,老公的妹妹穿的比我還像新娘咪辱。我一直安慰自己,他們只是感情好椎组,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布油狂。 她就那樣靜靜地躺著,像睡著了一般寸癌。 火紅的嫁衣襯著肌膚如雪专筷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天蒸苇,我揣著相機(jī)與錄音磷蛹,去河邊找鬼。 笑死溪烤,一個(gè)胖子當(dāng)著我的面吹牛味咳,可吹牛的內(nèi)容都是我干的庇勃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼槽驶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼责嚷!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起掂铐,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤罕拂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后堡纬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體聂受,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年烤镐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蛋济。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡炮叶,死狀恐怖碗旅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情镜悉,我是刑警寧澤祟辟,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站侣肄,受9級(jí)特大地震影響旧困,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜稼锅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一吼具、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧矩距,春花似錦拗盒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至哮肚,卻和暖如春登夫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背允趟。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工恼策, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拼窥。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓戏蔑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鲁纠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子总棵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354