test_security.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. from django.conf import settings
  2. from django.core.checks.messages import Error
  3. from django.core.checks.security import base, csrf, sessions
  4. from django.core.management.utils import get_random_secret_key
  5. from django.test import SimpleTestCase
  6. from django.test.utils import override_settings
  7. class CheckSessionCookieSecureTest(SimpleTestCase):
  8. @override_settings(
  9. SESSION_COOKIE_SECURE=False,
  10. INSTALLED_APPS=["django.contrib.sessions"],
  11. MIDDLEWARE=[],
  12. )
  13. def test_session_cookie_secure_with_installed_app(self):
  14. """
  15. Warn if SESSION_COOKIE_SECURE is off and "django.contrib.sessions" is
  16. in INSTALLED_APPS.
  17. """
  18. self.assertEqual(sessions.check_session_cookie_secure(None), [sessions.W010])
  19. @override_settings(
  20. SESSION_COOKIE_SECURE=False,
  21. INSTALLED_APPS=[],
  22. MIDDLEWARE=['django.contrib.sessions.middleware.SessionMiddleware'],
  23. )
  24. def test_session_cookie_secure_with_middleware(self):
  25. """
  26. Warn if SESSION_COOKIE_SECURE is off and
  27. "django.contrib.sessions.middleware.SessionMiddleware" is in
  28. MIDDLEWARE.
  29. """
  30. self.assertEqual(sessions.check_session_cookie_secure(None), [sessions.W011])
  31. @override_settings(
  32. SESSION_COOKIE_SECURE=False,
  33. INSTALLED_APPS=["django.contrib.sessions"],
  34. MIDDLEWARE=['django.contrib.sessions.middleware.SessionMiddleware'],
  35. )
  36. def test_session_cookie_secure_both(self):
  37. """
  38. If SESSION_COOKIE_SECURE is off and we find both the session app and
  39. the middleware, provide one common warning.
  40. """
  41. self.assertEqual(sessions.check_session_cookie_secure(None), [sessions.W012])
  42. @override_settings(
  43. SESSION_COOKIE_SECURE=True,
  44. INSTALLED_APPS=["django.contrib.sessions"],
  45. MIDDLEWARE=['django.contrib.sessions.middleware.SessionMiddleware'],
  46. )
  47. def test_session_cookie_secure_true(self):
  48. """
  49. If SESSION_COOKIE_SECURE is on, there's no warning about it.
  50. """
  51. self.assertEqual(sessions.check_session_cookie_secure(None), [])
  52. class CheckSessionCookieHttpOnlyTest(SimpleTestCase):
  53. @override_settings(
  54. SESSION_COOKIE_HTTPONLY=False,
  55. INSTALLED_APPS=["django.contrib.sessions"],
  56. MIDDLEWARE=[],
  57. )
  58. def test_session_cookie_httponly_with_installed_app(self):
  59. """
  60. Warn if SESSION_COOKIE_HTTPONLY is off and "django.contrib.sessions"
  61. is in INSTALLED_APPS.
  62. """
  63. self.assertEqual(sessions.check_session_cookie_httponly(None), [sessions.W013])
  64. @override_settings(
  65. SESSION_COOKIE_HTTPONLY=False,
  66. INSTALLED_APPS=[],
  67. MIDDLEWARE=['django.contrib.sessions.middleware.SessionMiddleware'],
  68. )
  69. def test_session_cookie_httponly_with_middleware(self):
  70. """
  71. Warn if SESSION_COOKIE_HTTPONLY is off and
  72. "django.contrib.sessions.middleware.SessionMiddleware" is in
  73. MIDDLEWARE.
  74. """
  75. self.assertEqual(sessions.check_session_cookie_httponly(None), [sessions.W014])
  76. @override_settings(
  77. SESSION_COOKIE_HTTPONLY=False,
  78. INSTALLED_APPS=["django.contrib.sessions"],
  79. MIDDLEWARE=['django.contrib.sessions.middleware.SessionMiddleware'],
  80. )
  81. def test_session_cookie_httponly_both(self):
  82. """
  83. If SESSION_COOKIE_HTTPONLY is off and we find both the session app and
  84. the middleware, provide one common warning.
  85. """
  86. self.assertEqual(sessions.check_session_cookie_httponly(None), [sessions.W015])
  87. @override_settings(
  88. SESSION_COOKIE_HTTPONLY=True,
  89. INSTALLED_APPS=["django.contrib.sessions"],
  90. MIDDLEWARE=['django.contrib.sessions.middleware.SessionMiddleware'],
  91. )
  92. def test_session_cookie_httponly_true(self):
  93. """
  94. If SESSION_COOKIE_HTTPONLY is on, there's no warning about it.
  95. """
  96. self.assertEqual(sessions.check_session_cookie_httponly(None), [])
  97. class CheckCSRFMiddlewareTest(SimpleTestCase):
  98. @override_settings(MIDDLEWARE=[])
  99. def test_no_csrf_middleware(self):
  100. """
  101. Warn if CsrfViewMiddleware isn't in MIDDLEWARE.
  102. """
  103. self.assertEqual(csrf.check_csrf_middleware(None), [csrf.W003])
  104. @override_settings(MIDDLEWARE=['django.middleware.csrf.CsrfViewMiddleware'])
  105. def test_with_csrf_middleware(self):
  106. self.assertEqual(csrf.check_csrf_middleware(None), [])
  107. class CheckCSRFCookieSecureTest(SimpleTestCase):
  108. @override_settings(
  109. MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
  110. CSRF_COOKIE_SECURE=False,
  111. )
  112. def test_with_csrf_cookie_secure_false(self):
  113. """
  114. Warn if CsrfViewMiddleware is in MIDDLEWARE but
  115. CSRF_COOKIE_SECURE isn't True.
  116. """
  117. self.assertEqual(csrf.check_csrf_cookie_secure(None), [csrf.W016])
  118. @override_settings(
  119. MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
  120. CSRF_USE_SESSIONS=True,
  121. CSRF_COOKIE_SECURE=False,
  122. )
  123. def test_use_sessions_with_csrf_cookie_secure_false(self):
  124. """
  125. No warning if CSRF_COOKIE_SECURE isn't True while CSRF_USE_SESSIONS
  126. is True.
  127. """
  128. self.assertEqual(csrf.check_csrf_cookie_secure(None), [])
  129. @override_settings(MIDDLEWARE=[], CSRF_COOKIE_SECURE=False)
  130. def test_with_csrf_cookie_secure_false_no_middleware(self):
  131. """
  132. No warning if CsrfViewMiddleware isn't in MIDDLEWARE, even if
  133. CSRF_COOKIE_SECURE is False.
  134. """
  135. self.assertEqual(csrf.check_csrf_cookie_secure(None), [])
  136. @override_settings(
  137. MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
  138. CSRF_COOKIE_SECURE=True,
  139. )
  140. def test_with_csrf_cookie_secure_true(self):
  141. self.assertEqual(csrf.check_csrf_cookie_secure(None), [])
  142. class CheckSecurityMiddlewareTest(SimpleTestCase):
  143. @override_settings(MIDDLEWARE=[])
  144. def test_no_security_middleware(self):
  145. """
  146. Warn if SecurityMiddleware isn't in MIDDLEWARE.
  147. """
  148. self.assertEqual(base.check_security_middleware(None), [base.W001])
  149. @override_settings(MIDDLEWARE=['django.middleware.security.SecurityMiddleware'])
  150. def test_with_security_middleware(self):
  151. self.assertEqual(base.check_security_middleware(None), [])
  152. class CheckStrictTransportSecurityTest(SimpleTestCase):
  153. @override_settings(
  154. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  155. SECURE_HSTS_SECONDS=0,
  156. )
  157. def test_no_sts(self):
  158. """
  159. Warn if SECURE_HSTS_SECONDS isn't > 0.
  160. """
  161. self.assertEqual(base.check_sts(None), [base.W004])
  162. @override_settings(MIDDLEWARE=[], SECURE_HSTS_SECONDS=0)
  163. def test_no_sts_no_middleware(self):
  164. """
  165. Don't warn if SECURE_HSTS_SECONDS isn't > 0 and SecurityMiddleware isn't
  166. installed.
  167. """
  168. self.assertEqual(base.check_sts(None), [])
  169. @override_settings(
  170. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  171. SECURE_HSTS_SECONDS=3600,
  172. )
  173. def test_with_sts(self):
  174. self.assertEqual(base.check_sts(None), [])
  175. class CheckStrictTransportSecuritySubdomainsTest(SimpleTestCase):
  176. @override_settings(
  177. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  178. SECURE_HSTS_INCLUDE_SUBDOMAINS=False,
  179. SECURE_HSTS_SECONDS=3600,
  180. )
  181. def test_no_sts_subdomains(self):
  182. """
  183. Warn if SECURE_HSTS_INCLUDE_SUBDOMAINS isn't True.
  184. """
  185. self.assertEqual(base.check_sts_include_subdomains(None), [base.W005])
  186. @override_settings(
  187. MIDDLEWARE=[],
  188. SECURE_HSTS_INCLUDE_SUBDOMAINS=False,
  189. SECURE_HSTS_SECONDS=3600,
  190. )
  191. def test_no_sts_subdomains_no_middleware(self):
  192. """
  193. Don't warn if SecurityMiddleware isn't installed.
  194. """
  195. self.assertEqual(base.check_sts_include_subdomains(None), [])
  196. @override_settings(
  197. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  198. SECURE_SSL_REDIRECT=False,
  199. SECURE_HSTS_SECONDS=None,
  200. )
  201. def test_no_sts_subdomains_no_seconds(self):
  202. """
  203. Don't warn if SECURE_HSTS_SECONDS isn't set.
  204. """
  205. self.assertEqual(base.check_sts_include_subdomains(None), [])
  206. @override_settings(
  207. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  208. SECURE_HSTS_INCLUDE_SUBDOMAINS=True,
  209. SECURE_HSTS_SECONDS=3600,
  210. )
  211. def test_with_sts_subdomains(self):
  212. self.assertEqual(base.check_sts_include_subdomains(None), [])
  213. class CheckStrictTransportSecurityPreloadTest(SimpleTestCase):
  214. @override_settings(
  215. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  216. SECURE_HSTS_PRELOAD=False,
  217. SECURE_HSTS_SECONDS=3600,
  218. )
  219. def test_no_sts_preload(self):
  220. """
  221. Warn if SECURE_HSTS_PRELOAD isn't True.
  222. """
  223. self.assertEqual(base.check_sts_preload(None), [base.W021])
  224. @override_settings(MIDDLEWARE=[], SECURE_HSTS_PRELOAD=False, SECURE_HSTS_SECONDS=3600)
  225. def test_no_sts_preload_no_middleware(self):
  226. """
  227. Don't warn if SecurityMiddleware isn't installed.
  228. """
  229. self.assertEqual(base.check_sts_preload(None), [])
  230. @override_settings(
  231. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  232. SECURE_SSL_REDIRECT=False,
  233. SECURE_HSTS_SECONDS=None,
  234. )
  235. def test_no_sts_preload_no_seconds(self):
  236. """
  237. Don't warn if SECURE_HSTS_SECONDS isn't set.
  238. """
  239. self.assertEqual(base.check_sts_preload(None), [])
  240. @override_settings(
  241. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  242. SECURE_HSTS_PRELOAD=True,
  243. SECURE_HSTS_SECONDS=3600,
  244. )
  245. def test_with_sts_preload(self):
  246. self.assertEqual(base.check_sts_preload(None), [])
  247. class CheckXFrameOptionsMiddlewareTest(SimpleTestCase):
  248. @override_settings(MIDDLEWARE=[])
  249. def test_middleware_not_installed(self):
  250. """
  251. Warn if XFrameOptionsMiddleware isn't in MIDDLEWARE.
  252. """
  253. self.assertEqual(base.check_xframe_options_middleware(None), [base.W002])
  254. @override_settings(MIDDLEWARE=["django.middleware.clickjacking.XFrameOptionsMiddleware"])
  255. def test_middleware_installed(self):
  256. self.assertEqual(base.check_xframe_options_middleware(None), [])
  257. class CheckXFrameOptionsDenyTest(SimpleTestCase):
  258. @override_settings(
  259. MIDDLEWARE=["django.middleware.clickjacking.XFrameOptionsMiddleware"],
  260. X_FRAME_OPTIONS='SAMEORIGIN',
  261. )
  262. def test_x_frame_options_not_deny(self):
  263. """
  264. Warn if XFrameOptionsMiddleware is in MIDDLEWARE but
  265. X_FRAME_OPTIONS isn't 'DENY'.
  266. """
  267. self.assertEqual(base.check_xframe_deny(None), [base.W019])
  268. @override_settings(MIDDLEWARE=[], X_FRAME_OPTIONS='SAMEORIGIN')
  269. def test_middleware_not_installed(self):
  270. """
  271. No error if XFrameOptionsMiddleware isn't in MIDDLEWARE even if
  272. X_FRAME_OPTIONS isn't 'DENY'.
  273. """
  274. self.assertEqual(base.check_xframe_deny(None), [])
  275. @override_settings(
  276. MIDDLEWARE=["django.middleware.clickjacking.XFrameOptionsMiddleware"],
  277. X_FRAME_OPTIONS='DENY',
  278. )
  279. def test_xframe_deny(self):
  280. self.assertEqual(base.check_xframe_deny(None), [])
  281. class CheckContentTypeNosniffTest(SimpleTestCase):
  282. @override_settings(
  283. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  284. SECURE_CONTENT_TYPE_NOSNIFF=False,
  285. )
  286. def test_no_content_type_nosniff(self):
  287. """
  288. Warn if SECURE_CONTENT_TYPE_NOSNIFF isn't True.
  289. """
  290. self.assertEqual(base.check_content_type_nosniff(None), [base.W006])
  291. @override_settings(MIDDLEWARE=[], SECURE_CONTENT_TYPE_NOSNIFF=False)
  292. def test_no_content_type_nosniff_no_middleware(self):
  293. """
  294. Don't warn if SECURE_CONTENT_TYPE_NOSNIFF isn't True and
  295. SecurityMiddleware isn't in MIDDLEWARE.
  296. """
  297. self.assertEqual(base.check_content_type_nosniff(None), [])
  298. @override_settings(
  299. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  300. SECURE_CONTENT_TYPE_NOSNIFF=True,
  301. )
  302. def test_with_content_type_nosniff(self):
  303. self.assertEqual(base.check_content_type_nosniff(None), [])
  304. class CheckSSLRedirectTest(SimpleTestCase):
  305. @override_settings(
  306. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  307. SECURE_SSL_REDIRECT=False,
  308. )
  309. def test_no_ssl_redirect(self):
  310. """
  311. Warn if SECURE_SSL_REDIRECT isn't True.
  312. """
  313. self.assertEqual(base.check_ssl_redirect(None), [base.W008])
  314. @override_settings(MIDDLEWARE=[], SECURE_SSL_REDIRECT=False)
  315. def test_no_ssl_redirect_no_middleware(self):
  316. """
  317. Don't warn if SECURE_SSL_REDIRECT is False and SecurityMiddleware isn't
  318. installed.
  319. """
  320. self.assertEqual(base.check_ssl_redirect(None), [])
  321. @override_settings(
  322. MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
  323. SECURE_SSL_REDIRECT=True,
  324. )
  325. def test_with_ssl_redirect(self):
  326. self.assertEqual(base.check_ssl_redirect(None), [])
  327. class CheckSecretKeyTest(SimpleTestCase):
  328. @override_settings(SECRET_KEY=('abcdefghijklmnopqrstuvwx' * 2) + 'ab')
  329. def test_okay_secret_key(self):
  330. self.assertEqual(len(settings.SECRET_KEY), base.SECRET_KEY_MIN_LENGTH)
  331. self.assertGreater(len(set(settings.SECRET_KEY)), base.SECRET_KEY_MIN_UNIQUE_CHARACTERS)
  332. self.assertEqual(base.check_secret_key(None), [])
  333. @override_settings(SECRET_KEY='')
  334. def test_empty_secret_key(self):
  335. self.assertEqual(base.check_secret_key(None), [base.W009])
  336. @override_settings(SECRET_KEY=None)
  337. def test_missing_secret_key(self):
  338. del settings.SECRET_KEY
  339. self.assertEqual(base.check_secret_key(None), [base.W009])
  340. @override_settings(SECRET_KEY=None)
  341. def test_none_secret_key(self):
  342. self.assertEqual(base.check_secret_key(None), [base.W009])
  343. @override_settings(
  344. SECRET_KEY=base.SECRET_KEY_INSECURE_PREFIX + get_random_secret_key()
  345. )
  346. def test_insecure_secret_key(self):
  347. self.assertEqual(base.check_secret_key(None), [base.W009])
  348. @override_settings(SECRET_KEY=('abcdefghijklmnopqrstuvwx' * 2) + 'a')
  349. def test_low_length_secret_key(self):
  350. self.assertEqual(len(settings.SECRET_KEY), base.SECRET_KEY_MIN_LENGTH - 1)
  351. self.assertEqual(base.check_secret_key(None), [base.W009])
  352. @override_settings(SECRET_KEY='abcd' * 20)
  353. def test_low_entropy_secret_key(self):
  354. self.assertGreater(len(settings.SECRET_KEY), base.SECRET_KEY_MIN_LENGTH)
  355. self.assertLess(len(set(settings.SECRET_KEY)), base.SECRET_KEY_MIN_UNIQUE_CHARACTERS)
  356. self.assertEqual(base.check_secret_key(None), [base.W009])
  357. class CheckDebugTest(SimpleTestCase):
  358. @override_settings(DEBUG=True)
  359. def test_debug_true(self):
  360. """
  361. Warn if DEBUG is True.
  362. """
  363. self.assertEqual(base.check_debug(None), [base.W018])
  364. @override_settings(DEBUG=False)
  365. def test_debug_false(self):
  366. self.assertEqual(base.check_debug(None), [])
  367. class CheckAllowedHostsTest(SimpleTestCase):
  368. @override_settings(ALLOWED_HOSTS=[])
  369. def test_allowed_hosts_empty(self):
  370. self.assertEqual(base.check_allowed_hosts(None), [base.W020])
  371. @override_settings(ALLOWED_HOSTS=['.example.com'])
  372. def test_allowed_hosts_set(self):
  373. self.assertEqual(base.check_allowed_hosts(None), [])
  374. class CheckReferrerPolicyTest(SimpleTestCase):
  375. @override_settings(
  376. MIDDLEWARE=['django.middleware.security.SecurityMiddleware'],
  377. SECURE_REFERRER_POLICY=None,
  378. )
  379. def test_no_referrer_policy(self):
  380. self.assertEqual(base.check_referrer_policy(None), [base.W022])
  381. @override_settings(MIDDLEWARE=[], SECURE_REFERRER_POLICY=None)
  382. def test_no_referrer_policy_no_middleware(self):
  383. """
  384. Don't warn if SECURE_REFERRER_POLICY is None and SecurityMiddleware
  385. isn't in MIDDLEWARE.
  386. """
  387. self.assertEqual(base.check_referrer_policy(None), [])
  388. @override_settings(MIDDLEWARE=['django.middleware.security.SecurityMiddleware'])
  389. def test_with_referrer_policy(self):
  390. tests = (
  391. 'strict-origin',
  392. 'strict-origin,origin',
  393. 'strict-origin, origin',
  394. ['strict-origin', 'origin'],
  395. ('strict-origin', 'origin'),
  396. )
  397. for value in tests:
  398. with self.subTest(value=value), override_settings(SECURE_REFERRER_POLICY=value):
  399. self.assertEqual(base.check_referrer_policy(None), [])
  400. @override_settings(
  401. MIDDLEWARE=['django.middleware.security.SecurityMiddleware'],
  402. SECURE_REFERRER_POLICY='invalid-value',
  403. )
  404. def test_with_invalid_referrer_policy(self):
  405. self.assertEqual(base.check_referrer_policy(None), [base.E023])
  406. def failure_view_with_invalid_signature():
  407. pass
  408. class CSRFFailureViewTest(SimpleTestCase):
  409. @override_settings(CSRF_FAILURE_VIEW='')
  410. def test_failure_view_import_error(self):
  411. self.assertEqual(
  412. csrf.check_csrf_failure_view(None),
  413. [
  414. Error(
  415. "The CSRF failure view '' could not be imported.",
  416. id='security.E025',
  417. )
  418. ],
  419. )
  420. @override_settings(
  421. CSRF_FAILURE_VIEW=f'{__name__}.failure_view_with_invalid_signature',
  422. )
  423. def test_failure_view_invalid_signature(self):
  424. msg = (
  425. "The CSRF failure view "
  426. "'check_framework.test_security.failure_view_with_invalid_signature' "
  427. "does not take the correct number of arguments."
  428. )
  429. self.assertEqual(
  430. csrf.check_csrf_failure_view(None),
  431. [Error(msg, id='security.E024')],
  432. )