Security/Features/Application Reputation Design Doc
Document application reputation implementation decisions so that other people than the author can debug it.
Google has offered an application reputation feature to detect malicious downloads as part of Google Safe Browsing since 2012 . Although this part of the Safe Browsing API is not documented, they have offered it to us for use in Firefox. Malicious download detection is separate from detection of phishing and malware pages (present in Firefox since 2.0), though both features use some of the same mechanisms.
This document attempts to document all of the things that Google Chrome does, so that even in the absence of official API documentation from Google, we collectively have a better chance of implementing this feature correctly.
How to turn off this feature
Do any one of the following:
- Turn off malware detection in Preferences > Security > "Block reported attack sites." This disables all Safebrowsing malware protection, including the warning interstitial that appears when the user navigates to a malware site.
- Set browser.safebrowsing.downloads.remote.enabled to false in about:config. This disables application reputation remote lookupsbut leaves other Safebrowsing malware protection intact. To turn off all download protection checks, use browser.safebrowsing.downloads.enabled instead.
The user-agent performs local lookups whenever a binary file is downloaded. If a local result is not found, the user-agent may perform a remote-lookup on Windows only. The bulk of Chrome's implementation is found in DownloadProtectionService .
When a binary file is downloaded, the user-agent extracts several pieces of metadata about the file, including:
- The target URL from which the file was downloaded, its referrer URL and any URLs in the redirect chain. These URLs are checked against goog-badbinurl-shavar.
- The SHA-256 hash of the contents of the file.
- Any certificate verification information obtained through the Windows Authenticode APIs. This certificate information is used to construct synthetic URLs with which to check goog-downloadwhite-digest256.
- The length of the file in bytes.
- The suggested filename for the download.
Using this metadata, the user-agent performs a local lookups against a blocklist. In Chrome, this happens in DownloadProtectionService::CheckDownloadUrl . If no match is found, the user-agent checks whether the binary is supported. In Chrome, the entry point is in DownloadProtectionService::CheckClientDownloadRequest . If the download is supported, it checks an allowlist. In Chrome, these checks happen in CheckClientDownloadRequest::CheckWhitelists . If the binary is signed, then the code signing information is checked against the allowlist. In Chrome, these checks begin inside CheckWhitelists .
If any blocklist matches are found, the user-agent must not save the file to disk. If any allowlist matches are found, the user-agent may treat the binary as trusted and skip the remote lookup. If no matches are found and the binary was unsigned or signature extraction completed successfully (on Windows only) and the filename ends with an executable extension, the user-agent may send a remote lookup to the application reputation service.
In Firefox, SHA-256 hash computation is performed in BackgroundFileSaver via DigestOutputStream as the temporary file is written to disk . After the download is complete, BackgroundFileSaver computes the signature verification of the downloaded file in ExtractSignatureInfo on Windows only . Both of these operations happen on a worker thread.
Extraction of the redirect chain will hopefully happen via exposing mRedirectedCacheKeys from HttpBaseChannel.
Application reputation requres two lists, goog-badbinurl-shavar for blocklisting and goog-downloadwhite-digest256 for allowlisting. Both of these lists are updated in the same way as existing Safe Browsing lists . The shavar list is an existing format. The digest256 list is similar to shavar, except that all of its entries are the full 256-bit hash. Lookups based on increasing-sized fragments of the URL happen in exactly the same way.
Local lookups (present in FF 31)
URL-based lookups for the target URL and its redirect chain happen in the same way for published Safe Browsing API. For certificate information lookups, the user-agent generates URLs based on signing information and looks up the resulting URL and its fragments in the same way.
A binary may be signed by multiple certificates. Each certificate may be part of a certificate chain, where the previous link in the chain is the issuer of the current certificate, all the way to the root certificate. Certificate chain information is extracted by the WinVerifyTrust and WTHelperProvDataFromStateData Windows API functions. In Chrome, this implementation is in SignatureUtil . In Firefox, this implementation is in BackgroundFileSaver.
For each certificate chain, let CN be the common name of the signer (the first certificate of the chain), O be the organization name of the signer, and OU the organization unit of the signer. For each issuer in the certificate chain starting with the issuer of the signer, construct a whitelist string of the form:
Thus every for every certificate chain of length n, n-1 whitelist strings are constructed. In Chrome, certificate whitelist strings are constructed in CertificateChainIsWhitelisted .
Remote lookup (present in FF 32, Windows-only)
These lookups are Windows-only, because we rely on signature information in order to suppress remote lookups and signature APIs are only available on Windows. If the binary is unsigned or its signature does not match a known good publisher and the filename ends in a known executable extension, Firefox sends a remote lookup to the application reputation service.
The user-agent encodes file metadata into a ClientDownloadRequest protocol buffer and sends it to the remote service. If a MALWARE verdict is received, the downloaded file should not be saved and the UI should report that the download may be malware. In Chrome, this occurs in CheckClientDownloadRequest::SendRequest . In Firefox, this happens in ApplicationReputation::PendingLookup::SendRemoteQuery  and in the JS DownloadIntegration.shouldBlockForApplicationReputation .
How do we know if it works? See Security/Features/Application_Reputation/Preliminary_Results for preliminary results.
Divergence from Chrome implementation
- We currently have no way to determine if a user initiated the download.
- We strip url params.
The tracking bug is bug 662819. This feature is enabled on Firefox Desktop for all OSes, except for remote lookups which are Windows only. Local lookups are turned on in FF 31, and remote lookups are scheduled to be turned on in FF 32. For more information, see