急速開(kāi)發(fā)系列——打造完善的https使用方案

很多文章對(duì)客戶端https的使用都是很模糊的血筑,不但如此枚尼,有些開(kāi)發(fā)者直接從網(wǎng)上拷貝一些使用https的“漏洞”代碼枉阵,無(wú)形之中讓客戶端處在一種高風(fēng)險(xiǎn)的情況下。

今天我們就對(duì)有關(guān)https使用的問(wèn)題進(jìn)行深入的探討技掏,希望能解決以往的困惑铃将。對(duì)于https,需要了解其工作原理的可以參考https是如何工作的哑梳?劲阎,更多關(guān)于https的問(wèn)題我會(huì)站在客戶端的角度在后面陸陸續(xù)續(xù)的寫(xiě)出來(lái)。


證書(shū)鎖定

簡(jiǎn)介

首先來(lái)說(shuō)說(shuō)什么是證書(shū)鎖定鸠真。

證書(shū)鎖定是用來(lái)限制哪些證書(shū)和證書(shū)頒發(fā)機(jī)構(gòu)是可信任的悯仙。需要我們直接在代碼中固定寫(xiě)死使用某個(gè)服務(wù)器的證書(shū),然后用自定義的信任存儲(chǔ)去代替系統(tǒng)系統(tǒng)自帶的吠卷,再去連接我們的服務(wù)器锡垄,我們將這種做法稱之為證書(shū)鎖定。換言之祭隔,證書(shū)鎖定就是在代碼中驗(yàn)證當(dāng)前服務(wù)器是否持有某張指定的證書(shū)货岭,如果不是則強(qiáng)行斷開(kāi)鏈接。

有同學(xué)問(wèn)證書(shū)鎖定有什么好處么?最大的好處使用證書(shū)鎖定提高安全性千贯,降低了成本屯仗。為什么這么說(shuō)呢?如果你想破解該通信搔谴,需要首先拿到客戶端魁袜,然后對(duì)其反編譯,修改后再重新打包簽名敦第,相比原先的做法慌核,這無(wú)疑是增加了破解難度。除了之外申尼,由于證書(shū)鎖定可以使用自簽名的證書(shū),那就意味著我們不需要再向android認(rèn)可的證書(shū)頒發(fā)機(jī)構(gòu)購(gòu)買證書(shū)了垫桂,這樣就可以剩下每年1000多塊錢的證書(shū)費(fèi)用师幕,能省一點(diǎn)就省一點(diǎn)嘛。

retrofit中使用證書(shū)鎖定

現(xiàn)在诬滩,我們來(lái)看看如何在retrofit中進(jìn)行證書(shū)鎖定霹粥。

OkHttpClient client = new OkHttpClient.Builder()
    .certificatePinner(new CertificatePinner.Builder()
            .add("sbbic.com", "sha1/C8xoaOSEzPC6BgGmxAt/EAcsajw=")
            .add("closedevice.com", "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=")
            .build())

通過(guò)上面的代碼不難看出,retrofit中的證書(shū)鎖定同樣是借助OkHttpClient實(shí)現(xiàn)的:通過(guò)為OkHttpClient添加CertificatePinner即可疼鸟。CertificatePinner對(duì)象以構(gòu)建器的方式創(chuàng)建后控,可以通過(guò)其add()方法來(lái)鎖定多個(gè)證書(shū)。

證書(shū)鎖定的原理

現(xiàn)在我們深入下證書(shū)鎖定的原理空镜。我們知道浩淘,無(wú)論http還是https,都是服務(wù)端被動(dòng)吴攒,客戶端主動(dòng)张抄。那么問(wèn)題來(lái)了,客戶端第一次發(fā)出請(qǐng)求之后洼怔,無(wú)法確定服務(wù)端是不是合法的署惯。那么很可能就會(huì)出現(xiàn)以下情景:

正常情況下是這樣,我們想要根據(jù)文章aid查看某篇文章內(nèi)容镣隶,其流程如下:


這里寫(xiě)圖片描述

此時(shí)极谊,如果黑客惡意攔截這個(gè)通信過(guò)程,會(huì)是怎么樣安岂?


這里寫(xiě)圖片描述

此時(shí)惡意服務(wù)端完全可以發(fā)起雙向攻擊:對(duì)上可以欺騙服務(wù)端轻猖,對(duì)下可以欺騙客戶端,更嚴(yán)重的是客戶端段和服務(wù)端完全感知不到已經(jīng)被攻擊了域那。這就是所謂的中間人攻擊蜕依。

中間人攻擊(MITM攻擊)是指,黑客攔截并篡改網(wǎng)絡(luò)中的通信數(shù)據(jù)。又分為被動(dòng)MITM和主動(dòng)MITM样眠,被動(dòng)MITM只竊取通信數(shù)據(jù)而不修改友瘤,而主動(dòng)MITM不當(dāng)能竊取數(shù)據(jù),還會(huì)篡改通信數(shù)據(jù)檐束。最常見(jiàn)的中間人攻擊常常發(fā)生了公共wifi或者公共路由上辫秧,有興趣的私下可以問(wèn)我,這里不做演示了被丧。

現(xiàn)在可以看看證書(shū)鎖定是怎么樣提高安全性盟戏,避免中間人攻擊的,用一張簡(jiǎn)單的流程圖來(lái)說(shuō)明:


這里寫(xiě)圖片描述

不難看出甥桂,通過(guò)證書(shū)鎖定能有有效的避免中間人攻擊柿究。

證書(shū)鎖定的缺點(diǎn)

證書(shū)鎖定盡管帶了較高的安全性,但是這種安全性的提高卻犧牲了靈活性黄选。一旦當(dāng)證書(shū)發(fā)生變化時(shí)蝇摸,我們的客戶端也必須隨之升級(jí),除此之外办陷,我們的服務(wù)端不得不為了兼容以前的客戶端而做出一些妥協(xié)或者說(shuō)直接停用以前的客戶端貌夕,這對(duì)開(kāi)發(fā)者和用戶來(lái)說(shuō)并不是那么的友好。

但實(shí)際上民镜,極少情況下我們才會(huì)變動(dòng)證書(shū)啡专。因此,如果產(chǎn)品安全性要求比較高還是啟動(dòng)證書(shū)鎖定吧制圈。


使用android認(rèn)可的證書(shū)頒發(fā)機(jī)構(gòu)頒發(fā)的證書(shū)

有些同學(xué)可能好奇自己公司中使用https们童,但是在客戶端代碼中并沒(méi)有書(shū)寫(xiě)綁定證書(shū)的代碼?以訪問(wèn)github的代碼為例:

public void loadData() {
        Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/").build();
        GitHubApi api = retrofit.create(GitHubApi.class);

        Call<ResponseBody> call = api.contributorsBySimpleGetCall(mUserName, mRepo);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                // handle response
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                // handle failure
            }
        });
    }

https是如何工作的一文中我們說(shuō)過(guò)android已經(jīng)幫我們預(yù)置了150多個(gè)證書(shū)鲸鹦,這些證書(shū)你可以在設(shè)置->安全->信任的憑據(jù)中看到(在windows中病附,你可以在命令行中打開(kāi)certmgr.msc來(lái)打開(kāi)證書(shū)管理器,這里你可以看看windows預(yù)置的證書(shū))『蓿現(xiàn)在可以明白了完沪,之所以沒(méi)有內(nèi)置證書(shū)的原因在于:我們服務(wù)端用的證書(shū)是從android認(rèn)可的證書(shū)頒發(fā)機(jī)構(gòu)購(gòu)買的證書(shū),在android中已經(jīng)內(nèi)置了這些證書(shū)嵌戈,而默認(rèn)情況下覆积,retrofit 2.0 所依賴的okhttp 3.0 是信任它們,因此可以直接訪問(wèn)而無(wú)需在客戶端設(shè)置什么熟呛。


使用非android認(rèn)可的證書(shū)頒發(fā)機(jī)構(gòu)頒發(fā)的證書(shū)或自簽名證書(shū)

購(gòu)買證書(shū)畢竟是花錢的宽档,現(xiàn)在免費(fèi)的證書(shū)有少之又少,因此使用自簽名證書(shū)就是另外一種常見(jiàn)的方式了庵朝。什么是自簽名證書(shū)呢吗冤?所謂的自簽名證書(shū)就是沒(méi)有通過(guò)受信任的證書(shū)頒發(fā)機(jī)構(gòu)又厉,自己給自己頒發(fā)的證書(shū)(下文中,我將非android認(rèn)可的證書(shū)頒發(fā)機(jī)構(gòu)頒發(fā)的證書(shū)也歸為自簽名證書(shū))椎瘟。最典型的就是12306火車購(gòu)票覆致,使用的證書(shū)就不是受信任的證書(shū)頒發(fā)機(jī)構(gòu)頒發(fā)的,而是旗下SRCA(中鐵數(shù)字證書(shū)認(rèn)證中心肺蔚,簡(jiǎn)稱中鐵CA煌妈,它是鐵道自己搞的機(jī)構(gòu),因此相當(dāng)于自己給自己頒發(fā)證書(shū))頒發(fā)的證書(shū)宣羊,如下圖:

這里寫(xiě)圖片描述

SSL證書(shū)分為三類:

  1. 由android認(rèn)可的證書(shū)頒發(fā)機(jī)構(gòu)或者該結(jié)構(gòu)下屬的機(jī)構(gòu)頒發(fā)的證書(shū)璧诵,比如Symantec,Go Daddy等機(jī)構(gòu),約150多個(gè)仇冯。更多的自行在手機(jī)“設(shè)置->安全->信任的憑據(jù)”中查看

2.沒(méi)有被android所認(rèn)可的證書(shū)所頒發(fā)的證書(shū)

  1. 自己頒發(fā)的證書(shū)

這三類證書(shū)中之宿,只有第一種在使用中不會(huì)出現(xiàn)安全提示,不會(huì)拋出異常苛坚。

由于我們使用的是自簽名的證書(shū)比被,因此客戶端不信任服務(wù)器,會(huì)拋出異常:javax.net.ssl.SSLHandshakeException:.為此炕婶,我們需要自定義信任處理器(TrustManager)來(lái)替代系統(tǒng)默認(rèn)的信任處理器,這樣我們才能正常的使用自定義的正說(shuō)或者非android認(rèn)可的證書(shū)頒發(fā)機(jī)構(gòu)頒發(fā)的證書(shū)莱预。

針對(duì)使用場(chǎng)景柠掂,又分為以下兩種情況:一種是安全性要求不高的情況下,客戶端無(wú)需內(nèi)置證書(shū)依沮;另外一種則是客戶端內(nèi)置證書(shū)涯贞。
下面我會(huì)針對(duì)這兩種情況說(shuō)明其中一些問(wèn)題點(diǎn)。

客戶端不內(nèi)置證書(shū)

我們知道由于我們使用的是自簽名的證書(shū)危喉,所以需要自定義TrustManager,那么很多開(kāi)發(fā)者的處理策略非常簡(jiǎn)單粗暴:讓客戶端不對(duì)服務(wù)器證書(shū)做任何驗(yàn)證宋渔,其實(shí)現(xiàn)代碼如下:

public static SSLSocketFactory getSSLSocketFactory() throws Exception {
        //創(chuàng)建一個(gè)不驗(yàn)證證書(shū)鏈的證書(shū)信任管理器。
        final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[0];
            }
        }};

        // Install the all-trusting trust manager
        final SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAllCerts,
                new java.security.SecureRandom());
        // Create an ssl socket factory with our all-trusting manager
        return sslContext
                .getSocketFactory();
    }
    

  //使用自定義SSLSocketFactory
  private void onHttps(OkHttpClient.Builder builder) {
       try {
            builder.sslSocketFactory(getSSLSocketFactory()).hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }   

上面的代碼不要輕易的應(yīng)用在實(shí)際工程中辜限,除非你能容忍他的危害皇拣。為什么這么說(shuō)呢?繼續(xù)往下看薄嫡。

在上面的代碼中氧急,我們自行實(shí)現(xiàn)X509TrustManager時(shí)并沒(méi)有對(duì)其中三個(gè)核心的方法進(jìn)行 具體實(shí)現(xiàn)(主要是沒(méi)有在checkServerTrusted()驗(yàn)證證書(shū)),這樣做相當(dāng)于直接忽略了檢驗(yàn)服務(wù)端證書(shū)毫深。因此無(wú)論服務(wù)器的證書(shū)如何吩坝,都能建立起https鏈接。

看起來(lái)好像解決了我們的問(wèn)題哑蔫,實(shí)則帶來(lái)更大的危害钉寝。此時(shí)弧呐,雖然能建立HTTPS連接,但是無(wú)形之中間人攻擊打開(kāi)了一道門(mén)嵌纲。此時(shí)俘枫,黑客完全可以攔截到我們的HTTPS請(qǐng)求,然后用偽造的證書(shū)冒充真正服務(wù)端的數(shù)字證書(shū)疹瘦,由于客戶端不對(duì)證書(shū)做驗(yàn)證(也就沒(méi)法判斷服務(wù)端到底是正常的還是偽造的)崩哩,這樣客戶端就會(huì)和黑客的服務(wù)器建立連接。這就相當(dāng)于你以為你對(duì)的對(duì)面是個(gè)美女言沐,卻沒(méi)有想到已經(jīng)被掉包了邓嘹,想想“貍貓換太子”就明白了。(對(duì)這點(diǎn)不明白的同學(xué)险胰,可以參見(jiàn)證書(shū)鎖定中的示例汹押。)

那么怎么避免呢?我們需要在自定義TrustManager時(shí)重寫(xiě)checkServerTrusted()方法起便,并在該方法中校驗(yàn)證書(shū)棚贾,完善后的代碼如下:

    public static SSLSocketFactory getSSLSocketFactory() throws Exception {
        // Create a trust manager that does not validate certificate chains
        final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            //證書(shū)中的公鑰
            public static final String PUB_KEY = "3082010a0282010100d52ff5dd432b3a05113ec1a7065fa5a80308810e4e181cf14f7598c8d553cccb7d5111fdcdb55f6ee84fc92cd594adc1245a9c4cd41cbe407a919c5b4d4a37a012f8834df8cfe947c490464602fc05c18960374198336ba1c2e56d2e984bdfb8683610520e417a1a9a5053a10457355cf45878612f04bb134e3d670cf96c6e598fd0c693308fe3d084a0a91692bbd9722f05852f507d910b782db4ab13a92a7df814ee4304dccdad1b766bb671b6f8de578b7f27e76a2000d8d9e6b429d4fef8ffaa4e8037e167a2ce48752f1435f08923ed7e2dafef52ff30fef9ab66fdb556a82b257443ba30a93fda7a0af20418aa0b45403a2f829ea6e4b8ddbb9987f1bf0203010001";

            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {


            }

            //客戶端并為對(duì)ssl證書(shū)的有效性進(jìn)行校驗(yàn)
            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
                if (chain == null) {
                    throw new IllegalArgumentException("checkServerTrusted:x509Certificate array isnull");
                }

                if (!(chain.length > 0)) {
                    throw new IllegalArgumentException("checkServerTrusted: X509Certificate is empty");
                }

                if (!(null != authType && authType.equalsIgnoreCase("RSA"))) {
                    throw new CertificateException("checkServerTrusted: AuthType is not RSA");
                }

                // Perform customary SSL/TLS checks
                try {
                    TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
                    tmf.init((KeyStore) null);
                    for (TrustManager trustManager : tmf.getTrustManagers()) {
                        ((X509TrustManager) trustManager).checkServerTrusted(chain, authType);
                    }
                } catch (Exception e) {
                    throw new CertificateException(e);
                }
                // Hack ahead: BigInteger and toString(). We know a DER encoded Public Key begins
                // with 0×30 (ASN.1 SEQUENCE and CONSTRUCTED), so there is no leading 0×00 to drop.
                RSAPublicKey pubkey = (RSAPublicKey) chain[0].getPublicKey();

                String encoded = new BigInteger(1 /* positive */, pubkey.getEncoded()).toString(16);
                // Pin it!
                final boolean expected = PUB_KEY.equalsIgnoreCase(encoded);

                if (!expected) {
                    throw new CertificateException("checkServerTrusted: Expected public key: "
                            + PUB_KEY + ", got public key:" + encoded);
                }

            }


            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[0];
            }
        }};

        // Install the all-trusting trust manager
        final SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAllCerts,
                new java.security.SecureRandom());
        // Create an ssl socket factory with our all-trusting manager
        return sslContext
                .getSocketFactory();
    }

其中PUB_KEY是我們證書(shū)中的公鑰,你可以自行從自己的證書(shū)中提取榆综。我們看到妙痹,在checkServerTrusted()方法中,我們通過(guò)證書(shū)的公鑰信息來(lái)確認(rèn)證書(shū)的真?zhèn)伪谴绻?yàn)證失敗怯伊,則中斷請(qǐng)求。當(dāng)然判沟,此處加入證書(shū)的有效期會(huì)更加的完善耿芹,實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單,這里就不做說(shuō)明了挪哄。

除了上面那種在checkServerTrusted()實(shí)現(xiàn)證書(shū)驗(yàn)證的方式之外吧秕,我們也可以利用retrofit中CertificatePinner來(lái)實(shí)現(xiàn)證書(shū)鎖定,同樣也能達(dá)到我們的目的迹炼。

客戶端內(nèi)置證書(shū)

如果我們使用的是自簽名證書(shū)砸彬,那么客戶端中的retrofit該如何進(jìn)行設(shè)置呢?關(guān)鍵還是我們上文提到的TrustManager斯入。在retrofit中使用自簽名證書(shū)大致要經(jīng)過(guò)以下幾步:

  1. 將證書(shū)添加到工程中
  2. 自定義信任管理器TrustManager
  3. 用自定義TrustManager代替系統(tǒng)默認(rèn)的信任管理器

我們按步驟進(jìn)行說(shuō)明拿霉。

添加證書(shū)到工程

比如現(xiàn)在我們有個(gè)證書(shū)media.crt,首先需要將其放在res/raw目錄下咱扣,當(dāng)然你可以可以放在assets目錄下绽淘。

自定義TrustManager

和上面不同的是,這里需要實(shí)現(xiàn)本地證書(shū)的加載闹伪,具體見(jiàn)代碼:

 protected static SSLSocketFactory getSSLSocketFactory(Context context, int[] certificates) {

        if (context == null) {
            throw new NullPointerException("context == null");
        }

        //CertificateFactory用來(lái)證書(shū)生成
        CertificateFactory certificateFactory;
        try {
            certificateFactory = CertificateFactory.getInstance("X.509");
            //Create a KeyStore containing our trusted CAs
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);

            for (int i = 0; i < certificates.length; i++) {
                //讀取本地證書(shū)
                InputStream is = context.getResources().openRawResource(certificates[i]);
                keyStore.setCertificateEntry(String.valueOf(i), certificateFactory.generateCertificate(is));

                if (is != null) {
                    is.close();
                }
            }
            //Create a TrustManager that trusts the CAs in our keyStore
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);

            //Create an SSLContext that uses our TrustManager
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            return sslContext.getSocketFactory();

        } catch (Exception e) {

        }
        return null;
    }

用自定義TrustManager代替系統(tǒng)默認(rèn)的信任管理器

   private void onHttpCertficates(OkHttpClient.Builder builder) {
        int[] certficates = new int[]{R.raw.media};
        builder.socketFactory(getSSLSocketFactory(AppContext.context(), certficates));
    }

這樣我們就可以的客戶端就可以使用自簽名的證書(shū)了沪铭。其實(shí)不難發(fā)現(xiàn)壮池,使用非android認(rèn)證證書(shū)頒發(fā)機(jī)構(gòu)頒發(fā)的證書(shū)的關(guān)鍵在于:修改android中SSLContext自帶的TrustManager以便能讓我們的簽名通過(guò)驗(yàn)證。


暫告一段落

本文中簡(jiǎn)單首先介紹了證書(shū)鎖定的使用杀怠、原理及優(yōu)缺點(diǎn)椰憋,接著對(duì)客戶端使用自定義證書(shū)中的一些點(diǎn)做了介紹,希望能幫助各位打造安全的安卓客戶端赔退。

另外橙依,大多數(shù)情況下,我建議使用證書(shū)鎖定來(lái)提高安全性硕旗。關(guān)于雙向證書(shū)驗(yàn)證窗骑,后續(xù)有時(shí)間再補(bǔ)充。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末漆枚,一起剝皮案震驚了整個(gè)濱河市创译,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌墙基,老刑警劉巖软族,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異残制,居然都是意外死亡立砸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)初茶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)颗祝,“玉大人,你說(shuō)我怎么就攤上這事纺蛆⊥驴” “怎么了规揪?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵桥氏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我猛铅,道長(zhǎng)字支,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任奸忽,我火速辦了婚禮堕伪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘栗菜。我一直安慰自己欠雌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布疙筹。 她就那樣靜靜地躺著富俄,像睡著了一般禁炒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上霍比,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天幕袱,我揣著相機(jī)與錄音,去河邊找鬼悠瞬。 笑死们豌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的浅妆。 我是一名探鬼主播望迎,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼狂打!你這毒婦竟也來(lái)了擂煞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤趴乡,失蹤者是張志新(化名)和其女友劉穎对省,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體晾捏,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蒿涎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惦辛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劳秋。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖胖齐,靈堂內(nèi)的尸體忽然破棺而出玻淑,到底是詐尸還是另有隱情,我是刑警寧澤呀伙,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布补履,位于F島的核電站,受9級(jí)特大地震影響剿另,放射性物質(zhì)發(fā)生泄漏箫锤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一雨女、第九天 我趴在偏房一處隱蔽的房頂上張望谚攒。 院中可真熱鬧,春花似錦氛堕、人聲如沸馏臭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)括儒。三九已至浪耘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間塑崖,已是汗流浹背七冲。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留规婆,地道東北人澜躺。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像抒蚜,于是被迫代替她去往敵國(guó)和親掘鄙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,111評(píng)論 25 707
  • retrofit中如何正確的使用https? 很多文章對(duì)客戶端https的使用都是很模糊的饿这,不但如此浊伙,有些開(kāi)發(fā)者直...
    流水潺湲閱讀 1,214評(píng)論 3 27
  • 目錄 準(zhǔn)備 分析2.1. 三次握手2.2. 創(chuàng)建 HTTP 代理(非必要)2.3. TLS/SSL 握手2.4. ...
    RunAlgorithm閱讀 38,170評(píng)論 12 117
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)长捧,斷路器嚣鄙,智...
    卡卡羅2017閱讀 134,654評(píng)論 18 139
  • 昨天江同學(xué)偷偷的悶在被窩里哭了好幾個(gè)小時(shí)哑子,明明已經(jīng)認(rèn)為自己習(xí)慣了孤獨(dú),習(xí)慣了獨(dú)來(lái)獨(dú)往的她肌割,沒(méi)想到脆弱的神經(jīng)再一次被...
    芃芃女孩閱讀 788評(píng)論 3 9