Insecure session management - CSRF Fixation
Need
Secure session management and protection against CSRF Fixation
Context
- Usage of TypeScript for statically typed JavaScript development
- Usage of Express for building web applications and APIs
Description
Non compliant code
import express from 'express';
const app = express();
app.get('/transaction', (req, res) => {
const authorizationHeader = req.headers.authorization;
// Perform transaction logic
res.send('Transaction completed successfully');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
The vulnerability in this code is an insecure session management issue known as CSRF (Cross-Site Request Forgery) Fixation.
In the code, the /transaction
route is defined as a GET request handler. Inside the handler function, the code retrieves the authorization
header from the request using req.headers.authorization
.
The problem is that the authorization
header is being used as a public key for authentication, and it is always the same for payment links. This means that an attacker can create a button or link that includes the content of a request and trick a user into clicking it. When the user clicks the button or link, the app will send a push notification to complete the transaction using the fixed authorization
header.
This vulnerability allows an attacker to spoof an authenticated user in the application by modifying the link and executing critical transactions such as transfers or payments on behalf of the victim.
To fix this vulnerability, it is recommended to implement CSRF protection by using tokens in the forms for verification of requests made by legitimate users. This will ensure that only requests originating from the application itself are considered valid, preventing CSRF attacks.
Steps
- Implement CSRF protection in the application
- Generate and include a CSRF token in the forms used for transactions
- Validate the CSRF token on the server-side before processing the transaction
- Ensure that the CSRF token is unique for each session and request
- Use a secure method to generate and store the CSRF token, such as using a cryptographic library or a secure random number generator
- Include the CSRF token in the request headers or body when making a transaction request
- Verify the CSRF token on the server-side by comparing it with the token stored in the session or database
- Reject the transaction request if the CSRF token is invalid or missing
- Regularly review and update the CSRF protection mechanism to address any new vulnerabilities or attack techniques
Compliant code
import express from 'express';
import csrf from 'csurf';
const app = express();
const csrfProtection = csrf({ cookie: true });
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(csrfProtection);
app.get('/transaction', (req, res) => {
const authorizationHeader = req.headers.authorization;
// Perform transaction logic
res.send('Transaction completed successfully');
});
app.post('/transaction', (req, res) => {
const authorizationHeader = req.headers.authorization;
const csrfToken = req.csrfToken();
// Validate CSRF token
// Perform transaction logic
res.send('Transaction completed successfully');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
The fixed code addresses the vulnerability by implementing CSRF protection using tokens. Here's an explanation of the changes made:
-
The
csrf
middleware is imported from thecsurf
library. This middleware generates and validates CSRF tokens. -
The
csrfProtection
middleware is created usingcsrf({ cookie: true })
. This configures the middleware to store the CSRF token in a cookie. -
The
express.urlencoded
andexpress.json
middlewares are used to parse incoming request bodies. -
The
csrfProtection
middleware is added to the middleware stack usingapp.use(csrfProtection)
. This ensures that all routes below this middleware are protected against CSRF attacks. -
The
GET /transaction
route is modified to include theauthorizationHeader
in the request. This is just for demonstration purposes and should be replaced with the actual logic for handling transactions. -
The
POST /transaction
route is modified to include theauthorizationHeader
andcsrfToken
in the request. ThecsrfToken
is obtained fromreq.csrfToken()
, which generates a new CSRF token for each request. -
The
POST /transaction
route also includes a step to validate the CSRF token. This step ensures that the request is coming from a legitimate user and not from an attacker trying to perform a CSRF attack. -
After the necessary validations, the transaction logic is performed, and a response is sent back to the client.
-
The server is set to listen on port 3000 using
app.listen(3000)
.