Spring Security

From bibbleWiki
Jump to navigation Jump to search

Introduction

Authentication

Spring Security Provides out of the box

  • Basic Web From Authentication
  • Ouath2 and OpenID Connect
  • LDAP
  • JWT JSon Web Tokens

Protection

Includes strategies for

  • Session Fixation (Reusing of the Session ID)
  • Clickjacking(UI redress attack)
  • Cross Site Scripting
  • Cross Site Request Forgery (CSRF)

Session Fixation (Reusing of the Session ID)

Session Fixation is an attack that permits an attacker to hijack a valid user session. The attack explores a limitation in the way the web application manages the session ID, more specifically the vulnerable web application. When authenticating a user, it doesn’t assign a new session ID, making it possible to use an existent session ID. The attack consists of obtaining a valid session ID (e.g. by connecting to the application), inducing a user to authenticate himself with that session ID, and then hijacking the user-validated session by the knowledge of the used session ID. The attacker has to provide a legitimate Web application session ID and try to make the victim’s browser use it.

Clickjacking(UI redress attack)

This is when an attacker uses multiple transparent or opaque layers to trick a user into clicking on a button or link on another page when they were intending to click on the top level page. Thus, the attacker is “hijacking” clicks meant for their page and routing them to another page, most likely owned by another application, domain, or both.

Cross Site Request Forgery (CSRF)

Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they’re currently authenticated. With a little help of social engineering (such as sending a link via email or chat), an attacker may trick the users of a web application into executing actions of the attacker’s choosing. If the victim is a normal user, a successful CSRF attack can force the user to perform state changing requests like transferring funds, changing their email address, and so forth. If the victim is an administrative account, CSRF can compromise the entire web application.

Cross Site Scripting

Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they’re currently authenticated. With a little help of social engineering (such as sending a link via email or chat), an attacker may trick the users of a web application into executing actions of the attacker’s choosing. If the victim is a normal user, a successful CSRF attack can force the user to perform state changing requests like transferring funds, changing their email address, and so forth. If the victim is an administrative account, CSRF can compromise the entire web application.

Spring Security Projects

The framework is broken own into different projects

  • Spring Security Core
  • Spring Security Config
  • Spring Security Test
  • Spring Security Web
  • Spring Security Oauth
  • Spring Security LDAP

Resources

Demos

https://github.com/wlesniak/spring-framework-securing-against-common-threats https://github.com/bh5k/spring-security-conference

Tomcat

Install Ubuntu 20.1

sudo useradd -m -U -d /opt/tomcat -s /bin/false tomcat
VERSION=9.0.35
wget https://www-eu.apache.org/dist/tomcat/tomcat-9/v${VERSION}/bin/apache-tomcat-${VERSION}.tar.gz -P /tmp
sudo tar -xf /tmp/apache-tomcat-${VERSION}.tar.gz -C /opt/tomcat/
sudo ln -s /opt/tomcat/apache-tomcat-${VERSION} /opt/tomcat/latest
sudo chown -R tomcat: /opt/tomcat
sudo sh -c 'chmod +x /opt/tomcat/latest/bin/*.sh'
sudo vi /etc/systemd/system/tomcat.service

Add the startup file

[Unit]
Description=Tomcat 9 servlet container
After=network.target

[Service]
Type=forking

User=tomcat
Group=tomcat

Environment="JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64"
Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom -Djava.awt.headless=true"

Environment="CATALINA_BASE=/opt/tomcat/latest"
Environment="CATALINA_HOME=/opt/tomcat/latest"
Environment="CATALINA_PID=/opt/tomcat/latest/temp/tomcat.pid"
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"

ExecStart=/opt/tomcat/latest/bin/startup.sh
ExecStop=/opt/tomcat/latest/bin/shutdown.sh

[Install]
WantedBy=multi-user.target

And update systemctl

sudo systemctl daemon-reload
sudo systemctl enable --now tomcat
sudo systemctl status tomcat

Web Management

# Add above </tomcat-users>
sudo vi /opt/tomcat/latest/conf/tomcat-users.xml
   <role rolename="admin-gui"/>
   <role rolename="manager-gui"/>
   <user username="NotThis" password="NotThisEither" roles="admin-gui,manager-gui"/>

And to enable

# Manager App
sudo vi /opt/tomcat/latest/webapps/manager/META-INF/context.xml
# Host Manager App
sudo vi /opt/tomcat/latest/webapps/host-manager/META-INF/context.xml

Then add your host

<Context antiResourceLocking="false" privileged="true" >
  <CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor"
                   sameSiteCookies="strict" />
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|192.168.50.1" />
  <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap"/>

Deploy in VS Code

I installed the tomcat and maven extension. Loaded up a dummy project from https://github.com/branflake2267/debugging-java-webapp and followed the instructions.

  • clone the project
  • goto Maven->plugins->war and right click war:exploded
  • install tomcat for java extension for VS CODE. I have tons of trouble with this. Do not put anything in the settings and make sure the root tomcat has 777 permissions
  • add a tomcat server
  • goto the target project directory and right click run on tomcat server

Deploy in IntelliJ

First of all I needed to specify the location of the JDK when building the project.

env |grep JAVA_HOME

Going to Maven->Package->Build resulted in "Failed to execute goal org.apache.maven.plugins:maven-surefile-plugin:2.22 I had to add the following

Open your project, build and go to the Maven tab on the right. Select->lifecycle->right click package->Select Modify Configuration->

Getting Started

Introduction

We can add security to a new project with

        <dependencies>
...
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-security</artifactId>
                </dependency>

                <dependency>
                        <groupId>org.springframework.security</groupId>
                        <artifactId>spring-security-test</artifactId>
                        <scope>test</scope>
                </dependency>

        </dependencies>

Spring uses Filters on request like interceptors in Angular. The filter

Example 1

In the Spring Boot Docs we see [here]

@Configuration(proxyBeanMethods=false)
 @ConditionalOnClass(value=org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.class)
 @ConditionalOnMissingBean(value=org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.class)
 @ConditionalOnWebApplication(type=SERVLET)
public class SpringBootWebSecurityConfiguration

extends Object

For basic authentication we use the WebSecurityConfigurationAdapter. This supports Web and Basic Authentication (Crikey). Here we can extend the class and override the configure

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequests().authenticated()
            .and().httpBasic();
        }   
}

Example 2

Here is a more complicated example. We can see some basic operations. E.g. Endpoints when logging in and logging out.

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
                http
                  .csrf()
                  .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                  .and()
                  .authorizeRequests()
                        
                  .mvcMatchers(HttpMethod.GET,"/","/index.html","/portfolio").permitAll()
                  .anyRequest().authenticated()
                  .and()
                  .formLogin()
                  .loginProcessingUrl("/api/login")
                  .and()
                  .logout()
                  .logoutUrl("/api/logout")
                  .logoutSuccessUrl("/");
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                auth.inMemoryAuthentication().withUser("victoria").password(" 
                   {noop}password").roles("ADMIN")
                .and().withUser("dave").password("{noop}password").roles("USER");
        }

        @Override
        public void configure(WebSecurity web) throws Exception {
                web.ignoring().antMatchers("/css/**", "/webjars/**","/js/**");
        }

}

Success Handling

We can define our own Success Handler by

@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
 
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        //do some logic here if you want something to be done whenever
        //the user successfully logs in.
 
        HttpSession session = httpServletRequest.getSession();
        User authUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        session.setAttribute("username", authUser.getUsername());
        session.setAttribute("authorities", authentication.getAuthorities());
 
        //set our response to OK status
        httpServletResponse.setStatus(HttpServletResponse.SC_OK);
 
        //since we have created our custom success handler, its up to us to where
        //we will redirect the user after successfully login
        httpServletResponse.sendRedirect("home");
    }
}

From here we can add the class to the formLogin method.

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
                http
                .csrf()
                        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and()
                .authorizeRequests()
                        .mvcMatchers(HttpMethod.GET,"/","/index.html","/portfolio").permitAll()
                        .anyRequest().authenticated()
                        .and()
                .formLogin()
                        .loginPage("/api/login").successHandler(new CustomAuthenticationSuccessHandler())
                .and()
                .logout()
                        .logoutUrl("/api/logout")
                        .logoutSuccessUrl("/");
        }

Common Security Threats

Introduction

Spring Security provides default headers which can be customised

Caching

By default the headers turn off caching to avoid data being left behind in the browser. You can of course switch this on and it is recommended you do this on a page by page approach. To do this

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
                http
                  .headers().cacheControl().disable()
                  .mvcMatchers("/login").permitAll()
...

And in the Controller

@GetMapping("/users/{name}")
public ResponseEntity<UserDto> getUser(@PathVariable String name) { 
    return ResponseEntity.ok()
      .cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
      .body(new UserDto(name));
}

Default Headers

Spring Security has a variety of default headers to protect the user. Try and understand them before ever changing the defaults. These include

 X-XSS-Protection: 1; mode=block
 X-Content-Type-Options: nosniff
 X-Frame-Options: DENY // ClickJacking

CSRF

This is implemented by default and generates a token like Microsoft Forgery tokens

Content Security Policy

This is turned off by default but when enable it can confine scripts to given domains for example. Well worth a look.

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
                http
                  .headers().contentSecurityPolicy("script-src: http://www.bibble....)

Http Firewall

Spring Security comes with a two types of firewall but of course you can override it to your needs

/**
 * Allow url encoded slash http firewall.
 *
 * @return the http firewall
 */
@Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
    DefaultHttpFirewall firewall = new DefaultHttpFirewall();
    firewall.setAllowUrlEncodedSlash(true);
    return firewall;
}

HTTPS

Create a Keystore and Certificate

To create the JKS keystore

keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -keystore keystore.jks -validity 3650 -storepass password

To create the Certificate

keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650 -storepass password

Where

  • genkeypair: generates a key pair
  • alias: the alias name for the item we are generating
  • keyalg: the cryptographic algorithm to generate the key pair
  • keysize: the size of the key. We have used 2048 bits, but 4096 would be a better choice for production
  • storetype: the type of keystore
  • keystore: the name of the keystore
  • validity: validity number of days
  • storepass: a password for the keystore

Verify the Keystore Content and Convert to PKCS12

keytool -list -v -keystore keystore.jks
keytool -list -v -storetype pkcs12 -keystore keystore.p12
keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -deststoretype pkcs12

Enable in Application (Application.yml)

server:
  ssl:
    key-store: classpath:keystore.p12
    key-store-password: password
    key-store-type: pkcs12
    key-alias: tomcat
    key-password: password
  port: 8443

Configure Redirects

In the Spring Boot application we can now redirect with

@SpringBootApplication
public class WebApplication {

...
	public static void main(String[] args) {
		SpringApplication.run(WebApplication.class, args);
	}
	
	@Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(redirectConnector());
        return tomcat;
    }

    private Connector redirectConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(8080);
        connector.setRedirectPort(8443);
        return connector;
    }
}

Spring Security As a Backend

You can use spring as backend to standardise you authentication. So we can use spring in place of authentication in React or Angular.

Managing Secrets

To management secrets like for the key-store we can use Jasypt. We can put the encoded value in the Application.yml and put the password in and environment variable. Was not impressed with what I learned but did recommend auditing properly i.e. logging recording access with who when and why as secret was accessed.

Exception Handling

You can manage various codes with in Spring and provide your own page. Below is an example of AccessDeniedHandler. Simply create a class and decide what you would like to have happen. E.g. Audit the problem

public class CustomAccessDeniedHandler implements AccessDeniedHandler {
 
 private String errorPage;
 
 public CustomAccessDeniedHandler() {
 }
 
 public CustomAccessDeniedHandler(String errorPage) {
  this.errorPage = errorPage;
 }
 
 public String getErrorPage() {
  return errorPage;
 }
 
 public void setErrorPage(String errorPage) {
  this.errorPage = errorPage;
 }
 
 @Override
 public void handle(HttpServletRequest request, HttpServletResponse response,
  AccessDeniedException accessDeniedException)
                throws IOException, ServletException {
 
  //You can redirect to errorpage
  response.sendRedirect(errorPage);
 }
}

Make sure you add this to the WebSecurityConfigurerAdapter

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
                http
                  .exceptionHandling()
                  .accessDeniedPage("/access denise")
                  .accessDeniedHandler(new AccessDeniedHandler())
 ...