2
0

headers.adoc 28 KB

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