security_state.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. // Copyright 2015 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. #include "components/security_state/core/security_state.h"
  5. #include <stdint.h>
  6. #include <string>
  7. #include "base/command_line.h"
  8. #include "base/metrics/field_trial.h"
  9. #include "base/metrics/field_trial_params.h"
  10. #include "base/metrics/histogram_macros.h"
  11. #include "build/build_config.h"
  12. #include "net/ssl/ssl_cipher_suite_names.h"
  13. #include "net/ssl/ssl_connection_status_flags.h"
  14. #include "services/network/public/cpp/is_potentially_trustworthy.h"
  15. namespace security_state {
  16. namespace {
  17. std::string GetHistogramSuffixForSecurityLevel(
  18. security_state::SecurityLevel level) {
  19. switch (level) {
  20. case SECURE:
  21. return "SECURE";
  22. case NONE:
  23. return "NONE";
  24. case WARNING:
  25. return "WARNING";
  26. case SECURE_WITH_POLICY_INSTALLED_CERT:
  27. return "SECURE_WITH_POLICY_INSTALLED_CERT";
  28. case DANGEROUS:
  29. return "DANGEROUS";
  30. default:
  31. return "OTHER";
  32. }
  33. }
  34. std::string GetHistogramSuffixForSafetyTipStatus(
  35. security_state::SafetyTipStatus safety_tip_status) {
  36. switch (safety_tip_status) {
  37. case security_state::SafetyTipStatus::kUnknown:
  38. return "SafetyTip_Unknown";
  39. case security_state::SafetyTipStatus::kNone:
  40. return "SafetyTip_None";
  41. case security_state::SafetyTipStatus::kBadReputation:
  42. return "SafetyTip_BadReputation";
  43. case security_state::SafetyTipStatus::kLookalike:
  44. return "SafetyTip_Lookalike";
  45. case security_state::SafetyTipStatus::kBadReputationIgnored:
  46. return "SafetyTip_BadReputationIgnored";
  47. case security_state::SafetyTipStatus::kLookalikeIgnored:
  48. return "SafetyTip_LookalikeIgnored";
  49. case security_state::SafetyTipStatus::kDigitalAssetLinkMatch:
  50. return "SafetyTip_DigitalAssetLinkMatch";
  51. case security_state::SafetyTipStatus::kBadKeyword:
  52. return "SafetyTip_BadKeyword";
  53. }
  54. NOTREACHED();
  55. return std::string();
  56. }
  57. // Returns whether to set the security level based on the safety tip status.
  58. // Sets |level| to the right value if status should be set.
  59. bool ShouldSetSecurityLevelFromSafetyTip(security_state::SafetyTipStatus status,
  60. SecurityLevel* level) {
  61. switch (status) {
  62. case security_state::SafetyTipStatus::kBadReputation:
  63. *level = security_state::NONE;
  64. return true;
  65. case security_state::SafetyTipStatus::kBadReputationIgnored:
  66. case security_state::SafetyTipStatus::kLookalike:
  67. case security_state::SafetyTipStatus::kLookalikeIgnored:
  68. case security_state::SafetyTipStatus::kBadKeyword:
  69. // TODO(crbug/1012982): Decide whether to degrade the indicator once the
  70. // UI lands.
  71. case security_state::SafetyTipStatus::kDigitalAssetLinkMatch:
  72. case security_state::SafetyTipStatus::kUnknown:
  73. case security_state::SafetyTipStatus::kNone:
  74. return false;
  75. }
  76. NOTREACHED();
  77. return false;
  78. }
  79. } // namespace
  80. SecurityLevel GetSecurityLevel(
  81. const VisibleSecurityState& visible_security_state,
  82. bool used_policy_installed_certificate) {
  83. // Override the connection security information if the website failed the
  84. // browser's malware checks.
  85. if (visible_security_state.malicious_content_status !=
  86. MALICIOUS_CONTENT_STATUS_NONE) {
  87. return DANGEROUS;
  88. }
  89. // If the navigation was upgraded to HTTPS because of HTTPS-Only Mode, but did
  90. // not succeed (either currently showing the HTTPS-Only Mode interstitial, or
  91. // the navigation fell back to HTTP), set the security level to WARNING. The
  92. // HTTPS-Only Mode interstitial warning is considered "less serious" than the
  93. // general certificate error interstitials.
  94. //
  95. // This check must come before the checks for `connection_info_initialized`
  96. // (because the HTTPS-Only Mode intersitital can trigger if the HTTPS version
  97. // of the page does not commit) and certificate errors (because the HTTPS-Only
  98. // Mode interstitial takes precedent if the certificate error occurred due to
  99. // an upgraded main-frame navigation).
  100. if (visible_security_state.is_https_only_mode_upgraded) {
  101. return WARNING;
  102. }
  103. if (!visible_security_state.connection_info_initialized) {
  104. return NONE;
  105. }
  106. // Set the security level to DANGEROUS for major certificate errors.
  107. if (HasMajorCertificateError(visible_security_state)) {
  108. return DANGEROUS;
  109. }
  110. DCHECK(!net::IsCertStatusError(visible_security_state.cert_status));
  111. const GURL& url = visible_security_state.url;
  112. // data: URLs don't define a secure context, and are a vector for spoofing.
  113. // Display a "Not secure" badge for all these URLs.
  114. if (url.SchemeIs(url::kDataScheme)) {
  115. return WARNING;
  116. }
  117. // Display DevTools pages as neutral since we can't be confident the page
  118. // is secure, but also don't want the "Not secure" badge.
  119. if (visible_security_state.is_devtools) {
  120. return NONE;
  121. }
  122. // Downgrade the security level for active insecure subresources. This comes
  123. // before handling non-cryptographic schemes below, because secure pages with
  124. // non-cryptographic schemes (e.g., about:blank) can still have mixed content.
  125. if (visible_security_state.ran_mixed_content ||
  126. visible_security_state.ran_content_with_cert_errors) {
  127. return kRanInsecureContentLevel;
  128. }
  129. // Choose the appropriate security level for requests to HTTP and remaining
  130. // pseudo URLs (blob:, filesystem:). filesystem: is a standard scheme so does
  131. // not need to be explicitly listed here.
  132. // TODO(meacer): Remove special case for blob (crbug.com/684751).
  133. const bool is_cryptographic_with_certificate =
  134. visible_security_state.url.SchemeIsCryptographic() &&
  135. visible_security_state.certificate;
  136. if (!is_cryptographic_with_certificate) {
  137. if (!visible_security_state.is_error_page &&
  138. !network::IsUrlPotentiallyTrustworthy(url) &&
  139. (url.IsStandard() || url.SchemeIs(url::kBlobScheme))) {
  140. #if !BUILDFLAG(IS_ANDROID)
  141. // On Desktop, Reader Mode pages have their own visible security state in
  142. // the omnibox. Display ReaderMode pages as neutral even if the original
  143. // URL was secure, because Chrome has modified the content so we don't
  144. // want to present it as the actual content that the server sent.
  145. // Distilled pages should not contain forms, payment handlers, or other JS
  146. // from the original URL, so they won't be affected by a downgraded
  147. // security level. On Desktop, Reader Mode is only run on SECURE pages and
  148. // and does not load mixed content or bad certificate subresources.
  149. if (visible_security_state.is_reader_mode) {
  150. return NONE;
  151. }
  152. #endif // !BUILDFLAG(IS_ANDROID)
  153. return WARNING;
  154. }
  155. return NONE;
  156. }
  157. // Downgrade the security level for pages that trigger a Safety Tip.
  158. SecurityLevel safety_tip_level;
  159. if (ShouldSetSecurityLevelFromSafetyTip(
  160. visible_security_state.safety_tip_info.status, &safety_tip_level)) {
  161. return safety_tip_level;
  162. }
  163. // In most cases, SHA1 use is treated as a certificate error, in which case
  164. // DANGEROUS will have been returned above. If SHA1 was permitted by policy,
  165. // downgrade the security level to Neutral.
  166. if (IsSHA1InChain(visible_security_state)) {
  167. return NONE;
  168. }
  169. // Active mixed content is handled above.
  170. DCHECK(!visible_security_state.ran_mixed_content);
  171. DCHECK(!visible_security_state.ran_content_with_cert_errors);
  172. if (visible_security_state.displayed_mixed_content) {
  173. return kDisplayedInsecureContentWarningLevel;
  174. }
  175. if ((visible_security_state.contained_mixed_form &&
  176. !visible_security_state.should_treat_displayed_mixed_forms_as_secure) ||
  177. visible_security_state.displayed_content_with_cert_errors) {
  178. return kDisplayedInsecureContentLevel;
  179. }
  180. if (visible_security_state.is_view_source) {
  181. return NONE;
  182. }
  183. // Any prior observation of a policy-installed cert is a strong indicator
  184. // of a MITM being present (the enterprise), so a "secure-but-inspected"
  185. // security level is returned.
  186. if (used_policy_installed_certificate) {
  187. return SECURE_WITH_POLICY_INSTALLED_CERT;
  188. }
  189. return SECURE;
  190. }
  191. bool HasMajorCertificateError(
  192. const VisibleSecurityState& visible_security_state) {
  193. if (!visible_security_state.connection_info_initialized)
  194. return false;
  195. const bool is_cryptographic_with_certificate =
  196. visible_security_state.url.SchemeIsCryptographic() &&
  197. visible_security_state.certificate;
  198. const bool is_major_cert_error =
  199. net::IsCertStatusError(visible_security_state.cert_status);
  200. return is_cryptographic_with_certificate && is_major_cert_error;
  201. }
  202. VisibleSecurityState::VisibleSecurityState()
  203. : malicious_content_status(MALICIOUS_CONTENT_STATUS_NONE),
  204. connection_info_initialized(false),
  205. cert_status(0),
  206. connection_status(0),
  207. key_exchange_group(0),
  208. peer_signature_algorithm(0),
  209. displayed_mixed_content(false),
  210. contained_mixed_form(false),
  211. ran_mixed_content(false),
  212. displayed_content_with_cert_errors(false),
  213. ran_content_with_cert_errors(false),
  214. pkp_bypassed(false),
  215. is_error_page(false),
  216. is_view_source(false),
  217. is_devtools(false),
  218. is_reader_mode(false),
  219. should_treat_displayed_mixed_forms_as_secure(false),
  220. is_https_only_mode_upgraded(false) {}
  221. VisibleSecurityState::VisibleSecurityState(const VisibleSecurityState& other) =
  222. default;
  223. VisibleSecurityState& VisibleSecurityState::operator=(
  224. const VisibleSecurityState& other) = default;
  225. VisibleSecurityState::~VisibleSecurityState() {}
  226. bool IsSchemeCryptographic(const GURL& url) {
  227. return url.is_valid() && url.SchemeIsCryptographic();
  228. }
  229. bool IsOriginLocalhostOrFile(const GURL& url) {
  230. return url.is_valid() && (net::IsLocalhost(url) || url.SchemeIsFile());
  231. }
  232. bool IsSslCertificateValid(SecurityLevel security_level) {
  233. return security_level == SECURE ||
  234. security_level == SECURE_WITH_POLICY_INSTALLED_CERT;
  235. }
  236. std::string GetSecurityLevelHistogramName(
  237. const std::string& prefix,
  238. security_state::SecurityLevel level) {
  239. return prefix + "." + GetHistogramSuffixForSecurityLevel(level);
  240. }
  241. std::string GetSafetyTipHistogramName(const std::string& prefix,
  242. SafetyTipStatus safety_tip_status) {
  243. return prefix + "." + GetHistogramSuffixForSafetyTipStatus(safety_tip_status);
  244. }
  245. bool IsSHA1InChain(const VisibleSecurityState& visible_security_state) {
  246. return visible_security_state.certificate &&
  247. (visible_security_state.cert_status &
  248. net::CERT_STATUS_SHA1_SIGNATURE_PRESENT);
  249. }
  250. } // namespace security_state