驗證碼WEB端產(chǎn)品調(diào)研(二):極限驗證

本文是驗證碼系列的第二篇铺韧。筆者的寫作順序基于心中排名,所以這次為大家?guī)淼氖菢O限驗證——GeeTest蟹略。

寫到這里可能會有人質(zhì)疑:難道阿里登失、騰訊、網(wǎng)易(以下簡稱ATN)的名氣和實力不是比極驗強嗎挖炬?不可否認揽浙,但我們討論的只是驗證碼:

  • 邏輯上,知名度高意敛,綜合實力強馅巷,不代表垂直領(lǐng)域?qū)嵙σ惨欢◤?/strong>——當(dāng)然,并不否認ATN具備這樣的人才和實力草姻。這應(yīng)該很好理解钓猬。玩吉他的人都知道YAMAHA,但YAMAHA的吉他卻不見得是最好的——大師可能更喜歡Martin or Taylor撩独,或者純私人訂制敞曹。換句話說:如果你有一把YAMAHA FG730,發(fā)朋友圈會有很多人點贊豎大拇指综膀,但是也有人會給你一個手動微笑澳迫。

  • 市場上,極驗在驗證碼領(lǐng)域已深耕多年剧劝,合作伙伴從直播纲刀、金融、電商担平,到資訊示绊、游戲、航旅暂论,甚至...政府面褐,且號稱有16w家企業(yè)正在使用。實力和人脈取胎,可見一斑展哭;而ATN的驗證碼服務(wù)只是其云平臺下的一個分支,官網(wǎng)均未專門介紹具體合作方和數(shù)量闻蛀。筆者雖沒有詳實的數(shù)據(jù)證明ATN接入方比極驗少匪傍,但從個人上網(wǎng)經(jīng)歷來看,極驗顯然更“面熟”觉痛。起碼簡書都在用了役衡。具體極驗官網(wǎng)可查詢,一張圖感受下:

優(yōu)勢往往就是這樣建立并擴大的:當(dāng)你和一個行業(yè)的Top 3合作愉快的時候

遺憾的是薪棒,極驗并沒有給筆者任何軟文費手蝎。鑒于此便不再繼續(xù)吹了。下面還是從產(chǎn)品和技術(shù)層面聊一聊俐芯。

產(chǎn)品背景

極驗?zāi)壳暗漠a(chǎn)品已經(jīng)升級為3.0:


其實這三代的產(chǎn)品棵介,目前是共存的勢態(tài):

存在即合理

1.0

1.0代表的是鍵盤輸入型字符驗證碼,開發(fā)成本低吧史,常用開源框架即可搞定(如Kaptcha 邮辽、JCaptcha)。其設(shè)計思路就一點:
如何讓生成的問題人可以解答贸营,而機器不可以


因此傳統(tǒng)驗證碼勢必要在讓機器感到壓力山大的事情上做文章吨述。但純圖片上做的文章,總是可以一物降一物:
左側(cè)是驗證碼常用技術(shù)莽使,右側(cè)是對應(yīng)的破解方法

當(dāng)網(wǎng)站本身被頻繁突破意義不大時锐极,自然不用考慮這些對抗上的“短兵相接”。但就此類驗證碼而言芳肌,最明顯的問題是:

  • 每次都要敲鍵盤輸入
  • 為了防范圖像識別破解灵再,便增大識別難度,導(dǎo)致有時候人都難以識別

更有甚者直接利用“人類(大學(xué)生或許更準(zhǔn)確)目前在認知學(xué)上對機器的優(yōu)勢“亿笤,在圖片上直接祭出了高數(shù)翎迁,將反人類做到極致:


當(dāng)然,上圖可能只是一個段子净薛⊥衾疲總之極驗官網(wǎng)已經(jīng)號稱對此沒有興趣:字符驗證碼不在服務(wù)范圍。而這也是大勢所趨:驗證碼本身沒有任何商業(yè)價值肃拜,為了阻擋機器會自帶反人類屬性痴腌。因此設(shè)計時一定要同時兼顧安全和用戶體驗雌团。對于一些電商類的網(wǎng)站,用戶體驗甚至是擺在首位的士聪。

2.0

2.0產(chǎn)品锦援,極驗稱其為”行為式驗證“。代表作是滑動拼圖驗證碼剥悟。目前也是各大驗證碼平臺的標(biāo)配:


為什么官網(wǎng)2.0的配圖不是點選驗證碼灵寺?點選同樣是標(biāo)配,極驗也有這款產(chǎn)品:

筆者認為区岗,主要原因是:
1)體驗不如滑動——點擊雖然比輸入更便捷略板,但識別文字依然要花大量時間,尤其是當(dāng)備選漢字遠多于待驗證漢字慈缔。
2)安全性不輸于滑動(如果設(shè)計足夠好)叮称,但其原理并非潮流所向——想要破解,首先要能摳出圖片中的漢字胀糜,保證所有的漢字都被識別颅拦,且能夠順序和待驗證漢字對上。這里窮舉法(隨便點三個)是沒有用的教藻,或者說成功概率很芯嗨А(1/P(n,m))。因為只要錯一個字就會刷新括堤÷到眨可以看出,其校驗原理更側(cè)重前端展示悄窃,并不過分依賴行為分析讥电。既讓用戶可見,又要在可見基礎(chǔ)上安全轧抗,就勢必帶來體驗的下降恩敌,這還是和字符驗證碼有殊途同歸的意思。
所以2.0強調(diào)行為横媚,也是基于思路的轉(zhuǎn)換:弱化前端展示纠炮,強化后臺分析,在不可見之處強化安全灯蝴。
對滑動拼圖而言恢口,滑到正確位置只是一個必要條件,用戶行為特征的提取才是核心穷躁。通過采集并分析用戶使用鼠標(biāo)拖動滑塊的行為特征(速度耕肩、頻率、耗時等)來判定是人還是機器。對用戶來說猿诸,體驗上比輸入或點選字符要更輕松愉快婚被,還兼具一定趣味性。但是便捷性往往和安全性相沖突:理論上只要機器模擬出人的行為两芳,就可以繞過驗證(有人可能會第一時間聯(lián)想到按鍵精靈)摔寨。其實是否輕松,就看對行為判定是否精準(zhǔn)了怖辆。這類判定,可以基于一些固定的規(guī)則(如滑動時間小于某個閾值)删顶,也可以引入機器學(xué)習(xí)分析特征量(如Kmeans做聚類分析)竖螃,看各家的思路和實力了。未來這些偏后端的技術(shù)才是賣點逗余,也不會輕易開源特咆。因此此類驗證碼更多還是各類驗證碼平臺提供,接入是有償?shù)摹?br> 知乎上有一位叫@darbra的兄弟录粱,對破解極驗2.0產(chǎn)品饒有興趣腻格。他總結(jié)出了selenium大法 和 requests基本法,號稱破率分別是98%和80%啥繁。其Github上的代碼7.4還有更新菜职。有興趣的讀者可以嘗試。

3.0

3.0時代則伴隨著人工智能的浪潮全面進化旗闽,強調(diào)的則是進一步弱化前端+強化機器學(xué)習(xí)酬核。前端越簡單越好,一個按鈕适室,一個滑塊嫡意,一個復(fù)選框即可,甚至...nothing捣辆。個人認為蔬螟,目前只有三家公司在這方面引領(lǐng)市場:Google,極驗和阿里汽畴。

1)Google第一篇已經(jīng)畫了大量篇幅介紹旧巾,已經(jīng)進化到“化無形為有形”的invisible reCAPTCHA,驗證碼實體完全透明整袁,是目前來說產(chǎn)品理念上最領(lǐng)先的(技術(shù)上就不談了)菠齿。
2)阿里和極驗是第二檔,區(qū)別在于一個是滑塊坐昙,一個是按鈕绳匀。相當(dāng)于Google的noCAPTCHA產(chǎn)品。



極驗的3.0產(chǎn)品思想,其實是官網(wǎng)提到的“驗證碼形如按鈕疾棵,更像按鈕一樣百搭”——也就是說這個按鈕會一直存在戈钢,只不過普通合法用戶,需要多點一下它來進行人機識別罷了是尔。只有非法用戶時才會出現(xiàn)滑動拼圖或圖文點選驗證殉了。
如果極驗有4.0,筆者大膽推測方向是invisible拟枚。
技術(shù)層面則強調(diào)使用了人工智能——其實各公司對應(yīng)的2.0產(chǎn)品薪铜,應(yīng)該都用到了。按照極驗官方的說法:
惡意程序模仿人類行為軌跡對驗證碼進行破解針對模擬恩溅,極驗擁有超過4000萬人機行為樣本的海量數(shù)據(jù)利用機器學(xué)習(xí)和神經(jīng)網(wǎng)絡(luò)構(gòu)建線上線下的多重靜態(tài)隔箍、動態(tài)防御模型識別模擬軌跡,界定人機邊界
極驗很可能是加強了人工智能的投入:例如新增更多特征量脚乡,優(yōu)化識別算法等蜒滩。畢竟機器學(xué)習(xí)還是一個數(shù)據(jù)為王的技術(shù),沒有足夠多的訓(xùn)練樣本是無法做到足夠精準(zhǔn)的奶稠。所以以極驗?zāi)壳暗氖袌龇蓊~俯艰,是有這個實力優(yōu)化的。但是加強了多少锌订,效果如何竹握,目前并沒有太好的印證方式,畢竟今年4月才上線瀑志∩辏看后期市場的反饋如何吧。

接入方式

同Google一樣劈猪,極驗的接入方式也如其UI一樣:清爽簡潔
按官網(wǎng)的說法:

  1. 引入初始化函數(shù)
<script src="gt.js"></script>
  1. 調(diào)用初始化函數(shù)進行初始化
initGeetest({
    // 以下配置參數(shù)來自服務(wù)端 SDK
    gt: data.gt,
    challenge: data.challenge,
    offline: !data.success,
    new_captcha: data.new_captcha
}, function (captchaObj) {
    // 這里可以調(diào)用驗證實例 captchaObj 的實例方法
})

結(jié)合配置參數(shù):


看似非常多昧甘,其實只有前面四個是必須,后面都是定制战得,按默認來均可不填充边。這樣的參數(shù)配置,作為一家專業(yè)驗證碼公司常侦,還是十分合理的——既要考慮到宕機問題浇冰,又得支持顧客的個性化需求。
參數(shù)含義聋亡,文檔已經(jīng)介紹的十分詳細肘习,Markdown排版閱讀起來也很舒適,筆者便不再贅言坡倔。值得一提的是漂佩,第二個參數(shù)challenge脖含,在前面介紹的Google驗證碼參數(shù)也出現(xiàn)過,且含義基本一樣投蝉⊙可能一半借鑒,一半致敬吧瘩缆。

源碼分析

細心的朋友會發(fā)現(xiàn)关拒,步驟1中加載的是一個本地路徑的gt.js,而非從極驗服務(wù)器加載庸娱。按一般驗證碼公司的做法着绊,給出一個http://static.geetest.com/static/tools/gt.js 就夠了。極驗則考慮到了failover層面——如果自己服務(wù)器故障怎么辦涌韩?在目前機房容災(zāi)能力越來越強的今天畔柔,這么考慮仍然是一種非常專業(yè)和負責(zé)的做法。online offline皆可進行驗證臣樱,這恰恰也是極驗有別于其他驗證碼的特點之一。

下面還是回到gt.js——最近喜歡看源碼腮考。雖然筆者前端經(jīng)驗并不豐富雇毫,但是覺得有趣的東西,還是忍不住分享:

gt.js的主要功能是定義初始化驗證碼的函數(shù)initGeetest踩蔚。

最開始的地方如下:

"v0.4.6 Geetest Inc.";

(function (window) {
    "use strict";
    if (typeof window === 'undefined') {
        throw new Error('Geetest requires browser environment');
    }

……
})(window);

"v0.4.6 Geetest Inc."行首直接字符串秀出版本號和公司棚放,一目了然。
這種重點要說的是"use strict"馅闽。

嚴以律己飘蚯,寬以待人

"use strict",嚴格模式福也,是Javascript非常好的一個特性局骤,可能會大大節(jié)約你查錯的時間。
先舉個例子:

var zombie = {
    eyeLeft : 0,
    eyeRight: 1,
    // ... a lot of keys ...
    eyeLeft : 1
}
mingo= 5;
  1. eyeLeft出現(xiàn)了兩次暴凑,你打算用哪個峦甩?
  2. mingo會是一個全局變量,如果被用于各種嵌套循環(huán)中會怎樣现喳?

這段代碼嚴格模式下會拋出兩個錯誤凯傲,而非嚴格模式不會報。
它以嚴格換來了如下好處嗦篱,主要是以下兩點:

  • 消除語法的一些不嚴謹之處冰单,減少怪異行為
  • 消除代碼運行的一些不安全之處
    最初網(wǎng)景在開發(fā)JavaScript可能存在一些考慮不周的情況,一些模棱兩可的特性被人詬病灸促,新手可能分不清是語法糖還是語法坑诫欠。
    user stick便是語言成熟化的一個方向涵卵。畢竟JavaScript將來會是一種全棧語言,尤其是在服務(wù)端Node.js逐漸強勢的今天呕诉。

好像扯遠了缘厢。其實筆者想說的是極驗代碼寫的非常嚴謹。有一個細節(jié):

var loadScript = function (url, cb) {
    var script = document.createElement("script");
    script.charset = "UTF-8";
    script.async = true;

    script.onerror = function () {
        cb(true);
    };
    var loaded = false;
    script.onload = script.onreadystatechange = function () {
        if (!loaded &&
            (!script.readyState ||
            "loaded" === script.readyState ||
            "complete" === script.readyState)) {

            loaded = true;
            setTimeout(function () {
                cb(false);
            }, 0);
        }
    };
    script.src = url;
    head.appendChild(script);
};

不知該寫法應(yīng)該是參考了JQuery如下源碼:

callback = errorCallback = xhr.onload =
                                xhr.onerror = xhr.onabort = xhr.onreadystatechange = null

這么寫主要還是因為:
IE的 script 元素支持onreadystatechange事件甩挫,不支持onload事件贴硫。FF則正好相反
如果要在一個<script src="x.js"> 加載完成執(zhí)行一個操作,F(xiàn)F使用onload事件就行了伊者,IE下則要結(jié)合onreadystatechange事件和this.readyState英遭。所以:

script.onload = script.onreadystatechange = function(){

     if(  ! this.readyState     //這是FF的判斷語句,因為ff下沒有readyState亦渗,IE的readyState肯定有值
          || this.readyState=='loaded' || this.readyState=='complete'   //這是IE的判斷語句
    ){
          alert('loaded');
    }

};

此外還有一個細節(jié):
gt.js有一個盡量利用多CDN挖诸,使靜態(tài)文件盡可能加載成功的機制:

fallback_config: {
        slide: {
            static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
            type: 'slide',
            slide: '/static/js/geetest.0.0.0.js'
        },
        fullpage: {
            static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
            type: 'fullpage',
            fullpage: '/static/js/fullpage.0.0.0.js'
        }
    }

其目的是加載滑動和點選的widget。在fullpage.js(已混淆)開頭可見以下寫法:

!function (a, b) {
  'use strict';
  'object' == typeof module && 'object' == typeof module.exports ? module.exports = a.document ? b(a, !0)  : function (a) {
    if (!a.document) throw new Error('Geetest requires a window with a document');
    return b(a)
  }
   : b(a)
}('undefined' != typeof window ? window : this, function (a, b) {
……
}

今天天氣不錯多律,挺風(fēng)和日麗的

這一段讓筆者想起中學(xué)時寫作的范文——JQuery就是這么玩的。JQuery向來以嚴謹和兼容性強大著稱搂蜓,究其根本是寫法的包容性狼荞。大家可以對照看一下其的源碼開頭,以最新版本為例:

/*!
 * jQuery JavaScript Library v3.2.1
 * https://jquery.com/
 *
 * Includes Sizzle.js
 * https://sizzlejs.com/
 *
 * Copyright JS Foundation and other contributors
 * Released under the MIT license
 * https://jquery.org/license
 *
 * Date: 2017-03-20T18:59Z
 */
( function( global, factory ) {

    "use strict";

    if ( typeof module === "object" && typeof module.exports === "object" ) {

        // For CommonJS and CommonJS-like environments where a proper `window`
        // is present, execute the factory and get jQuery.
        // For environments that do not have a `window` with a `document`
        // (such as Node.js), expose a factory as module.exports.
        // This accentuates the need for the creation of a real `window`.
        // e.g. var jQuery = require("jquery")(window);
        // See ticket #14549 for more info.
        module.exports = global.document ?
            factory( global, true ) :
            function( w ) {
                if ( !w.document ) {
                    throw new Error( "jQuery requires a window with a document" );
                }
                return factory( w );
            };
    } else {
        factory( global );
    }

// Pass this if window is not defined yet
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {

// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
// enough that all such attempts are guarded in a try block.
"use strict";

這里其實是一個閉包(Closures)“锱觯現(xiàn)今流行的一些 JS 庫中經(jīng)常見到以下形式的代碼相味。在閉包中,可以定義私有變量和函數(shù)殉挽,外部無法訪問它們丰涉,從而做到了私有成員的隱藏和隔離。而通過返回對象或函數(shù)斯碌,或是將某對象作為參數(shù)傳入一死,在函數(shù)體內(nèi)對該對象進行操作,就可以公開希望對外暴露的方法與數(shù)據(jù)输拇。

JQuery這一段的目的摘符,注釋已經(jīng)寫得非常清楚。其實就是為了保證不污染全局變量策吠,將所有的對象及方法創(chuàng)建都放到了factory函數(shù)中執(zhí)行逛裤。通過形參global來傳遞window變量,在利用factory創(chuàng)建jQuery對象以前猴抹,首先進行window變量的檢測带族。
module 和 module.exports主要是為了讓jQuery能夠以模塊的形式(如CMD)注入到?jīng)]有window.document變量的諸如Node.js的運行環(huán)境中,當(dāng)遇到這種情況蟀给,就不會在window中設(shè)置jQuery$變量蝙砌。要使用jQuery時阳堕,則是使用所返回的jQuery對象,如在Node.js中:
var jQuery = require("jquery")(window);
所以極限以"范文"開頭择克,也是考慮了同樣的事情恬总。

最后還是聊一聊UBC的部分(寫累了,突然想裝13)——筆者曾在阿里驗證碼里看到了一個類似的文件肚邢,所以對這個縮寫印象深刻——其實就是User Behavior Collection壹堰,給到后端做人機識別用。極驗的UBC在http://apiguard.geetest.com/dist/geeguard.js 這里骡湖。其實做的事情就是用戶行為收集贱纠。
老套路,先搜一波userAgent——為什么响蕴?因為做這件事情必須要瀏覽器指紋谆焊,否則無法鎖定設(shè)備,也就缺少了一個關(guān)鍵風(fēng)控維度浦夷。
不出意料可以看到這樣一段代碼:

 '_getKeys': function () {
      return ['textLength',
      'HTMLLength',
      'documentMode'].concat(this._tagKeys).concat(['screenLeft',
      'screenTop',
      'screenAvailLeft',
      'screenAvailTop',
      'innerWidth',
      'innerHeight',
      'outerWidth',
      'outerHeight',
      'browserLanguage',
      'browserLanguages',
      'systemLanguage',
      'devicePixelRatio',
      'colorDepth',
      'userAgent',
      'cookieEnabled',
      'netEnabled',
      'screenWidth',
      'screenHeight',
      'screenAvailWidth',
      'screenAvailHeight',
      'localStorageEnabled',
      'sessionStorageEnabled',
      'indexedDBEnabled',
      'CPUClass',
      'platform',
      'doNotTrack',
      'timezone',
      'canvas2DFP',
      'canvas3DFP',
      'plugins',
      'maxTouchPoints',
      'flashEnabled',
      'javaEnabled',
      'hardwareConcurrency',
      'jsFonts',
      'timestamp',
      'performanceTiming'])
    },

其實這段代碼就是基于多維度給瀏覽器采集一個指紋辖试。Github上有一款開源Js叫
fingerprintjs,目前已經(jīng)出了第二版劈狐,定位就是Modern & flexible browser fingerprinting library剃执,功能是一樣的,如下:

    get: function(done){
      var keys = [];
      keys = this.userAgentKey(keys);
      keys = this.languageKey(keys);
      keys = this.colorDepthKey(keys);
      keys = this.pixelRatioKey(keys);
      keys = this.hardwareConcurrencyKey(keys);
      keys = this.screenResolutionKey(keys);
      keys = this.availableScreenResolutionKey(keys);
      keys = this.timezoneOffsetKey(keys);
      keys = this.sessionStorageKey(keys);
      keys = this.localStorageKey(keys);
      keys = this.indexedDbKey(keys);
      keys = this.addBehaviorKey(keys);
      keys = this.openDatabaseKey(keys);
      keys = this.cpuClassKey(keys);
      keys = this.platformKey(keys);
      keys = this.doNotTrackKey(keys);
      keys = this.pluginsKey(keys);
      keys = this.canvasKey(keys);
      keys = this.webglKey(keys);
      keys = this.adBlockKey(keys);
      keys = this.hasLiedLanguagesKey(keys);
      keys = this.hasLiedResolutionKey(keys);
      keys = this.hasLiedOsKey(keys);
      keys = this.hasLiedBrowserKey(keys);
      keys = this.touchSupportKey(keys);
      keys = this.customEntropyFunction(keys);
      var that = this;
      this.fontsKey(keys, function(newKeys){
        var values = [];
        that.each(newKeys, function(pair) {
          var value = pair.value;
          if (typeof pair.value.join !== "undefined") {
            value = pair.value.join(";");
          }
          values.push(value);
        });
        var murmur = that.x64hash128(values.join("~~~"), 31);
        return done(murmur, newKeys);
      });
}

有興趣的讀者可以試著了解懈息。

總結(jié)

個人觀點:極驗是國內(nèi)目前最好的驗證碼產(chǎn)品——不論是產(chǎn)品設(shè)計、文檔風(fēng)格摹恰、還是代碼專業(yè)性辫继。這么說是因為,其他平臺俗慈,鮮有這幾方面都不錯的姑宽。例如阿里最大的問題就是接入配置較為復(fù)雜(接入頁面插入多段代碼);網(wǎng)易則是點選驗證碼圖文結(jié)合過于丑陋闺阱,無視審美炮车;點觸文檔排版不佳...諸如此類。
另外一個好感的原因酣溃,可能是筆者坐標(biāo)武漢瘦穆,明白在武漢做互聯(lián)網(wǎng)之不易。不管是政府扶持力度赊豌,還是人才凝聚力扛或,都和一線城市有差距。

希望極驗越做越好碘饼。

后續(xù)不打算再介紹其他平臺的驗證碼熙兔。一來都大同小異悲伶,其他平臺亮點不多,反復(fù)論述意義不大住涉;二來自身疲乏麸锉,想轉(zhuǎn)移一下興趣點。下一篇可能會介紹機器學(xué)習(xí)在人機識別中的簡單應(yīng)用舆声。鄙人新手花沉,如有翻車,老司機多多包涵扶正纳寂。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末主穗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子毙芜,更是在濱河造成了極大的恐慌忽媒,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腋粥,死亡現(xiàn)場離奇詭異晦雨,居然都是意外死亡,警方通過查閱死者的電腦和手機隘冲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門闹瞧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人展辞,你說我怎么就攤上這事奥邮。” “怎么了罗珍?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵洽腺,是天一觀的道長。 經(jīng)常有香客問我覆旱,道長蘸朋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任扣唱,我火速辦了婚禮藕坯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘噪沙。我一直安慰自己炼彪,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布曲聂。 她就那樣靜靜地躺著霹购,像睡著了一般。 火紅的嫁衣襯著肌膚如雪朋腋。 梳的紋絲不亂的頭發(fā)上齐疙,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天膜楷,我揣著相機與錄音,去河邊找鬼贞奋。 笑死赌厅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的轿塔。 我是一名探鬼主播特愿,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼勾缭!你這毒婦竟也來了揍障?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤俩由,失蹤者是張志新(化名)和其女友劉穎毒嫡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體幻梯,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡兜畸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了碘梢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咬摇。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖煞躬,靈堂內(nèi)的尸體忽然破棺而出肛鹏,到底是詐尸還是另有隱情,我是刑警寧澤恩沛,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布龄坪,位于F島的核電站,受9級特大地震影響复唤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜烛卧,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一佛纫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧总放,春花似錦呈宇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至炬搭,卻和暖如春蜈漓,著一層夾襖步出監(jiān)牢的瞬間穆桂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工融虽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留享完,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓有额,卻偏偏與公主長得像般又,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子巍佑,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

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