SECURE YOUR WEB DEVELOPMENT AGAINST REPLAY ATTACKS
NARAYANAN PALANI
??Platform Engineering Lead ???????? Certified AWS, GCP Architect ??Retail, Commercial and Investment Banking ??Best Seller ??FOLLOW
Replay attacks are popular among cyber threats and Rank #8 according to A8:2017-Insecure Deserialization hence let us deep dive on risk mitigations in this week's article
What is Replay Attack?
A replay attack at the TLS level (and thus HTTPS) as you imagine would mean that some attacker could simply replay a captured TLS session or inject a previously captured packet into an existing TLS session.
Replay attacks are a form of network attack where an attacker intercepts and retransmits data that was previously exchanged between two parties. Fundamentally, a replay attack occurs when an attacker is able to capture data-in-transit in cleartext form. Replay attacks may capture various forms of authentication data, such as passwords, session tokens, or cryptographic authentication hashes.
The problem lies in technologies that lack signature based authentication.? To understand this problem, it's important to understand the difference between using secrets vs. signatures for authentication. Essentially, secrets rely on transmitting predictable information such as a password or authentication token which, if stolen, can be used again since they don't change.? However, signature based authentication always transmits different data to authenticate because it relies on public key cryptography.
How is a Replay Attack carried-out?
So,
How to prevent the Replay Attack using nonce?
If www.iBuy.com requires Alice to send Hashed [Credentials + non-repetitive Nonce sent by www.iBuy.com to Alice], then even though Bob eavesdropped, retrieved and REPLAYED the hashed value, www.iBuy.com denies the request, because the nonce sent by www.iBuy.com to Alice is now different, subsequently the hashed value is also different now and certainly the hashed value is not the one expected by www.iBuy.com.
Risk Mitigation through Nonce
Nonce as a timestamp provides a reliable way to prevent replay attacks. Using a nonce as a timestamp ensures that a message is used only once, and if an attacker tries to replay the same message, it will be detected as invalid.
Nonces must be stored securely to prevent attackers from accessing or modifying them. Ideally, nonces should be stored in a tamper-evident way, such as in a secure hardware module.
Let us see how to implement it:
The Web Fundamentals Content Security Policy article’s If you absolutely must use it section has a good example of how to use the nonce attribute, which amounts to the following steps:
So the mechanism of using a nonce is an alternative to instead of having your backend generate a hash of the contents of the inline script or style you want to allow, and then specifying that hash in the appropriate source list in your CSP header.
Use of Rebouncing in Typescript
Let's understand this with an example. Suppose we have an input element that gets some data when we type something. For example, let's say we type any pin-code, and it returns some data.
But there is a catch here. Let's say our pin-code is 800001. If we type the first character, that is 8, we will send request to the backend server. Then we type 0, and we will send another request to the server, and so on. ?
This calls the API so many times, and in turn overuses the requests. So, to prevent this, we use something called a debounce function.
So to achieve this, we have a feature in JavaScript called Debouncing.
Debouncing in JavaScript – a Practical Example
In the below example, we are simply calling an API using the axios.get method when we type any numeric character in the input box.
The input character is getting passed to the function as an argument and we are passing the value as path parameters. We are also logging the response in the console.
import axios from "axios";
import React from "react";
import "./styles.css";
export default function App() {
const setInput = (value) => {
axios
.get(`https://api.postalpincode.in/pincode/${value}`)
.then((response) => {
console.log(response.data[0]?.PostOffice[0]);
});
};
return (
<div className="app">
<input
placeholder="Search Input.."
onChange={(e) => setInput(e.target.value)}
/>
</div>
);
}
But the catch here is, every time we write a character, our API will get triggered. So going back to our example above, let's say we want to type 800001. Again, as soon as we type 8, the API will be triggered and it will search the character 8. Then we will type 0 (zero), and the API will search for 80, and so on.
Now, let's change the whole flow in order to add debouncing. In the case of Debouncing, the API will trigger only once after 2 seconds, after we type our whole pin-code.
First of all, create a state using the useState hook in React.
const [pinCode, setPinCode] = React.useState("");
Now, we need to set the data in the pinCode state when we type something, using the onChange event handler.
领英推荐
<input
placeholder="Search Input.."
onChange={(event) => setPinCode(event.target.value)}
/>
Now, let's have a useEffect Hook that will run every time our pin-code changes, or when we type something in the search input.
React.useEffect(() => {
}, [pinCode])
In this useEffect Hook, we will have a function called getData. This function getData will have a callback function called setTimeOut. And we will set the timer for 2 seconds.
React.useEffect(() => {
const getData = setTimeout(() => {
}, 2000)
}, [pinCode])
And now in this getData function, let's call our API.
React.useEffect(() => {
const getData = setTimeout(() => {
axios
.get(`https://api.postalpincode.in/pincode/${pinCode}`)
.then((response) => {
console.log(response.data[0]);
});
}, 2000)
}, [pinCode])
We will also need to destroy the instance of the useEffect hook using return, followed by clearTimeout, every time it finishes.
React.useEffect(() => {
const getData = setTimeout(() => {
axios
.get(`https://api.postalpincode.in/pincode/${pinCode}`)
.then((response) => {
console.log(response.data[0]);
});
}, 2000)
return () => clearTimeout(getData)
}, [pinCode])
And we are done. Let's type something in the input, and after 2 seconds we will get our results.
On a summary, if we type any search query in the input, it will display after 2 seconds just when we stop changing the input. And we used debouncing to do this.
There are multiple applications of debouncing. We can use it to keep from hitting our API over and over. And we can use it to make sure the the form data gets submitted only once, even if we click the submit button multiple times.
Stopping a Replay Attack
Preventing such replay attack is all about having the right method of encryption. Encrypted messages carry "keys" within them, and when they're decoded at the end of the transmission, they open the message. In a replay attack, it doesn't matter if the attacker who intercepted the original message can read or decipher the key. All he or she has to do is capture and resend the entire thing — message and key — together.
To counter this possibility, both sender and receiver should establish a completely random session key, which is a type of code that is only valid for one transaction and can't be used again.
Summary
Signature-based authentication, data encryption, employing unique token identifiers and nonce values within the applications will control replay attacks of some types but not all the different (newly emerging) types hence having sold security detection mechanism such as CheckMarx Scans, BurpSuite Scans to the application interfaces are essential to bring additional measures to reduce the overall impact of different Replay Attack methods.
References:
Like this article? Subscribe to Engineering Leadership and Digital Payments Hub to enjoy reading useful articles.
Disclaimer: Contents, posts and media used in this account of the author do not represent any organisation of any sort. Under no circumstances will the author be held responsible or liable in any way for any claims, loss, expenses or liabilities whatsoever.