headers.adoc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. [[webflux-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 WebFlux based support for Security HTTP Response Headers.
  5. [[webflux-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 xref:servlet/exploits/headers.adoc#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. @Bean
  20. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  21. http
  22. // ...
  23. .headers(headers -> headers
  24. .frameOptions(frameOptions -> frameOptions
  25. .mode(Mode.SAMEORIGIN)
  26. )
  27. );
  28. return http.build();
  29. }
  30. ----
  31. Kotlin::
  32. +
  33. [source,kotlin,role="secondary"]
  34. ----
  35. @Bean
  36. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  37. return http {
  38. // ...
  39. headers {
  40. frameOptions {
  41. mode = Mode.SAMEORIGIN
  42. }
  43. }
  44. }
  45. }
  46. ----
  47. ======
  48. If you do not want the defaults to be added and want explicit control over what should be used, you can disable the defaults.
  49. An example is provided below:
  50. .Disable HTTP Security Response Headers
  51. [tabs]
  52. ======
  53. Java::
  54. +
  55. [source,java,role="primary"]
  56. ----
  57. @Bean
  58. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  59. http
  60. // ...
  61. .headers(headers -> headers.disable());
  62. return http.build();
  63. }
  64. ----
  65. Kotlin::
  66. +
  67. [source,kotlin,role="secondary"]
  68. ----
  69. @Bean
  70. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  71. return http {
  72. // ...
  73. headers {
  74. disable()
  75. }
  76. }
  77. }
  78. ----
  79. ======
  80. [[webflux-headers-cache-control]]
  81. == Cache Control
  82. Spring Security includes xref:features/exploits/headers.adoc#headers-cache-control[Cache Control] headers by default.
  83. However, if you actually want to cache specific responses, your application can selectively add them to the https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/server/reactive/ServerHttpResponse.html[ServerHttpResponse] to override the header set by Spring Security.
  84. This is useful to ensure things like CSS, JavaScript, and images are properly cached.
  85. When using Spring WebFlux, this is typically done within your configuration.
  86. 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-reactive.html#webflux-config-static-resources[Static Resources] portion of the Spring Reference documentation
  87. If necessary, you can also disable Spring Security's cache control HTTP response headers.
  88. .Cache Control Disabled
  89. [tabs]
  90. ======
  91. Java::
  92. +
  93. [source,java,role="primary"]
  94. ----
  95. @Bean
  96. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  97. http
  98. // ...
  99. .headers(headers -> headers
  100. .cache(cache -> cache.disable())
  101. );
  102. return http.build();
  103. }
  104. ----
  105. Kotlin::
  106. +
  107. [source,kotlin,role="secondary"]
  108. ----
  109. @Bean
  110. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  111. return http {
  112. // ...
  113. headers {
  114. cache {
  115. disable()
  116. }
  117. }
  118. }
  119. }
  120. ----
  121. ======
  122. [[webflux-headers-content-type-options]]
  123. == Content Type Options
  124. Spring Security includes xref:features/exploits/headers.adoc#headers-content-type-options[Content-Type] headers by default.
  125. However, you can disable it with:
  126. .Content Type Options Disabled
  127. [tabs]
  128. ======
  129. Java::
  130. +
  131. [source,java,role="primary"]
  132. ----
  133. @Bean
  134. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  135. http
  136. // ...
  137. .headers(headers -> headers
  138. .contentTypeOptions(contentTypeOptions -> contentTypeOptions.disable())
  139. );
  140. return http.build();
  141. }
  142. ----
  143. Kotlin::
  144. +
  145. [source,kotlin,role="secondary"]
  146. ----
  147. @Bean
  148. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  149. return http {
  150. // ...
  151. headers {
  152. contentTypeOptions {
  153. disable()
  154. }
  155. }
  156. }
  157. }
  158. ----
  159. ======
  160. [[webflux-headers-hsts]]
  161. == HTTP Strict Transport Security (HSTS)
  162. Spring Security provides the xref:features/exploits/headers.adoc#headers-hsts[Strict Transport Security] header by default.
  163. However, you can customize the results explicitly.
  164. For example, the following is an example of explicitly providing HSTS:
  165. .Strict Transport Security
  166. [tabs]
  167. ======
  168. Java::
  169. +
  170. [source,java,role="primary"]
  171. ----
  172. @Bean
  173. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  174. http
  175. // ...
  176. .headers(headers -> headers
  177. .hsts(hsts -> hsts
  178. .includeSubdomains(true)
  179. .preload(true)
  180. .maxAge(Duration.ofDays(365))
  181. )
  182. );
  183. return http.build();
  184. }
  185. ----
  186. Kotlin::
  187. +
  188. [source,kotlin,role="secondary"]
  189. ----
  190. @Bean
  191. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  192. return http {
  193. // ...
  194. headers {
  195. hsts {
  196. includeSubdomains = true
  197. preload = true
  198. maxAge = Duration.ofDays(365)
  199. }
  200. }
  201. }
  202. }
  203. ----
  204. ======
  205. [[webflux-headers-frame-options]]
  206. == X-Frame-Options
  207. By default, Spring Security disables rendering within an iframe using xref:features/exploits/headers.adoc#headers-frame-options[X-Frame-Options].
  208. You can customize frame options to use the same origin using the following:
  209. .X-Frame-Options: SAMEORIGIN
  210. [tabs]
  211. ======
  212. Java::
  213. +
  214. [source,java,role="primary"]
  215. ----
  216. @Bean
  217. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  218. http
  219. // ...
  220. .headers(headers -> headers
  221. .frameOptions(frameOptions -> frameOptions
  222. .mode(SAMEORIGIN)
  223. )
  224. );
  225. return http.build();
  226. }
  227. ----
  228. Kotlin::
  229. +
  230. [source,kotlin,role="secondary"]
  231. ----
  232. @Bean
  233. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  234. return http {
  235. // ...
  236. headers {
  237. frameOptions {
  238. mode = SAMEORIGIN
  239. }
  240. }
  241. }
  242. }
  243. ----
  244. ======
  245. [[webflux-headers-xss-protection]]
  246. == X-XSS-Protection
  247. By default, Spring Security instructs browsers to block reflected XSS attacks using the <<headers-xss-protection,X-XSS-Protection header>.
  248. You can disable `X-XSS-Protection` with the following Configuration:
  249. .X-XSS-Protection Customization
  250. [tabs]
  251. ======
  252. Java::
  253. +
  254. [source,java,role="primary"]
  255. ----
  256. @Bean
  257. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  258. http
  259. // ...
  260. .headers(headers -> headers
  261. .xssProtection(xssProtection -> xssProtection.disable())
  262. );
  263. return http.build();
  264. }
  265. ----
  266. Kotlin::
  267. +
  268. [source,kotlin,role="secondary"]
  269. ----
  270. @Bean
  271. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  272. return http {
  273. // ...
  274. headers {
  275. xssProtection {
  276. disable()
  277. }
  278. }
  279. }
  280. }
  281. ----
  282. ======
  283. [[webflux-headers-csp]]
  284. == Content Security Policy (CSP)
  285. 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.
  286. The web application author must declare the security policy(s) to enforce and/or monitor for the protected resources.
  287. For example, given the following security policy:
  288. .Content Security Policy Example
  289. [source,http]
  290. ----
  291. Content-Security-Policy: script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/
  292. ----
  293. You can enable the CSP header as shown below:
  294. .Content Security Policy
  295. [tabs]
  296. ======
  297. Java::
  298. +
  299. [source,java,role="primary"]
  300. ----
  301. @Bean
  302. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  303. http
  304. // ...
  305. .headers(headers -> headers
  306. .contentSecurityPolicy(policy -> policy
  307. .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
  308. )
  309. );
  310. return http.build();
  311. }
  312. ----
  313. Kotlin::
  314. +
  315. [source,kotlin,role="secondary"]
  316. ----
  317. @Bean
  318. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  319. return http {
  320. // ...
  321. headers {
  322. contentSecurityPolicy {
  323. policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
  324. }
  325. }
  326. }
  327. }
  328. ----
  329. ======
  330. To enable the CSP `report-only` header, provide the following configuration:
  331. .Content Security Policy Report Only
  332. [tabs]
  333. ======
  334. Java::
  335. +
  336. [source,java,role="primary"]
  337. ----
  338. @Bean
  339. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  340. http
  341. // ...
  342. .headers(headers -> headers
  343. .contentSecurityPolicy(policy -> policy
  344. .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
  345. .reportOnly()
  346. )
  347. );
  348. return http.build();
  349. }
  350. ----
  351. Kotlin::
  352. +
  353. [source,kotlin,role="secondary"]
  354. ----
  355. @Bean
  356. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  357. return http {
  358. // ...
  359. headers {
  360. contentSecurityPolicy {
  361. policyDirectives = "script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/"
  362. reportOnly = true
  363. }
  364. }
  365. }
  366. }
  367. ----
  368. ======
  369. [[webflux-headers-referrer]]
  370. == Referrer Policy
  371. Spring Security does not add xref:features/exploits/headers.adoc#headers-referrer[Referrer Policy] headers by default.
  372. You can enable the Referrer Policy header using configuration as shown below:
  373. .Referrer Policy Configuration
  374. [tabs]
  375. ======
  376. Java::
  377. +
  378. [source,java,role="primary"]
  379. ----
  380. @Bean
  381. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  382. http
  383. // ...
  384. .headers(headers -> headers
  385. .referrerPolicy(referrer -> referrer
  386. .policy(ReferrerPolicy.SAME_ORIGIN)
  387. )
  388. );
  389. return http.build();
  390. }
  391. ----
  392. Kotlin::
  393. +
  394. [source,kotlin,role="secondary"]
  395. ----
  396. @Bean
  397. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  398. return http {
  399. // ...
  400. headers {
  401. referrerPolicy {
  402. policy = ReferrerPolicy.SAME_ORIGIN
  403. }
  404. }
  405. }
  406. }
  407. ----
  408. ======
  409. [[webflux-headers-feature]]
  410. == Feature Policy
  411. Spring Security does not add xref:features/exploits/headers.adoc#headers-feature[Feature Policy] headers by default.
  412. The following `Feature-Policy` header:
  413. .Feature-Policy Example
  414. [source]
  415. ----
  416. Feature-Policy: geolocation 'self'
  417. ----
  418. You can enable the Feature Policy header as shown below:
  419. .Feature-Policy Configuration
  420. [tabs]
  421. ======
  422. Java::
  423. +
  424. [source,java,role="primary"]
  425. ----
  426. @Bean
  427. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  428. http
  429. // ...
  430. .headers(headers -> headers
  431. .featurePolicy("geolocation 'self'")
  432. );
  433. return http.build();
  434. }
  435. ----
  436. Kotlin::
  437. +
  438. [source,kotlin,role="secondary"]
  439. ----
  440. @Bean
  441. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  442. return http {
  443. // ...
  444. headers {
  445. featurePolicy("geolocation 'self'")
  446. }
  447. }
  448. }
  449. ----
  450. ======
  451. [[webflux-headers-permissions]]
  452. == Permissions Policy
  453. Spring Security does not add xref:features/exploits/headers.adoc#headers-permissions[Permissions Policy] headers by default.
  454. The following `Permissions-Policy` header:
  455. .Permissions-Policy Example
  456. [source]
  457. ----
  458. Permissions-Policy: geolocation=(self)
  459. ----
  460. You can enable the Permissions Policy header as shown below:
  461. .Permissions-Policy Configuration
  462. [tabs]
  463. ======
  464. Java::
  465. +
  466. [source,java,role="primary"]
  467. ----
  468. @Bean
  469. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  470. http
  471. // ...
  472. .headers(headers -> headers
  473. .permissionsPolicy(permissions -> permissions
  474. .policy("geolocation=(self)")
  475. )
  476. );
  477. return http.build();
  478. }
  479. ----
  480. Kotlin::
  481. +
  482. [source,kotlin,role="secondary"]
  483. ----
  484. @Bean
  485. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  486. return http {
  487. // ...
  488. headers {
  489. permissionsPolicy {
  490. policy = "geolocation=(self)"
  491. }
  492. }
  493. }
  494. }
  495. ----
  496. ======
  497. [[webflux-headers-clear-site-data]]
  498. == Clear Site Data
  499. Spring Security does not add xref:features/exploits/headers.adoc#headers-clear-site-data[Clear-Site-Data] headers by default.
  500. The following Clear-Site-Data header:
  501. .Clear-Site-Data Example
  502. ----
  503. Clear-Site-Data: "cache", "cookies"
  504. ----
  505. can be sent on log out with the following configuration:
  506. .Clear-Site-Data Configuration
  507. [tabs]
  508. ======
  509. Java::
  510. +
  511. [source,java,role="primary"]
  512. ----
  513. @Bean
  514. SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  515. ServerLogoutHandler securityContext = new SecurityContextServerLogoutHandler();
  516. ClearSiteDataServerHttpHeadersWriter writer = new ClearSiteDataServerHttpHeadersWriter(CACHE, COOKIES);
  517. ServerLogoutHandler clearSiteData = new HeaderWriterServerLogoutHandler(writer);
  518. DelegatingServerLogoutHandler logoutHandler = new DelegatingServerLogoutHandler(securityContext, clearSiteData);
  519. http
  520. // ...
  521. .logout()
  522. .logoutHandler(logoutHandler);
  523. return http.build();
  524. }
  525. ----
  526. Kotlin::
  527. +
  528. [source,kotlin,role="secondary"]
  529. ----
  530. @Bean
  531. fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  532. val securityContext: ServerLogoutHandler = SecurityContextServerLogoutHandler()
  533. val writer = ClearSiteDataServerHttpHeadersWriter(CACHE, COOKIES)
  534. val clearSiteData: ServerLogoutHandler = HeaderWriterServerLogoutHandler(writer)
  535. val customLogoutHandler = DelegatingServerLogoutHandler(securityContext, clearSiteData)
  536. return http {
  537. // ...
  538. logout {
  539. logoutHandler = customLogoutHandler
  540. }
  541. }
  542. }
  543. ----
  544. ======
  545. [[webflux-headers-cross-origin-policies]]
  546. == Cross-Origin Policies
  547. Spring Security provides built-in support for adding some Cross-Origin policies headers, those headers are:
  548. [source]
  549. ----
  550. Cross-Origin-Opener-Policy
  551. Cross-Origin-Embedder-Policy
  552. Cross-Origin-Resource-Policy
  553. ----
  554. Spring Security does not add <<headers-cross-origin-policies,Cross-Origin Policies>> headers by default.
  555. The headers can be added with the following configuration:
  556. .Cross-Origin Policies
  557. [tabs]
  558. ======
  559. Java::
  560. +
  561. [source,java,role="primary"]
  562. ----
  563. @EnableWebFluxSecurity
  564. @EnableWebFlux
  565. public class WebSecurityConfig {
  566. @Bean
  567. SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) {
  568. http.headers((headers) -> headers
  569. .crossOriginOpenerPolicy(CrossOriginOpenerPolicy.SAME_ORIGIN)
  570. .crossOriginEmbedderPolicy(CrossOriginEmbedderPolicy.REQUIRE_CORP)
  571. .crossOriginResourcePolicy(CrossOriginResourcePolicy.SAME_ORIGIN));
  572. return http.build();
  573. }
  574. }
  575. ----
  576. Kotlin::
  577. +
  578. [source,kotlin,role="secondary"]
  579. ----
  580. @EnableWebFluxSecurity
  581. @EnableWebFlux
  582. open class CrossOriginPoliciesCustomConfig {
  583. @Bean
  584. open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
  585. return http {
  586. headers {
  587. crossOriginOpenerPolicy(CrossOriginOpenerPolicy.SAME_ORIGIN)
  588. crossOriginEmbedderPolicy(CrossOriginEmbedderPolicy.REQUIRE_CORP)
  589. crossOriginResourcePolicy(CrossOriginResourcePolicy.SAME_ORIGIN)
  590. }
  591. }
  592. }
  593. }
  594. ----
  595. ======
  596. This configuration will write the headers with the values provided:
  597. [source]
  598. ----
  599. Cross-Origin-Opener-Policy: same-origin
  600. Cross-Origin-Embedder-Policy: require-corp
  601. Cross-Origin-Resource-Policy: same-origin
  602. ----