Home | History | Annotate | Download | only in safe_browsing
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 
      6 #include "base/logging.h"
      7 #include "base/time.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 #include "chrome/browser/safe_browsing/protocol_manager.h"
     10 
     11 using base::Time;
     12 using base::TimeDelta;
     13 
     14 static const char kInfoUrlPrefix[] = "http://info.prefix.com/foo";
     15 static const char kMacKeyUrlPrefix[] = "https://key.prefix.com/bar";
     16 static const char kClient[] = "unittest";
     17 static const char kAppVer[] = "1.0";
     18 static const char kClientKey[] = "SCg9lcLHd0dfksXgYsacwQ==";
     19 static const char kWrappedKey[] =
     20     "AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8nNaYH47tiQ7pDe9cEErjVHGZaPPUau5h61tbXSDqA"
     21     "BiJZnDFByc_g8B5vTwxkhBf9g==";
     22 static const char kAdditionalQuery[] = "additional_query";
     23 
     24 class SafeBrowsingProtocolManagerTest : public testing::Test {
     25 };
     26 
     27 // Ensure that we respect section 5 of the SafeBrowsing protocol specification.
     28 TEST_F(SafeBrowsingProtocolManagerTest, TestBackOffTimes) {
     29   SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
     30                                  kInfoUrlPrefix, kMacKeyUrlPrefix, false);
     31   pm.next_update_sec_ = 1800;
     32   DCHECK(pm.back_off_fuzz_ >= 0.0 && pm.back_off_fuzz_ <= 1.0);
     33 
     34   // No errors received so far.
     35   EXPECT_EQ(pm.GetNextUpdateTime(false), 1800 * 1000);
     36 
     37   // 1 error.
     38   EXPECT_EQ(pm.GetNextUpdateTime(true), 60 * 1000);
     39 
     40   // 2 errors.
     41   int next_time = pm.GetNextUpdateTime(true) / (60 * 1000);  // Minutes
     42   EXPECT_TRUE(next_time >= 30 && next_time <= 60);
     43 
     44   // 3 errors.
     45   next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
     46   EXPECT_TRUE(next_time >= 60 && next_time <= 120);
     47 
     48   // 4 errors.
     49   next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
     50   EXPECT_TRUE(next_time >= 120 && next_time <= 240);
     51 
     52   // 5 errors.
     53   next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
     54   EXPECT_TRUE(next_time >= 240 && next_time <= 480);
     55 
     56   // 6 errors, reached max backoff.
     57   EXPECT_EQ(pm.GetNextUpdateTime(true), 480 * 60 * 1000);
     58 
     59   // 7 errors.
     60   EXPECT_EQ(pm.GetNextUpdateTime(true), 480 * 60 * 1000);
     61 
     62   // Received a successful response.
     63   EXPECT_EQ(pm.GetNextUpdateTime(false), 1800 * 1000);
     64 }
     65 
     66 // Test string combinations with and without MAC.
     67 TEST_F(SafeBrowsingProtocolManagerTest, TestChunkStrings) {
     68   SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
     69                                  kInfoUrlPrefix, kMacKeyUrlPrefix, false);
     70 
     71   // Add and Sub chunks.
     72   SBListChunkRanges phish("goog-phish-shavar");
     73   phish.adds = "1,4,6,8-20,99";
     74   phish.subs = "16,32,64-96";
     75   EXPECT_EQ(pm.FormatList(phish, false),
     76             "goog-phish-shavar;a:1,4,6,8-20,99:s:16,32,64-96\n");
     77   EXPECT_EQ(pm.FormatList(phish, true),
     78             "goog-phish-shavar;a:1,4,6,8-20,99:s:16,32,64-96:mac\n");
     79 
     80   // Add chunks only.
     81   phish.subs = "";
     82   EXPECT_EQ(pm.FormatList(phish, false),
     83             "goog-phish-shavar;a:1,4,6,8-20,99\n");
     84   EXPECT_EQ(pm.FormatList(phish, true),
     85             "goog-phish-shavar;a:1,4,6,8-20,99:mac\n");
     86 
     87   // Sub chunks only.
     88   phish.adds = "";
     89   phish.subs = "16,32,64-96";
     90   EXPECT_EQ(pm.FormatList(phish, false), "goog-phish-shavar;s:16,32,64-96\n");
     91   EXPECT_EQ(pm.FormatList(phish, true),
     92             "goog-phish-shavar;s:16,32,64-96:mac\n");
     93 
     94   // No chunks of either type.
     95   phish.adds = "";
     96   phish.subs = "";
     97   EXPECT_EQ(pm.FormatList(phish, false), "goog-phish-shavar;\n");
     98   EXPECT_EQ(pm.FormatList(phish, true), "goog-phish-shavar;mac\n");
     99 }
    100 
    101 TEST_F(SafeBrowsingProtocolManagerTest, TestGetHashBackOffTimes) {
    102   SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
    103                                  kInfoUrlPrefix, kMacKeyUrlPrefix, false);
    104 
    105   // No errors or back off time yet.
    106   EXPECT_EQ(pm.gethash_error_count_, 0);
    107   EXPECT_TRUE(pm.next_gethash_time_.is_null());
    108 
    109   Time now = Time::Now();
    110 
    111   // 1 error.
    112   pm.HandleGetHashError(now);
    113   EXPECT_EQ(pm.gethash_error_count_, 1);
    114   TimeDelta margin = TimeDelta::FromSeconds(5);  // Fudge factor.
    115   Time future = now + TimeDelta::FromMinutes(1);
    116   EXPECT_TRUE(pm.next_gethash_time_ >= future - margin &&
    117               pm.next_gethash_time_ <= future + margin);
    118 
    119   // 2 errors.
    120   pm.HandleGetHashError(now);
    121   EXPECT_EQ(pm.gethash_error_count_, 2);
    122   EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(30));
    123   EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(60));
    124 
    125   // 3 errors.
    126   pm.HandleGetHashError(now);
    127   EXPECT_EQ(pm.gethash_error_count_, 3);
    128   EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(60));
    129   EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(120));
    130 
    131   // 4 errors.
    132   pm.HandleGetHashError(now);
    133   EXPECT_EQ(pm.gethash_error_count_, 4);
    134   EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(120));
    135   EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(240));
    136 
    137   // 5 errors.
    138   pm.HandleGetHashError(now);
    139   EXPECT_EQ(pm.gethash_error_count_, 5);
    140   EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(240));
    141   EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(480));
    142 
    143   // 6 errors, reached max backoff.
    144   pm.HandleGetHashError(now);
    145   EXPECT_EQ(pm.gethash_error_count_, 6);
    146   EXPECT_TRUE(pm.next_gethash_time_ == now + TimeDelta::FromMinutes(480));
    147 
    148   // 7 errors.
    149   pm.HandleGetHashError(now);
    150   EXPECT_EQ(pm.gethash_error_count_, 7);
    151   EXPECT_TRUE(pm.next_gethash_time_== now + TimeDelta::FromMinutes(480));
    152 }
    153 
    154 TEST_F(SafeBrowsingProtocolManagerTest, TestGetHashUrl) {
    155   SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
    156                                  kInfoUrlPrefix, kMacKeyUrlPrefix, false);
    157   pm.version_ = kAppVer;
    158   EXPECT_EQ("http://info.prefix.com/foo/gethash?client=unittest&appver=1.0&"
    159             "pver=2.2", pm.GetHashUrl(false).spec());
    160   EXPECT_EQ("http://info.prefix.com/foo/gethash?client=unittest&appver=1.0&"
    161             "pver=2.2&wrkey=AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8nNaYH47tiQ7pDe9cE"
    162             "ErjVHGZaPPUau5h61tbXSDqABiJZnDFByc_g8B5vTwxkhBf9g==",
    163             pm.GetHashUrl(true).spec());
    164 
    165   pm.set_additional_query(kAdditionalQuery);
    166   EXPECT_EQ("http://info.prefix.com/foo/gethash?client=unittest&appver=1.0&"
    167             "pver=2.2&additional_query",
    168             pm.GetHashUrl(false).spec());
    169   EXPECT_EQ("http://info.prefix.com/foo/gethash?client=unittest&appver=1.0&"
    170             "pver=2.2&additional_query&wrkey=AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8"
    171             "nNaYH47tiQ7pDe9cEErjVHGZaPPUau5h61tbXSDqABiJZnDFByc_g8B5vTwxkhBf"
    172             "9g==", pm.GetHashUrl(true).spec());
    173 }
    174 
    175 TEST_F(SafeBrowsingProtocolManagerTest, TestUpdateUrl) {
    176   SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
    177                                  kInfoUrlPrefix, kMacKeyUrlPrefix, false);
    178   pm.version_ = kAppVer;
    179 
    180   EXPECT_EQ("http://info.prefix.com/foo/downloads?client=unittest&appver=1.0&"
    181             "pver=2.2", pm.UpdateUrl(false).spec());
    182   EXPECT_EQ("http://info.prefix.com/foo/downloads?client=unittest&appver=1.0&"
    183             "pver=2.2&wrkey=AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8nNaYH47tiQ7pDe9cE"
    184             "ErjVHGZaPPUau5h61tbXSDqABiJZnDFByc_g8B5vTwxkhBf9g==",
    185             pm.UpdateUrl(true).spec());
    186 
    187   pm.set_additional_query(kAdditionalQuery);
    188   EXPECT_EQ("http://info.prefix.com/foo/downloads?client=unittest&appver=1.0&"
    189             "pver=2.2&additional_query", pm.UpdateUrl(false).spec());
    190   EXPECT_EQ("http://info.prefix.com/foo/downloads?client=unittest&appver=1.0&"
    191             "pver=2.2&additional_query&wrkey=AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8"
    192             "nNaYH47tiQ7pDe9cEErjVHGZaPPUau5h61tbXSDqABiJZnDFByc_g8B5vTwxkhBf"
    193             "9g==", pm.UpdateUrl(true).spec());
    194 }
    195 
    196 TEST_F(SafeBrowsingProtocolManagerTest, TestSafeBrowsingHitUrl) {
    197   SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
    198                                  kInfoUrlPrefix, kMacKeyUrlPrefix, false);
    199   pm.version_ = kAppVer;
    200 
    201   GURL malicious_url("http://malicious.url.com");
    202   GURL page_url("http://page.url.com");
    203   GURL referrer_url("http://referrer.url.com");
    204   EXPECT_EQ("http://info.prefix.com/foo/report?client=unittest&appver=1.0&"
    205             "pver=2.2&evts=malblhit&evtd=http%3A%2F%2Fmalicious.url.com%2F&"
    206             "evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
    207             "url.com%2F&evtb=1",
    208             pm.SafeBrowsingHitUrl(
    209                 malicious_url, page_url, referrer_url,
    210                 true, SafeBrowsingService::URL_MALWARE).spec());
    211 
    212   pm.set_additional_query(kAdditionalQuery);
    213   EXPECT_EQ("http://info.prefix.com/foo/report?client=unittest&appver=1.0&"
    214             "pver=2.2&additional_query&evts=phishblhit&"
    215             "evtd=http%3A%2F%2Fmalicious.url.com%2F&"
    216             "evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
    217             "url.com%2F&evtb=0",
    218             pm.SafeBrowsingHitUrl(
    219                 malicious_url, page_url, referrer_url,
    220                 false, SafeBrowsingService::URL_PHISHING).spec());
    221 
    222   EXPECT_EQ("http://info.prefix.com/foo/report?client=unittest&appver=1.0&"
    223             "pver=2.2&additional_query&evts=binurlhit&"
    224             "evtd=http%3A%2F%2Fmalicious.url.com%2F&"
    225             "evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
    226             "url.com%2F&evtb=0",
    227             pm.SafeBrowsingHitUrl(
    228                 malicious_url, page_url, referrer_url,
    229                 false, SafeBrowsingService::BINARY_MALWARE_URL).spec());
    230 
    231   EXPECT_EQ("http://info.prefix.com/foo/report?client=unittest&appver=1.0&"
    232             "pver=2.2&additional_query&evts=binhashhit&"
    233             "evtd=http%3A%2F%2Fmalicious.url.com%2F&"
    234             "evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
    235             "url.com%2F&evtb=0",
    236             pm.SafeBrowsingHitUrl(
    237                 malicious_url, page_url, referrer_url,
    238                 false, SafeBrowsingService::BINARY_MALWARE_HASH).spec());
    239 }
    240 
    241 TEST_F(SafeBrowsingProtocolManagerTest, TestMalwareDetailsUrl) {
    242   SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
    243                                  kInfoUrlPrefix, kMacKeyUrlPrefix, false);
    244 
    245   pm.version_ = kAppVer;
    246   pm.set_additional_query(kAdditionalQuery);  // AdditionalQuery is not used.
    247   EXPECT_EQ("https://key.prefix.com/bar/clientreport/malware?"
    248             "client=unittest&appver=1.0&pver=1.0",
    249             pm.MalwareDetailsUrl().spec());
    250 }
    251 
    252 TEST_F(SafeBrowsingProtocolManagerTest, TestMacKeyUrl) {
    253   SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
    254                                  kInfoUrlPrefix, kMacKeyUrlPrefix, false);
    255   pm.version_ = kAppVer;
    256 
    257   EXPECT_EQ("https://key.prefix.com/bar/newkey?client=unittest&appver=1.0&"
    258             "pver=2.2", pm.MacKeyUrl().spec());
    259 
    260   pm.set_additional_query(kAdditionalQuery);
    261   EXPECT_EQ("https://key.prefix.com/bar/newkey?client=unittest&appver=1.0&"
    262             "pver=2.2&additional_query", pm.MacKeyUrl().spec());
    263 }
    264 
    265 TEST_F(SafeBrowsingProtocolManagerTest, TestNextChunkUrl) {
    266   SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
    267                                  kInfoUrlPrefix, kMacKeyUrlPrefix, false);
    268   pm.version_ = kAppVer;
    269 
    270   std::string url_partial = "localhost:1234/foo/bar?foo";
    271   std::string url_http_full = "http://localhost:1234/foo/bar?foo";
    272   std::string url_https_full = "https://localhost:1234/foo/bar?foo";
    273   std::string url_https_no_query = "https://localhost:1234/foo/bar";
    274 
    275   EXPECT_EQ("http://localhost:1234/foo/bar?foo",
    276             pm.NextChunkUrl(url_partial).spec());
    277   EXPECT_EQ("http://localhost:1234/foo/bar?foo",
    278             pm.NextChunkUrl(url_http_full).spec());
    279   EXPECT_EQ("https://localhost:1234/foo/bar?foo",
    280             pm.NextChunkUrl(url_https_full).spec());
    281   EXPECT_EQ("https://localhost:1234/foo/bar",
    282             pm.NextChunkUrl(url_https_no_query).spec());
    283 
    284   pm.set_additional_query(kAdditionalQuery);
    285   EXPECT_EQ("http://localhost:1234/foo/bar?foo&additional_query",
    286             pm.NextChunkUrl(url_partial).spec());
    287   EXPECT_EQ("http://localhost:1234/foo/bar?foo&additional_query",
    288             pm.NextChunkUrl(url_http_full).spec());
    289   EXPECT_EQ("https://localhost:1234/foo/bar?foo&additional_query",
    290             pm.NextChunkUrl(url_https_full).spec());
    291   EXPECT_EQ("https://localhost:1234/foo/bar?additional_query",
    292             pm.NextChunkUrl(url_https_no_query).spec());
    293 }
    294