headers.adoc 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285
  1. [[servlet-headers]]
  2. = Security HTTP Response Headers
  3. You can use xref:features/exploits/headers.adoc#headers[Security HTTP Response Headers] to increase the security of web applications.
  4. This section is dedicated to servlet-based support for Security HTTP Response Headers.
  5. [[servlet-headers-default]]
  6. == Default Security Headers
  7. Spring Security provides a xref:features/exploits/headers.adoc#headers-default[default set of Security HTTP Response Headers] to provide secure defaults.
  8. While each of these headers are considered best practice, it should be noted that not all clients use the headers, so additional testing is encouraged.
  9. You can customize specific headers.
  10. For example, assume that you want the defaults but you wish to specify `SAMEORIGIN` for <<servlet-headers-frame-options,X-Frame-Options>>.
  11. You can do so with the following configuration:
  12. .Customize Default Security Headers
  13. [tabs]
  14. ======
  15. Java::
  16. +
  17. [source,java,role="primary"]
  18. ----
  19. @Configuration
  20. @EnableWebSecurity
  21. public class WebSecurityConfig {
  22. @Bean
  23. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  24. http
  25. // ...
  26. .headers((headers) -> headers
  27. .frameOptions((frameOptions) -> frameOptions
  28. .sameOrigin()
  29. )
  30. );
  31. return http.build();
  32. }
  33. }
  34. ----
  35. XML::
  36. +
  37. [source,xml,role="secondary"]
  38. ----
  39. <http>
  40. <!-- ... -->
  41. <headers>
  42. <frame-options policy="SAMEORIGIN" />
  43. </headers>
  44. </http>
  45. ----
  46. Kotlin::
  47. +
  48. [source,kotlin,role="secondary"]
  49. ----
  50. @Configuration
  51. @EnableWebSecurity
  52. class SecurityConfig {
  53. @Bean
  54. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  55. http {
  56. // ...
  57. headers {
  58. frameOptions {
  59. sameOrigin = true
  60. }
  61. }
  62. }
  63. return http.build()
  64. }
  65. }
  66. ----
  67. ======
  68. If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults.
  69. The next code listing shows how to do so.
  70. If you use Spring Security's configuration, the following adds only xref:features/exploits/headers.adoc#headers-cache-control[Cache Control]:
  71. .Customize Cache Control Headers
  72. [tabs]
  73. ======
  74. Java::
  75. +
  76. [source,java,role="primary"]
  77. ----
  78. @Configuration
  79. @EnableWebSecurity
  80. public class WebSecurityConfig {
  81. @Bean
  82. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  83. http
  84. // ...
  85. .headers((headers) -> headers
  86. // do not use any default headers unless explicitly listed
  87. .defaultsDisabled()
  88. .cacheControl(withDefaults())
  89. );
  90. return http.build();
  91. }
  92. }
  93. ----
  94. XML::
  95. +
  96. [source,xml,role="secondary"]
  97. ----
  98. <http>
  99. <!-- ... -->
  100. <headers defaults-disabled="true">
  101. <cache-control/>
  102. </headers>
  103. </http>
  104. ----
  105. Kotlin::
  106. +
  107. [source,kotlin,role="secondary"]
  108. ----
  109. @Configuration
  110. @EnableWebSecurity
  111. class SecurityConfig {
  112. @Bean
  113. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  114. http {
  115. // ...
  116. headers {
  117. // do not use any default headers unless explicitly listed
  118. defaultsDisabled = true
  119. cacheControl {
  120. }
  121. }
  122. }
  123. return http.build()
  124. }
  125. }
  126. ----
  127. ======
  128. If necessary, you can disable all of the HTTP Security response headers with the following configuration:
  129. .Disable All HTTP Security Headers
  130. [tabs]
  131. ======
  132. Java::
  133. +
  134. [source,java,role="primary"]
  135. ----
  136. @Configuration
  137. @EnableWebSecurity
  138. public class WebSecurityConfig {
  139. @Bean
  140. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  141. http
  142. // ...
  143. .headers((headers) -> headers.disable());
  144. return http.build();
  145. }
  146. }
  147. ----
  148. XML::
  149. +
  150. [source,xml,role="secondary"]
  151. ----
  152. <http>
  153. <!-- ... -->
  154. <headers disabled="true" />
  155. </http>
  156. ----
  157. Kotlin::
  158. +
  159. [source,kotlin,role="secondary"]
  160. ----
  161. @Configuration
  162. @EnableWebSecurity
  163. class SecurityConfig {
  164. @Bean
  165. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  166. http {
  167. // ...
  168. headers {
  169. disable()
  170. }
  171. }
  172. return http.build()
  173. }
  174. }
  175. ----
  176. ======
  177. [[servlet-headers-cache-control]]
  178. == Cache Control
  179. Spring Security includes xref:features/exploits/headers.adoc#headers-cache-control[Cache Control] headers by default.
  180. However, if you actually want to cache specific responses, your application can selectively invoke https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#setHeader(java.lang.String,java.lang.String)[`HttpServletResponse.setHeader(String,String)`] to override the header set by Spring Security.
  181. You can use this to ensure that content (such as CSS, JavaScript, and images) is properly cached.
  182. When you use Spring Web MVC, this is typically done within your configuration.
  183. You can find details on how to do this in the https://docs.spring.io/spring/docs/5.0.0.RELEASE/spring-framework-reference/web.html#mvc-config-static-resources[Static Resources] portion of the Spring Reference documentation
  184. If necessary, you can also disable Spring Security's cache control HTTP response headers.
  185. .Cache Control Disabled
  186. [tabs]
  187. ======
  188. Java::
  189. +
  190. [source,java,role="primary"]
  191. ----
  192. @Configuration
  193. @EnableWebSecurity
  194. public class WebSecurityConfig {
  195. @Bean
  196. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  197. http
  198. // ...
  199. .headers((headers) -> headers
  200. .cacheControl((cache) -> cache.disable())
  201. );
  202. return http.build();
  203. }
  204. }
  205. ----
  206. XML::
  207. +
  208. [source,xml,role="secondary"]
  209. ----
  210. <http>
  211. <!-- ... -->
  212. <headers>
  213. <cache-control disabled="true"/>
  214. </headers>
  215. </http>
  216. ----
  217. Kotlin::
  218. +
  219. [source,kotlin,role="secondary"]
  220. ----
  221. @Configuration
  222. @EnableWebSecurity
  223. class SecurityConfig {
  224. @Bean
  225. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  226. http {
  227. headers {
  228. cacheControl {
  229. disable()
  230. }
  231. }
  232. }
  233. return http.build()
  234. }
  235. }
  236. ----
  237. ======
  238. [[servlet-headers-content-type-options]]
  239. == Content Type Options
  240. Spring Security includes xref:features/exploits/headers.adoc#headers-content-type-options[Content-Type] headers by default.
  241. However, you can disable it:
  242. .Content Type Options Disabled
  243. [tabs]
  244. ======
  245. Java::
  246. +
  247. [source,java,role="primary"]
  248. ----
  249. @Configuration
  250. @EnableWebSecurity
  251. public class WebSecurityConfig {
  252. @Bean
  253. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  254. http
  255. // ...
  256. .headers((headers) -> headers
  257. .contentTypeOptions((contentTypeOptions) -> contentTypeOptions.disable())
  258. );
  259. return http.build();
  260. }
  261. }
  262. ----
  263. XML::
  264. +
  265. [source,xml,role="secondary"]
  266. ----
  267. <http>
  268. <!-- ... -->
  269. <headers>
  270. <content-type-options disabled="true"/>
  271. </headers>
  272. </http>
  273. ----
  274. Kotlin::
  275. +
  276. [source,kotlin,role="secondary"]
  277. ----
  278. @Configuration
  279. @EnableWebSecurity
  280. class SecurityConfig {
  281. @Bean
  282. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  283. http {
  284. headers {
  285. contentTypeOptions {
  286. disable()
  287. }
  288. }
  289. }
  290. return http.build()
  291. }
  292. }
  293. ----
  294. ======
  295. [[servlet-headers-hsts]]
  296. == HTTP Strict Transport Security (HSTS)
  297. By default, Spring Security provides the xref:features/exploits/headers.adoc#headers-hsts[Strict Transport Security] header.
  298. However, you can explicitly customize the results.
  299. The following example explicitly provides HSTS:
  300. .Strict Transport Security
  301. [tabs]
  302. ======
  303. Java::
  304. +
  305. [source,java,role="primary"]
  306. ----
  307. @Configuration
  308. @EnableWebSecurity
  309. public class WebSecurityConfig {
  310. @Bean
  311. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  312. http
  313. // ...
  314. .headers((headers) -> headers
  315. .httpStrictTransportSecurity((hsts) -> hsts
  316. .includeSubDomains(true)
  317. .preload(true)
  318. .maxAgeInSeconds(31536000)
  319. )
  320. );
  321. return http.build();
  322. }
  323. }
  324. ----
  325. XML::
  326. +
  327. [source,xml,role="secondary"]
  328. ----
  329. <http>
  330. <!-- ... -->
  331. <headers>
  332. <hsts
  333. include-subdomains="true"
  334. max-age-seconds="31536000"
  335. preload="true" />
  336. </headers>
  337. </http>
  338. ----
  339. Kotlin::
  340. +
  341. [source,kotlin,role="secondary"]
  342. ----
  343. @Configuration
  344. @EnableWebSecurity
  345. class SecurityConfig {
  346. @Bean
  347. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  348. http {
  349. headers {
  350. httpStrictTransportSecurity {
  351. includeSubDomains = true
  352. preload = true
  353. maxAgeInSeconds = 31536000
  354. }
  355. }
  356. }
  357. return http.build()
  358. }
  359. }
  360. ----
  361. ======
  362. [[servlet-headers-hpkp]]
  363. == HTTP Public Key Pinning (HPKP)
  364. Spring Security provides servlet support for xref:features/exploits/headers.adoc#headers-hpkp[HTTP Public Key Pinning], but it is xref:features/exploits/headers.adoc#headers-hpkp-deprecated[no longer recommended].
  365. You can enable HPKP headers with the following configuration:
  366. .HTTP Public Key Pinning
  367. [tabs]
  368. ======
  369. Java::
  370. +
  371. [source,java,role="primary"]
  372. ----
  373. @Configuration
  374. @EnableWebSecurity
  375. public class WebSecurityConfig {
  376. @Bean
  377. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  378. http
  379. // ...
  380. .headers((headers) -> headers
  381. .httpPublicKeyPinning((hpkp) -> hpkp
  382. .includeSubDomains(true)
  383. .reportUri("https://example.net/pkp-report")
  384. .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=")
  385. )
  386. );
  387. return http.build();
  388. }
  389. }
  390. ----
  391. XML::
  392. +
  393. [source,xml,role="secondary"]
  394. ----
  395. <http>
  396. <!-- ... -->
  397. <headers>
  398. <hpkp
  399. include-subdomains="true"
  400. report-uri="https://example.net/pkp-report">
  401. <pins>
  402. <pin algorithm="sha256">d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=</pin>
  403. <pin algorithm="sha256">E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=</pin>
  404. </pins>
  405. </hpkp>
  406. </headers>
  407. </http>
  408. ----
  409. Kotlin::
  410. +
  411. [source,kotlin,role="secondary"]
  412. ----
  413. @Configuration
  414. @EnableWebSecurity
  415. class SecurityConfig {
  416. @Bean
  417. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  418. http {
  419. headers {
  420. httpPublicKeyPinning {
  421. includeSubDomains = true
  422. reportUri = "https://example.net/pkp-report"
  423. pins = mapOf("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" to "sha256",
  424. "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" to "sha256")
  425. }
  426. }
  427. }
  428. return http.build()
  429. }
  430. }
  431. ----
  432. ======
  433. [[servlet-headers-frame-options]]
  434. == X-Frame-Options
  435. By default, Spring Security instructs browsers to block reflected XSS attacks by using the xref:features/exploits/headers.adoc#headers-frame-options[X-Frame-Options].
  436. For example, the following configuration specifies that Spring Security should no longer instruct browsers to block the content:
  437. .X-Frame-Options: SAMEORIGIN
  438. [tabs]
  439. ======
  440. Java::
  441. +
  442. [source,java,role="primary"]
  443. ----
  444. @Configuration
  445. @EnableWebSecurity
  446. public class WebSecurityConfig {
  447. @Bean
  448. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  449. http
  450. // ...
  451. .headers((headers) -> headers
  452. .frameOptions((frameOptions) -> frameOptions
  453. .sameOrigin()
  454. )
  455. );
  456. return http.build();
  457. }
  458. }
  459. ----
  460. XML::
  461. +
  462. [source,xml,role="secondary"]
  463. ----
  464. <http>
  465. <!-- ... -->
  466. <headers>
  467. <frame-options
  468. policy="SAMEORIGIN" />
  469. </headers>
  470. </http>
  471. ----
  472. Kotlin::
  473. +
  474. [source,kotlin,role="secondary"]
  475. ----
  476. @Configuration
  477. @EnableWebSecurity
  478. class SecurityConfig {
  479. @Bean
  480. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  481. http {
  482. headers {
  483. frameOptions {
  484. sameOrigin = true
  485. }
  486. }
  487. }
  488. return http.build()
  489. }
  490. }
  491. ----
  492. ======
  493. [[servlet-headers-xss-protection]]
  494. == X-XSS-Protection
  495. By default, Spring Security instructs browsers to disable the XSS Auditor by using <<headers-xss-protection,X-XSS-Protection header>.
  496. However, you can change this default.
  497. For example, the following configuration specifies that Spring Security instruct compatible browsers to enable filtering,
  498. and block the content:
  499. .X-XSS-Protection Customization
  500. [tabs]
  501. ======
  502. Java::
  503. +
  504. [source,java,role="primary"]
  505. ----
  506. @Configuration
  507. @EnableWebSecurity
  508. public class WebSecurityConfig {
  509. @Bean
  510. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  511. http
  512. // ...
  513. .headers((headers) -> headers
  514. .xssProtection((xss) -> xss
  515. .headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)
  516. )
  517. );
  518. return http.build();
  519. }
  520. }
  521. ----
  522. XML::
  523. +
  524. [source,xml,role="secondary"]
  525. ----
  526. <http>
  527. <!-- ... -->
  528. <headers>
  529. <xss-protection headerValue="1; mode=block"/>
  530. </headers>
  531. </http>
  532. ----
  533. Kotlin::
  534. +
  535. [source,kotlin,role="secondary"]
  536. ----
  537. @Configuration
  538. @EnableWebSecurity
  539. class SecurityConfig {
  540. @Bean
  541. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  542. // ...
  543. http {
  544. headers {
  545. xssProtection {
  546. headerValue = XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK
  547. }
  548. }
  549. }
  550. return http.build()
  551. }
  552. }
  553. ----
  554. ======
  555. [[servlet-headers-csp]]
  556. == Content Security Policy (CSP)
  557. Spring Security does not add xref:features/exploits/headers.adoc#headers-csp[Content Security Policy] by default, because a reasonable default is impossible to know without knowing the context of the application.
  558. The web application author must declare the security policy (or policies) to enforce or monitor for the protected resources.
  559. Consider the following security policy:
  560. .Content Security Policy Example
  561. [source,http]
  562. ----
  563. Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/
  564. ----
  565. Given the preceding security policy, you can enable the CSP header:
  566. .Content Security Policy
  567. [tabs]
  568. ======
  569. Java::
  570. +
  571. [source,java,role="primary"]
  572. ----
  573. @Configuration
  574. @EnableWebSecurity
  575. public class WebSecurityConfig {
  576. @Bean
  577. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  578. http
  579. // ...
  580. .headers((headers) -> headers
  581. .contentSecurityPolicy((csp) -> csp
  582. .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
  583. )
  584. );
  585. return http.build();
  586. }
  587. }
  588. ----
  589. XML::
  590. +
  591. [source,xml,role="secondary"]
  592. ----
  593. <http>
  594. <!-- ... -->
  595. <headers>
  596. <content-security-policy
  597. policy-directives="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/" />
  598. </headers>
  599. </http>
  600. ----
  601. Kotlin::
  602. +
  603. [source,kotlin,role="secondary"]
  604. ----
  605. @Configuration
  606. @EnableWebSecurity
  607. class SecurityConfig {
  608. @Bean
  609. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  610. http {
  611. // ...
  612. headers {
  613. contentSecurityPolicy {
  614. policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
  615. }
  616. }
  617. }
  618. return http.build()
  619. }
  620. }
  621. ----
  622. ======
  623. To enable the CSP `report-only` header, provide the following configuration:
  624. .Content Security Policy Report Only
  625. [tabs]
  626. ======
  627. Java::
  628. +
  629. [source,java,role="primary"]
  630. ----
  631. @Configuration
  632. @EnableWebSecurity
  633. public class WebSecurityConfig {
  634. @Bean
  635. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  636. http
  637. // ...
  638. .headers((headers) -> headers
  639. .contentSecurityPolicy((csp) -> csp
  640. .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
  641. .reportOnly()
  642. )
  643. );
  644. return http.build();
  645. }
  646. }
  647. ----
  648. XML::
  649. +
  650. [source,xml,role="secondary"]
  651. ----
  652. <http>
  653. <!-- ... -->
  654. <headers>
  655. <content-security-policy
  656. policy-directives="script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
  657. report-only="true" />
  658. </headers>
  659. </http>
  660. ----
  661. Kotlin::
  662. +
  663. [source,kotlin,role="secondary"]
  664. ----
  665. @Configuration
  666. @EnableWebSecurity
  667. class SecurityConfig {
  668. @Bean
  669. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  670. http {
  671. // ...
  672. headers {
  673. contentSecurityPolicy {
  674. policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
  675. reportOnly = true
  676. }
  677. }
  678. }
  679. return http.build()
  680. }
  681. }
  682. ----
  683. ======
  684. [[servlet-headers-referrer]]
  685. == Referrer Policy
  686. Spring Security does not add xref:features/exploits/headers.adoc#headers-referrer[Referrer Policy] headers by default.
  687. You can enable the Referrer Policy header by using the configuration:
  688. .Referrer Policy
  689. [tabs]
  690. ======
  691. Java::
  692. +
  693. [source,java,role="primary"]
  694. ----
  695. @Configuration
  696. @EnableWebSecurity
  697. public class WebSecurityConfig {
  698. @Bean
  699. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  700. http
  701. // ...
  702. .headers((headers) -> headers
  703. .referrerPolicy((referrer) -> referrer
  704. .policy(ReferrerPolicy.SAME_ORIGIN)
  705. )
  706. );
  707. return http.build();
  708. }
  709. }
  710. ----
  711. XML::
  712. +
  713. [source,xml,role="secondary"]
  714. ----
  715. <http>
  716. <!-- ... -->
  717. <headers>
  718. <referrer-policy policy="same-origin" />
  719. </headers>
  720. </http>
  721. ----
  722. Kotlin::
  723. +
  724. [source,kotlin,role="secondary"]
  725. ----
  726. @Configuration
  727. @EnableWebSecurity
  728. class SecurityConfig {
  729. @Bean
  730. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  731. http {
  732. // ...
  733. headers {
  734. referrerPolicy {
  735. policy = ReferrerPolicy.SAME_ORIGIN
  736. }
  737. }
  738. }
  739. return http.build()
  740. }
  741. }
  742. ----
  743. ======
  744. [[servlet-headers-feature]]
  745. == Feature Policy
  746. Spring Security does not add xref:features/exploits/headers.adoc#headers-feature[Feature Policy] headers by default.
  747. Consider the following `Feature-Policy` header:
  748. .Feature-Policy Example
  749. [source]
  750. ----
  751. Feature-Policy: geolocation 'self'
  752. ----
  753. You can enable the preceding feature policy header by using the following configuration:
  754. .Feature-Policy
  755. [tabs]
  756. ======
  757. Java::
  758. +
  759. [source,java,role="primary"]
  760. ----
  761. @Configuration
  762. @EnableWebSecurity
  763. public class WebSecurityConfig {
  764. @Bean
  765. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  766. http
  767. // ...
  768. .headers((headers) -> headers
  769. .featurePolicy("geolocation 'self'")
  770. );
  771. return http.build();
  772. }
  773. }
  774. ----
  775. XML::
  776. +
  777. [source,xml,role="secondary"]
  778. ----
  779. <http>
  780. <!-- ... -->
  781. <headers>
  782. <feature-policy policy-directives="geolocation 'self'" />
  783. </headers>
  784. </http>
  785. ----
  786. Kotlin::
  787. +
  788. [source,kotlin,role="secondary"]
  789. ----
  790. @Configuration
  791. @EnableWebSecurity
  792. class SecurityConfig {
  793. @Bean
  794. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  795. http {
  796. // ...
  797. headers {
  798. featurePolicy("geolocation 'self'")
  799. }
  800. }
  801. return http.build()
  802. }
  803. }
  804. ----
  805. ======
  806. [[servlet-headers-permissions]]
  807. == Permissions Policy
  808. Spring Security does not add xref:features/exploits/headers.adoc#headers-permissions[Permissions Policy] headers by default.
  809. Consider the following `Permissions-Policy` header:
  810. .Permissions-Policy Example
  811. [source]
  812. ----
  813. Permissions-Policy: geolocation=(self)
  814. ----
  815. You can enable the preceding permissions policy header using the following configuration:
  816. .Permissions-Policy
  817. [tabs]
  818. ======
  819. Java::
  820. +
  821. [source,java,role="primary"]
  822. ----
  823. @Configuration
  824. @EnableWebSecurity
  825. public class WebSecurityConfig {
  826. @Bean
  827. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  828. http
  829. // ...
  830. .headers((headers) -> headers
  831. .permissionsPolicy((permissions) -> permissions
  832. .policy("geolocation=(self)")
  833. )
  834. );
  835. return http.build();
  836. }
  837. }
  838. ----
  839. XML::
  840. +
  841. [source,xml,role="secondary"]
  842. ----
  843. <http>
  844. <!-- ... -->
  845. <headers>
  846. <permissions-policy policy="geolocation=(self)" />
  847. </headers>
  848. </http>
  849. ----
  850. Kotlin::
  851. +
  852. [source,kotlin,role="secondary"]
  853. ----
  854. @Configuration
  855. @EnableWebSecurity
  856. class SecurityConfig {
  857. @Bean
  858. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  859. http {
  860. // ...
  861. headers {
  862. permissionPolicy {
  863. policy = "geolocation=(self)"
  864. }
  865. }
  866. }
  867. return http.build()
  868. }
  869. }
  870. ----
  871. ======
  872. [[servlet-headers-clear-site-data]]
  873. == Clear Site Data
  874. Spring Security does not add xref:features/exploits/headers.adoc#headers-clear-site-data[Clear-Site-Data] headers by default.
  875. Consider the following Clear-Site-Data header:
  876. .Clear-Site-Data Example
  877. ----
  878. Clear-Site-Data: "cache", "cookies"
  879. ----
  880. You can send the preceding header on log out with the following configuration:
  881. .Clear-Site-Data
  882. [tabs]
  883. ======
  884. Java::
  885. +
  886. [source,java,role="primary"]
  887. ----
  888. @Configuration
  889. @EnableWebSecurity
  890. public class WebSecurityConfig {
  891. @Bean
  892. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  893. http
  894. // ...
  895. .logout((logout) -> logout
  896. .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(CACHE, COOKIES)))
  897. );
  898. return http.build();
  899. }
  900. }
  901. ----
  902. Kotlin::
  903. +
  904. [source,kotlin,role="secondary"]
  905. ----
  906. @Configuration
  907. @EnableWebSecurity
  908. class SecurityConfig {
  909. @Bean
  910. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  911. http {
  912. // ...
  913. logout {
  914. addLogoutHandler(HeaderWriterLogoutHandler(ClearSiteDataHeaderWriter(CACHE, COOKIES)))
  915. }
  916. }
  917. return http.build()
  918. }
  919. }
  920. ----
  921. ======
  922. [[servlet-headers-custom]]
  923. == Custom Headers
  924. Spring Security has mechanisms to make it convenient to add the more common security headers to your application.
  925. However, it also provides hooks to enable adding custom headers.
  926. [[servlet-headers-static]]
  927. === Static Headers
  928. There may be times when you wish to inject custom security headers that are not supported out of the box into your application.
  929. Consider the following custom security header:
  930. [source]
  931. ----
  932. X-Custom-Security-Header: header-value
  933. ----
  934. Given the preceding header, you could add the headers to the response by using the following configuration:
  935. .StaticHeadersWriter
  936. [tabs]
  937. ======
  938. Java::
  939. +
  940. [source,java,role="primary"]
  941. ----
  942. @Configuration
  943. @EnableWebSecurity
  944. public class WebSecurityConfig {
  945. @Bean
  946. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  947. http
  948. // ...
  949. .headers((headers) -> headers
  950. .addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value"))
  951. );
  952. return http.build();
  953. }
  954. }
  955. ----
  956. XML::
  957. +
  958. [source,xml,role="secondary"]
  959. ----
  960. <http>
  961. <!-- ... -->
  962. <headers>
  963. <header name="X-Custom-Security-Header" value="header-value"/>
  964. </headers>
  965. </http>
  966. ----
  967. Kotlin::
  968. +
  969. [source,kotlin,role="secondary"]
  970. ----
  971. @Configuration
  972. @EnableWebSecurity
  973. class SecurityConfig {
  974. @Bean
  975. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  976. http {
  977. // ...
  978. headers {
  979. addHeaderWriter(StaticHeadersWriter("X-Custom-Security-Header","header-value"))
  980. }
  981. }
  982. return http.build()
  983. }
  984. }
  985. ----
  986. ======
  987. [[servlet-headers-writer]]
  988. === Headers Writer
  989. When the namespace or Java configuration does not support the headers you want, you can create a custom `HeadersWriter` instance or even provide a custom implementation of the `HeadersWriter`.
  990. The next example use a custom instance of `XFrameOptionsHeaderWriter`.
  991. If you wanted to explicitly configure <<servlet-headers-frame-options>>, you could do so with the following configuration:
  992. .Headers Writer
  993. [tabs]
  994. ======
  995. Java::
  996. +
  997. [source,java,role="primary"]
  998. ----
  999. @Configuration
  1000. @EnableWebSecurity
  1001. public class WebSecurityConfig {
  1002. @Bean
  1003. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  1004. http
  1005. // ...
  1006. .headers((headers) -> headers
  1007. .addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
  1008. );
  1009. return http.build();
  1010. }
  1011. }
  1012. ----
  1013. XML::
  1014. +
  1015. [source,xml,role="secondary"]
  1016. ----
  1017. <http>
  1018. <!-- ... -->
  1019. <headers>
  1020. <header ref="frameOptionsWriter"/>
  1021. </headers>
  1022. </http>
  1023. <!-- Requires the c-namespace.
  1024. See https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-c-namespace
  1025. -->
  1026. <beans:bean id="frameOptionsWriter"
  1027. class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter"
  1028. c:frameOptionsMode="SAMEORIGIN"/>
  1029. ----
  1030. Kotlin::
  1031. +
  1032. [source,kotlin,role="secondary"]
  1033. ----
  1034. @Configuration
  1035. @EnableWebSecurity
  1036. class SecurityConfig {
  1037. @Bean
  1038. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  1039. http {
  1040. // ...
  1041. headers {
  1042. addHeaderWriter(XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
  1043. }
  1044. }
  1045. return http.build()
  1046. }
  1047. }
  1048. ----
  1049. ======
  1050. [[headers-delegatingrequestmatcherheaderwriter]]
  1051. === DelegatingRequestMatcherHeaderWriter
  1052. At times, you may want to write a header only for certain requests.
  1053. For example, perhaps you want to protect only your login page from being framed.
  1054. You could use the `DelegatingRequestMatcherHeaderWriter` to do so.
  1055. The following configuration example uses `DelegatingRequestMatcherHeaderWriter`:
  1056. .DelegatingRequestMatcherHeaderWriter Java Configuration
  1057. [tabs]
  1058. ======
  1059. Java::
  1060. +
  1061. [source,java,role="primary"]
  1062. ----
  1063. @Configuration
  1064. @EnableWebSecurity
  1065. public class WebSecurityConfig {
  1066. @Bean
  1067. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  1068. RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher("/login");
  1069. DelegatingRequestMatcherHeaderWriter headerWriter =
  1070. new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter());
  1071. http
  1072. // ...
  1073. .headers((headers) -> headers
  1074. .frameOptions((frameOptions) -> frameOptions.disable())
  1075. .addHeaderWriter(headerWriter)
  1076. );
  1077. return http.build();
  1078. }
  1079. }
  1080. ----
  1081. XML::
  1082. +
  1083. [source,xml,role="secondary"]
  1084. ----
  1085. <http>
  1086. <!-- ... -->
  1087. <headers>
  1088. <frame-options disabled="true"/>
  1089. <header ref="headerWriter"/>
  1090. </headers>
  1091. </http>
  1092. <beans:bean id="headerWriter"
  1093. class="org.springframework.security.web.header.writers.DelegatingRequestMatcherHeaderWriter">
  1094. <beans:constructor-arg>
  1095. <bean class="org.springframework.security.config.http.PathPatternRequestMatcherFactoryBean"
  1096. c:pattern="/login"/>
  1097. </beans:constructor-arg>
  1098. <beans:constructor-arg>
  1099. <beans:bean
  1100. class="org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter"/>
  1101. </beans:constructor-arg>
  1102. </beans:bean>
  1103. ----
  1104. Kotlin::
  1105. +
  1106. [source,kotlin,role="secondary"]
  1107. ----
  1108. @Configuration
  1109. @EnableWebSecurity
  1110. class SecurityConfig {
  1111. @Bean
  1112. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  1113. val matcher: RequestMatcher = PathPatternRequestMatcher.withDefaults().matcher("/login")
  1114. val headerWriter = DelegatingRequestMatcherHeaderWriter(matcher, XFrameOptionsHeaderWriter())
  1115. http {
  1116. headers {
  1117. frameOptions {
  1118. disable()
  1119. }
  1120. addHeaderWriter(headerWriter)
  1121. }
  1122. }
  1123. return http.build()
  1124. }
  1125. }
  1126. ----
  1127. ======