How Banks Can Fight Scammers

Adonis Gaitatzis
4 min readMar 27, 2022

--

Bank, support, and gift card scams are on the rise in the United States, causing a reported loss of 148 million dollars in 2021.

While consumer education helps reduce harm and police investigations help make the cost of running these scams more difficult, some simple systems can be implemented by companies that can make these scams much harder to implement.

One such example is a simple change that any banking website could implement. I call it Client-side Content Revision Monitoring (CCRM) because the acronym doesn’t collide with any major existing technologies or government organizations.

How it works

A client-side javascript periodically checks for changes to important HTML in the browser. If a change is detected, a banner is displayed in the web page to alert the customer of the change.

Why this is useful

A common tactic of scammers is to alter the client-side HTML of a user’s bank page.

They do this by:

  1. Having the victim share their screen with the scammer
  2. Having the victim log into their bank account
  3. Covertly altering the HTML of the bank site from the user’s browser over screen sharing
  4. Using the altered bank page to tell the user that they have been overpaid and must refund the money.

The process looks like this:

Demonstration of how client-side content revisions work in scamming.
Demonstration of client-side revision scam technique

Victims are typically not tech-literate enough to understand that only their client-side HTML has been altered and are unaware that they can re-load accurate information by refreshing the page. They see the bank page and trust that anything provided by the bank must be accurate.

So there are two major vulnerabilities the scammer is taking advantage of:

  1. The victim doesn’t know that their account data has been altered
  2. They don’t know that they can refresh the page to get up-to-date account data

A system where the bank can tell the user that their client-side HTML has been altered can remedy both of these issues.

Here’s how that could look:

Demonstration of client-content revisioning monitoring
Demonstration of Client-side Content Revision Monitoring

How to Implement

Implementation is simple but nuanced.

Requirements

  • The banner must be inserted in the <body> tag so that the scammer can’t remove the containing element
  • The banner content must be stored in program memory rather than a <template> or retrieved from a <div> to reduce the ability of the scammer to remove or alter the banner content.
  • The content monitor must be ongoing so that even if the scammer removes the banner, it will re-appear again later
  • The banner must be sticky so that the scammer can’t scroll the banner out of view of the screen
  • Ideally, the banner will not show until the scammer is in the process of showing the altered data to the victim, rather than while the scammer is in the process of editing. For this reason, I recommend a 10 second or so delay on the banner.
  • The monitoring must begin after the page has rendered, so that the HTML being monitored has been rendered by the browser.

Example Code

Take the following HTML snippet. We want to know if data has been altered inside a specific element, <div id="sensitive-data”>:

<html>
<body>
<div id="sensitive-data">
Your account has $12,345.67
</div>
</body>
</html>

The script will generate a unique hash of the data:

initialDataHash = await createHashFromElement('sensitive-data')

Then, a monitoring function will execute every few seconds and compare against the initialDataHash :

setInterval(() => {
currentDataHash = await createHashFromElement('sensitive-data')
if (currentDataHash != initialDataHash) {
displayContentChangedBanner()
}
}, contentMonitoringIntervalTimeoutMilliseconds)

We can use crypto.subtle.digest() to create the unique hash. In this case I’m using SHA-1 because we only generating a hash, not concerned about encryption:

const createHashFromElement = async (elementId) {
const encoder = new TextEncoder()
const decoder = new TextDecoder()
const html = document.getElementById(elementId).outerHTML
const htmlBytes = encoder.encode(html)
const digest = await crypto.subtle.digest('SHA-1', htmlBytes)
const hash = decoder.decode(digest)
return hash
}

Finally, we can display the warning banner to the user in the <body> tag if the banner doesn’t already exist. The CSS position should be sticky so that the scammer can’t scroll the banner out of view.

const displayContentChangedBanner = () => {
const banner = `
<div class="alert" id="content-alert"
style="position: sticky"
>
Danger! The content of this page has been altered.
Please reload this page for the correct information.
</div>
`
const existingAlert = document.getElementById('content-alert')
if (existingAlert == null) {
document.body.insertAdjacentHTML('afterBegin', banner)
}
}

Live Demo and Source Code

A live, interactive demo for this project can be found at https://backupbrain.github.io/anti-scam-bank-page-monitor/demo.html

Source code for this project is hosted at https://github.com/backupbrain/anti-scam-bank-page-monitor

--

--

Adonis Gaitatzis

Is a technology and branding nerd who can synthesize any business need into a technology solution. Fun projects have included brain imaging tech & mesh routers.