10 Excellent Ways to Secure Your Spring Boot Application - Devoxx Morocco 2019

72a2082c6a4dd79ad68befb3db911616?s=47 Matt Raible
November 13, 2019

10 Excellent Ways to Secure Your Spring Boot Application - Devoxx Morocco 2019

Spring Boot is an excellent way to build Java applications with the Spring Framework. If you’re developing apps that handle sensitive data, you should make sure they’re secure.

This session will cover HTTPS, dependency checking, CSRF, using a CSP to prevent XSS, OIDC, password hashing, and much more!

You’ll learn how to add these features to a real application, using the Java language you know and love.

* Blog post: https://developer.okta.com/blog/2018/07/30/10-ways-to-secure-spring-boot
* Cheat sheet: https://snyk.io/blog/spring-boot-security-best-practices/

72a2082c6a4dd79ad68befb3db911616?s=128

Matt Raible

November 13, 2019
Tweet

Transcript

  1. 1.
  2. 2.
  3. 3.
  4. 5.
  5. 6.

    @Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void

    configure(HttpSecurity http) throws Exception { http.requiresChannel().anyRequest().requiresSecure(); } }
  6. 7.

    @Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void

    configure(HttpSecurity http) throws Exception { http.requiresChannel() .requestMatchers(r -> r.getHeader("X-Forwarded-Proto") != null) .requiresSecure(); } }
  7. 8.
  8. 9.
  9. 10.
  10. 11.
  11. 12.
  12. 13.

    'use strict'; const fetch = require('node-fetch'); const AWS = require('aws-sdk');

    // eslint-disable-line import/no-extraneous-dependencies const s3 = new AWS.S3(); module.exports.save = (event, context, callback) => { fetch(event.image_url) .then((response) => { if (response.ok) { return response; } return Promise.reject(new Error( `Failed to fetch ${response.url}: ${response.status} ${response.statusText}`)); }) .then(response => response.buffer()) .then(buffer => ( s3.putObject({ Bucket: process.env.BUCKET, Key: event.key, Body: buffer, }).promise() )) .then(v => callback(null, v), callback); };
  13. 14.

    'use strict'; const fetch = require('node-fetch'); const AWS = require('aws-sdk');

    // eslint-disable-line import/no-extraneous-dependencies const s3 = new AWS.S3(); module.exports.save = (event, context, callback) => { fetch(event.image_url) .then((response) => { if (response.ok) { return response; } return Promise.reject(new Error( `Failed to fetch ${response.url}: ${response.status} ${response.statusText}`)); }) .then(response => response.buffer()) .then(buffer => ( s3.putObject({ Bucket: process.env.BUCKET, Key: event.key, Body: buffer, }).promise() )) .then(v => callback(null, v), callback); }; { "dependencies": { "aws-sdk": "^2.7.9", "node-fetch": "^1.6.3" } }
  14. 15.

    'use strict'; const fetch = require('node-fetch'); const AWS = require('aws-sdk');

    // eslint-disable-line import/no-extraneous-dependencies const s3 = new AWS.S3(); module.exports.save = (event, context, callback) => { fetch(event.image_url) .then((response) => { if (response.ok) { return response; } return Promise.reject(new Error( `Failed to fetch ${response.url}: ${response.status} ${response.statusText}`)); }) .then(response => response.buffer()) .then(buffer => ( s3.putObject({ Bucket: process.env.BUCKET, Key: event.key, Body: buffer, }).promise() )) .then(v => callback(null, v), callback); }; { "dependencies": { "aws-sdk": "^2.7.9", "node-fetch": "^1.6.3" } }
  15. 16.

    'use strict'; const fetch = require('node-fetch'); const AWS = require('aws-sdk');

    // eslint-disable-line import/no-extraneous-dependencies const s3 = new AWS.S3(); module.exports.save = (event, context, callback) => { fetch(event.image_url) .then((response) => { if (response.ok) { return response; } return Promise.reject(new Error( `Failed to fetch ${response.url}: ${response.status} ${response.statusText}`)); }) .then(response => response.buffer()) .then(buffer => ( s3.putObject({ Bucket: process.env.BUCKET, Key: event.key, Body: buffer, }).promise() )) .then(v => callback(null, v), callback); }; { "dependencies": { "aws-sdk": "^2.7.9", "node-fetch": "^1.6.3" } }
  16. 17.
  17. 18.
  18. 19.
  19. 20.
  20. 21.
  21. 22.

    23

  22. 26.
  23. 27.

    @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void

    configure(HttpSecurity http) throws Exception { http .csrf() .csrfTokenRepository( CookieCsrfTokenRepository.withHttpOnlyFalse()); } }
  24. 28.
  25. 29.
  26. 30.

    Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Content-Type-Options:

    nosniff Strict-Transport-Security: max-age=31536000; includeSubDomains X-Frame-Options: DENY X-XSS-Protection: 1; mode=block
  27. 31.

    @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void

    configure(HttpSecurity http) throws Exception { http.headers() .contentSecurityPolicy("script-src 'self' " + "https://trustedscripts.example.com; " + "object-src https://trustedplugins.example.com; " + "report-uri /csp-report-endpoint/"); } }
  28. 32.
  29. 33.
  30. 34.
  31. 35.
  32. 36.
  33. 37.

    spring: security: oauth2: client: registration: okta: client-id: {clientId} client-secret: {clientSecret}

    provider: okta: issuer-uri: https://{yourOktaDomain}/oauth2/default
  34. 40.
  35. 41.
  36. 42.
  37. 49.
  38. 50.
  39. 51.
  40. 52.
  41. 56.
  42. 57.
  43. 58.
  44. 59.
  45. 62.
  46. 63.
  47. 64.
  48. 65.

    68