Skip to main content

Insecure session management - CSRF Fixation

Description

It is possible generate a CSRF Fixation in the transaction functionality. Authorization header is the public key, and It is always the same for payment links. An attacker can create a button with the content of a request and trick a user running a transaction to receive the Nequi push notification and complete the request.

Impact

Spoof an authenticated user in the application by means of a modified link to execute critical transactions such as transfers or payments.

Recommendation

Make use of tokens in the forms for the verification of requests made by legitimate users.

Threat

Attacker from the Internet without authentication.

Expected Remediation Time

⌚ 60 minutes.

Score

Default score using CVSS 3.1. It may change depending on the context of the vulnerability.

Base

  • Attack vector: N
  • Attack complexity: L
  • Privileges required: N
  • User interaction: R
  • Scope: U
  • Confidentiality: N
  • Integrity: L
  • Availability: N

Temporal

  • Exploit code madurity: P
  • Remediation level: X
  • Report confidence: X

Result

  • Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N/E:P/RL:X/RC:X
  • Score:
    • Base: 4.3
    • Temporal: 4.1
  • Severity:
    • Base: Medium
    • Temporal: Medium

Code Examples

Compliant code

Including functionality to authenticate a user by sending them a token before accepting payment

app.post('/user/payment', (req, res) => {
const { username, password, paymentInfo } = req.body;
const user = users.find(u => { return u.username === username && u.password === password });
if (user) {
const token = jwt.sign({ username: user.username, role: user.role }, accessTokenSecret);
sendAuthToken(user, token)
//Code to handle redirection for token to be processed
} else {
res.send('Unable to generate token. Login again to re try');
}
});

Non compliant code

The same header is included in the payments after processing which could be exploited by an attacker

app.post('/user/payment', (req, res) => {
const { username, password, paymentInfo } = req.body;
const user = users.find(u => { return u.username === username && u.password === password });
if (user) {
processPayment(user, paymentInfo);
res.json({
accessKey
});
} else {
res.send('Unable to generate token. Login again to re try');
}
});

Requirements