23 min read

CORS uses MVC Config and can also use Nginx Config

Using external APIs requires managing access tokens on server, without putting these tokens into GitHub.

We can also use DotEnv to manage secret keys and storing keys on localhost and the AWS server

Overview

Many of your user’s important info or the data collections such as their name, email, and dob may be found. Leaking this info can make people to stray away from using your website.

What is CORS

  • CORS stands for Cross-Origin Resource Sharing and it works to defend the the server side (APIs and the Backend)

  • When you make a request on the client side (the frontend site), your sending a request to another site which has an API, CORS works to protect sensitive data and make sure that only secure websites and the site with the server to have access to the data.

/src/main/java/com/nighthawk/spring_portfolio/

to find under SecurityConfig.java

.cors(Customizer.withDefaults())
.headers(headers -> headers
    .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Credentials", "true"))
    .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-ExposedHeaders", "*", "Authorization"))
    .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Headers", "Content-Type", "Authorization", "x-csrf-token"))
    .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-MaxAge", "600"))
    .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Methods", "POST", "GET", "OPTIONS", "HEAD"))
    .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Origin", "http://link1", "http://link2", "http://link3", "http://link4"))

Explanation 1

.addHeaderWriter(new StaticHeadersWriter(“Access-Control-Allow-Credentials”, “true”))

  • This header indicates whether the code should include credentials (like cookies, HTTP authentication, and client-side SSL certificates) in the request
  • This is typically used when the server needs to send and receive cookies on the requested domain.

Explanation 2

.addHeaderWriter(new StaticHeadersWriter(“Access-Control-Allow-ExposedHeaders”, “*”, “Authorization”)):

  • This header, enables you to specify cors headers (“*”) and grants the browser to expose headers like “Authorization” to the client.

Explanation 3

.addHeaderWriter(new StaticHeadersWriter(“Access-Control-Allow-Headers”, “Content-Type”, “Authorization”, “x-csrf-token”)):

  • This line is listing the headers that the client is allowed to use in the actual request

Explanation 4

.addHeaderWriter(new StaticHeadersWriter(“Access-Control-Allow-MaxAge”, “600”)):

  • This line specifies that the results of a https request can be cached for in this case, 600 seconds
  • What this does in other words is before the actual request is received, a small request is typically sent and this request is saved for 600 seconds allowing for it so when similar calls are made, the result of the initial call is reused, this improves the performance and latency.

Explanation 5

.addHeaderWriter(new StaticHeadersWriter(“Access-Control-Allow-Methods”, “POST”, “GET”, “OPTIONS”, “HEAD”)):

  • This line just lists the different HTTP methods that are allowed when making a request

Explanation 6

.addHeaderWriter(new StaticHeadersWriter(“Access-Control-Allow-Origin”, “http://link1”, “http://link2”, “http://link3”, “http://link4”)):

  • This line simply specifies what links are allowed to make requests to the server

image

Nginx

Nginx is a web server and reverse proxy server that has a wide variety of functions that enable for better performance, security, and connections between a client and the server. Some its most important features include:

MVC

MVC serves in order to make the code separated into different roles and parts allowing for it to be easily used and easily reusable. It also provides great extendability and makes it really easy to test the code since each part is essentially independent from each other.

Basic Knowledge

HTTP: a communication protocol to deliver data over the internet

  • The client makes a request (ex: POST, GET), server consults database and returns an output

Database: collection of information that is organized, where the server can quickly query data and add/delete data

  • SQL is the language used for managing these databases (which are made up of tables each with data)
  • Databases store data in the website, such as passwords or FLAGS
  • SQL syntax:
    • SELECT * FROM table_name
  • Selects all data from specific table (this can be exploited)

Proxy: a server that redirects your browsing activity before accessing the web

  • The web request first gets sent to the proxy and then to the web instead of straight to the web, masking IP address
  • Also provides a way to edit the request before it leaves (BURP SUITE)

Example

Let’s say you want to buy a gift on Amazon and go to this link https://amazon.com/products?category=Gifts

This causes the SQL query to retrieve details from the database

SELECT * FROM products WHERE category = ‘Gifts’ AND released = 1

Where

  • “*” = everything
  • Products = table name
  • The restricts are that the category is ‘Gifts’ and released is equal to 1 (in this example this means the gift is released)

Now what if we want to get stuff from the database that isn’t released? How would we bypass the “released=1”?

This is where SQL injection comes into play! Before we tackle how to do it, let’s go over some syntax

Syntax

  • Two dashes (- -) is an SQL comment
  •   ” is concatenate
  • SELECT * FROM users WHERE username = ‘william’ AND password = ‘Password1!’
    • Stuff between single quotes are strings
    • Everything else is an SQL query

IMPORTANT

  • A single quote (‘) helps you break out of a string and write more SQL query!
  • “AND” statement always runs before “OR” statement

Now we are getting into the good stuff

How the attack works

Remember that a login page uses a sql query to search the db if the user and password entered is correct. Remember this syntax: SELECT * FROM users WHERE username = ‘william’ AND password = ‘Password1!’ Whatever you enter into the login page will be set as “username” and “password”. My syntax examples has username as ‘william’ and password as ‘Password1!’. Notice how they are between single quotes. Anything between quotes is a string and everything outside of it is a SQL query.

But what if you enter a single quote ‘ into the login page? Then you will break out of the string and be able to run SQL queries! This is the basis of the two payloads below:

  • OR Payload: Having an OR statement that is always true

Let’s say we enter admin’ OR ‘1’=’1’ for the username field. Then our sql query will look like this: SELECT * FROM users WHERE username = ‘admin’’ OR ‘1’=’1’ AND password = ‘Password1!’

Now remember how a single quote ‘ will break out of a string and run sql query commands. We are basically running OR ‘1’=’1’ which will obviously always evaulate as true. And since a OR statement will be true if one side of the argument is true, we basically bypass both the username and the password. Thus both fields could be incorrect but we would still be able to login!

  • Comment Payload: Commenting parts of the query in order to bypass stuff

Remember how two dashes (–) is an SQL comment? Well we can abuse this to bypass some info.

For example, we can bypass the password by inputting admin’– in the username box. The sql query would be: SELECT * FROM users WHERE username = ‘admin’’– AND password = ‘Password1!’

This will lead to the AND password section not being executed. Thus we don’t need to input the correct password in order to login. In fact, we don’t even need to input a username as sql validates it as an empty string and the whole expression would take the first user. So uh you won’t need to have either info.

How to protect

Learning how the exploits are cool and all but the whole point of this blog is to learn how to protect your website. Here is one way you can protect against sql injections

Use of Prepared Statements (with Parameterized Queries)

  • Instead of directly embedding user-supplied data in SQL queries, prepared statements use placeholders for the input data. The SQL statement and the input data are sent separately to the database, preventing malicious input from altering the structure of the query.

Here’s an example of not protected code:

import java.sql.*;

public class DatabaseExample {

    // Assuming you have established a database connection
    
    // Without any protection measures
    public static void createUser(String username, String password) {
        String sql = "INSERT INTO users (username, password) VALUES ('" + username + "', '" + password + "')";
        
        try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db_name", "username", "password");
             Statement statement = connection.createStatement()) {
            
            statement.executeUpdate(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        // Example usage
        String username = "john";
        String password = "secretpassword'; DROP TABLE users; --";
        
        createUser(username, password);
    }
}

With protection

import java.sql.*;

public class DatabaseExample {

    // Assuming you have established a database connection
    
    // Option 1: Use of Prepared Statements (with Parameterized Queries)
    public static void createUser(String username, String password) {
        String sql = "INSERT INTO users (username, password) VALUES (?, ?)";
        
        try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db_name", "username", "password");
             PreparedStatement statement = connection.prepareStatement(sql)) {
            
            statement.setString(1, username);
            statement.setString(2, password);
            
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        // Example usage
        String username = "john";
        String password = "secretpassword";
        
        createUser(username, password);
    }
}