blob: 3ae657b623422a0c98e3a64a8931292e146cfc0c [file] [log] [blame]
// Copyright (c) 2011 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.
//
// Helper class which handles communication with the SafeBrowsing backends for
// client-side phishing detection. This class is used to fetch the client-side
// model and send it to all renderers. This class is also used to send a ping
// back to Google to verify if a particular site is really phishing or not.
//
// This class is not thread-safe and expects all calls to be made on the UI
// thread. We also expect that the calling thread runs a message loop.
#ifndef CHROME_BROWSER_SAFE_BROWSING_CLIENT_SIDE_DETECTION_SERVICE_H_
#define CHROME_BROWSER_SAFE_BROWSING_CLIENT_SIDE_DETECTION_SERVICE_H_
#pragma once
#include <map>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/basictypes.h"
#include "base/callback_old.h"
#include "base/gtest_prod_util.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/task.h"
#include "base/time.h"
#include "content/public/common/url_fetcher_delegate.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"
class RenderProcessHost;
class SafeBrowsingService;
namespace base {
class TimeDelta;
}
namespace net {
class URLRequestContextGetter;
class URLRequestStatus;
typedef std::vector<std::string> ResponseCookies;
} // namespace net
namespace safe_browsing {
class ClientPhishingRequest;
class ClientPhishingResponse;
class ClientSideModel;
class ClientSideDetectionService : public content::URLFetcherDelegate,
public content::NotificationObserver {
public:
typedef Callback2<GURL /* phishing URL */, bool /* is phishing */>::Type
ClientReportPhishingRequestCallback;
virtual ~ClientSideDetectionService();
// Creates a client-side detection service. The service is initially
// disabled, use SetEnabledAndRefreshState() to start it. The caller takes
// ownership of the object. This function may return NULL.
static ClientSideDetectionService* Create(
net::URLRequestContextGetter* request_context_getter);
// Enables or disables the service, and refreshes the state of all renderers.
// This is usually called by the SafeBrowsingService, which tracks whether
// any profile uses these services at all. Disabling cancels any pending
// requests; existing ClientSideDetectionHosts will have their callbacks
// called with "false" verdicts. Enabling starts downloading the model after
// a delay. In all cases, each render process is updated to match the state
// of the SafeBrowsing preference for that profile.
void SetEnabledAndRefreshState(bool enabled);
bool enabled() const {
return enabled_;
}
// From the content::URLFetcherDelegate interface.
virtual void OnURLFetchComplete(const content::URLFetcher* source) OVERRIDE;
// content::NotificationObserver overrides:
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// Sends a request to the SafeBrowsing servers with the ClientPhishingRequest.
// The URL scheme of the |url()| in the request should be HTTP. This method
// takes ownership of the |verdict| as well as the |callback| and calls the
// the callback once the result has come back from the server or if an error
// occurs during the fetch. If the service is disabled or an error occurs
// the phishing verdict will always be false. The callback is always called
// after SendClientReportPhishingRequest() returns and on the same thread as
// SendClientReportPhishingRequest() was called. You may set |callback| to
// NULL if you don't care about the server verdict.
virtual void SendClientReportPhishingRequest(
ClientPhishingRequest* verdict,
ClientReportPhishingRequestCallback* callback);
// Returns true if the given IP address string falls within a private
// (unroutable) network block. Pages which are hosted on these IP addresses
// are exempt from client-side phishing detection. This is called by the
// ClientSideDetectionHost prior to sending the renderer a
// SafeBrowsingMsg_StartPhishingDetection IPC.
//
// ip_address should be a dotted IPv4 address, or an unbracketed IPv6
// address.
virtual bool IsPrivateIPAddress(const std::string& ip_address) const;
// Returns true if the given IP address is on the list of known bad IPs.
// ip_address should be a dotted IPv4 address, or an unbracketed IPv6
// address.
virtual bool IsBadIpAddress(const std::string& ip_address) const;
// Returns true and sets is_phishing if url is in the cache and valid.
virtual bool GetValidCachedResult(const GURL& url, bool* is_phishing);
// Returns true if the url is in the cache.
virtual bool IsInCache(const GURL& url);
// Returns true if we have sent more than kMaxReportsPerInterval in the last
// kReportsInterval.
virtual bool OverReportLimit();
protected:
// Use Create() method to create an instance of this object.
explicit ClientSideDetectionService(
net::URLRequestContextGetter* request_context_getter);
// Enum used to keep stats about why we fail to get the client model.
enum ClientModelStatus {
MODEL_SUCCESS,
MODEL_NOT_CHANGED,
MODEL_FETCH_FAILED,
MODEL_EMPTY,
MODEL_TOO_LARGE,
MODEL_PARSE_ERROR,
MODEL_MISSING_FIELDS,
MODEL_INVALID_VERSION_NUMBER,
MODEL_BAD_HASH_IDS,
MODEL_STATUS_MAX // Always add new values before this one.
};
// Starts fetching the model from the network or the cache. This method
// is called periodically to check whether a new client model is available
// for download.
void StartFetchModel();
// Schedules the next fetch of the model.
virtual void ScheduleFetchModel(int64 delay_ms); // Virtual for testing.
// This method is called when we're done fetching the model either because
// we hit an error somewhere or because we're actually done fetch and
// validating the model.
virtual void EndFetchModel(ClientModelStatus status); // Virtual for testing.
private:
friend class ClientSideDetectionServiceTest;
FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest, FetchModelTest);
FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest, SetBadSubnets);
FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest,
SetEnabledAndRefreshState);
FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest, IsBadIpAddress);
FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest,
IsFalsePositiveResponse);
FRIEND_TEST_ALL_PREFIXES(ClientSideDetectionServiceTest,
ModelHasValidHashIds);
// CacheState holds all information necessary to respond to a caller without
// actually making a HTTP request.
struct CacheState {
bool is_phishing;
base::Time timestamp;
CacheState(bool phish, base::Time time);
};
typedef std::map<GURL, linked_ptr<CacheState> > PhishingCache;
// A tuple of (IP address block, prefix size) representing a private
// IP address range.
typedef std::pair<net::IPAddressNumber, size_t> AddressRange;
// Maps a IPv6 subnet mask to a set of hashed IPv6 subnets. The IPv6
// subnets are in network order and hashed with sha256.
typedef std::map<std::string /* subnet mask */,
std::set<std::string /* hashed subnet */> > BadSubnetMap;
static const char kClientReportPhishingUrl[];
static const char kClientModelUrl[];
static const size_t kMaxModelSizeBytes;
static const int kMaxReportsPerInterval;
static const int kClientModelFetchIntervalMs;
static const int kInitialClientModelFetchDelayMs;
static const base::TimeDelta kReportsInterval;
static const base::TimeDelta kNegativeCacheInterval;
static const base::TimeDelta kPositiveCacheInterval;
// Starts sending the request to the client-side detection frontends.
// This method takes ownership of both pointers.
void StartClientReportPhishingRequest(
ClientPhishingRequest* verdict,
ClientReportPhishingRequestCallback* callback);
// Called by OnURLFetchComplete to handle the response from fetching the
// model.
void HandleModelResponse(const content::URLFetcher* source,
const GURL& url,
const net::URLRequestStatus& status,
int response_code,
const net::ResponseCookies& cookies,
const std::string& data);
// Called by OnURLFetchComplete to handle the server response from
// sending the client-side phishing request.
void HandlePhishingVerdict(const content::URLFetcher* source,
const GURL& url,
const net::URLRequestStatus& status,
int response_code,
const net::ResponseCookies& cookies,
const std::string& data);
// Invalidate cache results which are no longer useful.
void UpdateCache();
// Get the number of phishing reports that we have sent over kReportsInterval
int GetNumReports();
// Initializes the |private_networks_| vector with the network blocks
// that we consider non-public IP addresses. Returns true on success.
bool InitializePrivateNetworks();
// Send the model to the given renderer.
void SendModelToProcess(RenderProcessHost* process);
// Same as above but sends the model to all rendereres.
void SendModelToRenderers();
// Reads the bad subnets from the client model and inserts them into
// |bad_subnets| for faster lookups. This method is static to simplify
// testing.
static void SetBadSubnets(const ClientSideModel& model,
BadSubnetMap* bad_subnets);
// Returns true iff all the hash id's in the client-side model point to
// valid hashes in the model.
static bool ModelHasValidHashIds(const ClientSideModel& model);
// Returns true iff the response is phishing (phishy() is true) and if the
// given URL matches one of the whitelisted expressions in the given
// ClientPhishingResponse.
static bool IsFalsePositiveResponse(const GURL& url,
const ClientPhishingResponse& response);
// Whether the service is running or not. When the service is not running,
// it won't download the model nor report detected phishing URLs.
bool enabled_;
std::string model_str_;
scoped_ptr<ClientSideModel> model_;
scoped_ptr<base::TimeDelta> model_max_age_;
scoped_ptr<content::URLFetcher> model_fetcher_;
// Map of client report phishing request to the corresponding callback that
// has to be invoked when the request is done.
struct ClientReportInfo;
std::map<const content::URLFetcher*, ClientReportInfo*>
client_phishing_reports_;
// Cache of completed requests. Used to satisfy requests for the same urls
// as long as the next request falls within our caching window (which is
// determined by kNegativeCacheInterval and kPositiveCacheInterval). The
// size of this cache is limited by kMaxReportsPerDay *
// ceil(InDays(max(kNegativeCacheInterval, kPositiveCacheInterval))).
// TODO(gcasto): Serialize this so that it doesn't reset on browser restart.
PhishingCache cache_;
// Timestamp of when we sent a phishing request. Used to limit the number
// of phishing requests that we send in a day.
// TODO(gcasto): Serialize this so that it doesn't reset on browser restart.
std::queue<base::Time> phishing_report_times_;
// Used to asynchronously call the callbacks for
// SendClientReportPhishingRequest.
ScopedRunnableMethodFactory<ClientSideDetectionService> method_factory_;
// The context we use to issue network requests.
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
// The network blocks that we consider private IP address ranges.
std::vector<AddressRange> private_networks_;
// Map of bad subnets which are copied from the client model and put into
// this map to speed up lookups.
BadSubnetMap bad_subnets_;
content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(ClientSideDetectionService);
};
} // namepsace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_CLIENT_SIDE_DETECTION_SERVICE_H_