blob: b0320741de3bcfb24dbacf23b3a0b84afda7a3e5 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include "chrome/browser/lookalikes/lookalike_url_service.h"
#include "chrome/browser/reputation/local_heuristics.h"
#include "base/metrics/field_trial_params.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/common/chrome_features.h"
#include "components/security_state/core/features.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
struct KeywordHeuristicTestCase {
const GURL url;
const bool should_trigger;
};
// Verify behavior of the "Sensitive Keywords" heuristic, which, triggers when
// it finds a keyword (like a popular brand name) in a hostname unexpectedly.
TEST(SafetyTipHeuristicsTest, SensitiveKeywordsTest) {
// These keywords must always be in sorted order.
const std::vector<const char*> keywords = {"bad", "evil", "keyword"};
const std::vector<KeywordHeuristicTestCase> test_cases = {
// Verify scheme doesn't affect results.
{GURL("http://good-domain.com"), false},
{GURL("https://good-domain.com"), false},
{GURL("http://bad-domain.com"), true},
{GURL("https://bad-domain.com"), true},
// Verify detection works in subdomains.
{GURL("http://www.domain.evil.safe-domain.com"), true},
{GURL("http://www.evil-domain.safe-domain.com"), true},
{GURL("http://evil.domain.safe-domain.com"), true},
// e2LDs that are a sensitive keyword themselves should *not* trigger the
// heuristic, but they shouldn't prevent the heuristic from triggering for
// other reasons.
{GURL("http://www.bad.com"), false},
{GURL("http://bad.com"), false},
{GURL("http://evil.bad.com"), true},
// Verify keywords still in the e2LD no matter where they fall.
{GURL("http://www.good-and-bad.com"), true},
{GURL("http://www.bad-other.edu"), true},
{GURL("http://bad-keyword.com"), true},
{GURL("http://www.evil-and-bad.com"), true},
{GURL("http://www.good-evil-neutral.com"), true},
// Make sure heuristic still works, even for really long domains.
{GURL("http://"
"www.super-duper-uber-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-domain-with-a-lot-of-parts-to-it.org"),
false},
{GURL("http://"
"www.super-duper-uber-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-THISISEVIL-evil-THISISEVIL-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-long-long-long-long-long-"
"long-long-long-long-long-long-long-long-domain-with-a-lot-of-"
"parts-to-it.org"),
true},
// Ensure heuristic doesn't trigger on misspelled keywords.
{GURL("http://www.misspelled-example-keywrd.edu"), false},
{GURL("http://www.spelled-right-example-keyword.edu"), true},
// Make sure passing a lot of keywords doesn't result in a false negative.
{GURL("http://evil-bad-keyword-example.com"), true},
// Test a few cases with edge-case URLs. URLs with unknown registries
// shouldn't trigger.
{GURL("http://foo"), false},
{GURL("http://foo.invalidregistry"), false},
{GURL("http://evil-site"), false},
{GURL("http://evil-site.invalidregistry"), false},
{GURL("http://this.is.an.evil-site.invalidregistry"), false},
// Test some edge cases which the heuristic should gracefully handle.
{GURL("http://localhost"), false},
{GURL("http://1.2.3.4"), false},
{GURL("http://127.0.0.1"), false},
// Make sure the heuristic never triggers on non-http / https URLs.
{GURL("ftp://www.safe-website.com"), false},
{GURL("ftp://www.evil-website.com"), false},
{GURL("garbage://www.evil-website.com"), false},
// Ensure that the URL path doesn't affect the heuristic.
{GURL("http://www.evil-site.com/some/random/path"), true},
{GURL("http://www.safe-site.com/evil-path/even-more-evil-path"), false},
{GURL("http://www.evil.com/safe-path/"), false},
{GURL("http://www.evil.com/safe-path/evil"), false},
{GURL("http://www.evil.com/evil-path/"), false},
// Ensure a really long path doesn't affect the heuristic.
{GURL("http://www.safe.com/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/safe-path/evil/evil/evil/evil/evil/"
"evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/evil/"),
false},
};
for (const auto& test_case : test_cases) {
const DomainInfo test_case_navigated_domain = GetDomainInfo(test_case.url);
ASSERT_EQ(test_case.should_trigger,
ShouldTriggerSafetyTipFromKeywordInURL(
test_case.url, test_case_navigated_domain, keywords.data(),
keywords.size()))
<< "Expected that \"" << test_case.url << "\" would"
<< (test_case.should_trigger ? "" : "n't") << " trigger but it did"
<< (test_case.should_trigger ? "n't" : "");
}
}
TEST(SafetyTipHeuristicsTest, ShouldTriggerSafetyTipFromLookalike) {
base::FieldTrialParams params;
params["editdistance"] = "true";
base::test::ScopedFeatureList feature;
feature.InitAndEnableFeatureWithParameters(
security_state::features::kSafetyTipUI, params);
struct TestCase {
GURL navigated_url;
GURL engaged_url;
GURL expected_safe_url;
} kTestCases[] = {
// Top domain matches should have https:// scheme for safe URLs.
{GURL("https://gooogle.com"), GURL(), GURL("https://google.com")},
{GURL("http://gooogle.com"), GURL(), GURL("https://google.com")},
// Engaged site matches should use the scheme of the lookalike URL for
// safe URLs.
{GURL("http://teestsite.com"), GURL("https://testsite.com"),
GURL("http://testsite.com")},
{GURL("http://teestsite.com"), GURL("http://testsite.com"),
GURL("http://testsite.com")},
{GURL("https://teestsite.com"), GURL("https://testsite.com"),
GURL("https://testsite.com")},
{GURL("https://teestsite.com"), GURL("http://testsite.com"),
GURL("https://testsite.com")},
};
for (const TestCase& test_case : kTestCases) {
std::vector<DomainInfo> engaged_sites;
if (test_case.engaged_url.is_valid()) {
engaged_sites.push_back(GetDomainInfo(test_case.engaged_url));
}
GURL safe_url;
EXPECT_TRUE(ShouldTriggerSafetyTipFromLookalike(
test_case.navigated_url, GetDomainInfo(test_case.navigated_url),
engaged_sites, &safe_url));
EXPECT_EQ(test_case.expected_safe_url, safe_url);
}
}