Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Clickjacking Cheatsheet . Closes #1577 #1609

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

caffeine-rohit
Copy link
Contributor

Closes #1577 . I updated the Clickjacking cheat sheet by adding Double Clickjacking into it. I added all the necessary information about this issue and explained some good effective ways to prevent Double clickjacking .

@caffeine-rohit
Copy link
Contributor Author

@jmanico @kwwall @szh @mackowski
Please Review the PR . It closes #1577

@jmanico
Copy link
Member

jmanico commented Feb 5, 2025

This is very new information to me, I will approve when @kwwall says go.

Copy link
Collaborator

@mackowski mackowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this!

@mackowski
Copy link
Collaborator

@caffeine-rohit do you have PoC of this exploit somewhere? I am wondering if COOP https://web.dev/articles/security-headers#coop and CORP https://web.dev/articles/security-headers#corp can help to mitigate that.

Copy link
Collaborator

@kwwall kwwall Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, 2 things here that concern me:

  1. Why this image. I don't see anywhere in "cheatsheets/Clickjacking_Defense_Cheat_Sheet.md", that it's being referenced. (I've searched for the file name and 'img'.) It it is not referenced in this Clickjacking Cheat Sheet, why is it ever here?
  2. This image is straight out of Paulos Yibelo's blog (although there, it is a PNG file, rather than a WebP format; so apparently the format was converted.) If you did intend to use it, at a minimum, we at least need to acknowledge it as Yibelo's creation. And ideally, we ought to permission to use unless it unless it is clearly covered by some FOSS license that allows us to freely use it. While I don't believe you had malicious intentions, we certainly don't want to risk OWASP getting sued.


## Introduction

This cheat sheet is intended to provide guidance for developers on how to defend against [Clickjacking](https://owasp.org/www-community/attacks/Clickjacking), also known as UI redress attacks.
This cheat sheet is intended to provide guidance for developers on how to defend against [Clickjacking](https://owasp.org/www-community/attacks/Clickjacking) (also known as UI redress attacks) and [Double Clickjacking](https://www.paulosyibelo.com/2024/12/doubleclickjacking-what.html?m=1) (also called forced multi-click exploitation)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Much better.

Comment on lines +357 to +367
```javascript
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (!entry.isIntersecting) {
alert("Warning: A hidden iframe may be attempting a Clickjacking attack!");
}
});
}, { threshold: 0.5 });

document.querySelectorAll("iframe").forEach(iframe => observer.observe(iframe));
```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmanico - I am not enough of a JavaScript expert to be able to discern if this is an effective defense against Double Clickjacking or not. Could you please take a look at this (lines 357-367) and give us your thoughts regarding it's effectiveness? It is very different than Yibelo's client-side JS defense. And I am a little concerned that this may have false positives (the assumption seemingly being it is rare for multiple entities to overlap) and also it may be a time-consuming defense if there are a lot of entities on a page, given that you'd need to check this on every page.

Comment on lines +377 to +381
```javascript
if (document.referrer && !document.referrer.includes("your-website.com")) {
alert("Warning: Clicks from an untrusted source detected!");
}
```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things:

  1. I'm not sure any website really should be trusted. Or at least there's a lot of cases not to do that. There are insider attackers. Also, this doesn't fit well into an "assume breach" mentality that many security conscious companies are now taking. (Also, we we're only concerned about cross-site requests SameSite cookies, CORS headers, etc. probably would be sufficient, shouldn't they?)
  2. I'm not confident this would work. I mean false positives would surely seem to be an issue, wouldn't it?

At a bare minimum, I will wait until @jmanico looks at this, but if it is valid, it probably needs a better explanation.

Comment on lines +391 to +403
```javascript
let lastClickTime = 0;
document.getElementById("submitButton").addEventListener("click", function (event) {
const now = Date.now();
if (now - lastClickTime < 500) { // 500ms delay
event.preventDefault();
alert("Double-click detected! Please click only once.");
} else {
lastClickTime = now;
// Proceed with the action
}
});
```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems feasible. Have you tried this on Yibelo's PoC on his blog post?
What do you think @jmanico ?

Comment on lines +413 to +420
```javascript
function confirmAction() {
let confirmation = confirm("Are you sure you want to proceed?");
if (confirmation) {
// Perform action
}
}
```
Copy link
Collaborator

@kwwall kwwall Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Um, TBH, I'm beginning to wonder if you are missing the point about how Clickjacking iis exploited in general. The targeted system is just there to entice the user to click or to garner the user's trust. The way this "UI redress" works is the attack places something dangerous (e.g., a site that might download malware) in a transparent overlay over something that the user generally thinks would be safe to click on (the underlying iframe of the targeted system). That overlaid system may or may not overlay "sensitive data". And you surely cannot do this on every page. You couldn't even use it on something like a financial or health insurance site, because there pretty much everything is sensitive on almost every page. Thus using something the above on such a site would be very intrusive. If it did work (and do you really think the average user is going to do a 'view source' or open the browser's web development tools and try to figure it out?), the defense needs to be unobtrusive and not require any special intelligence from the end user.

Comment on lines +447 to +459
**Concept:** Instead of a simple click, users must perform a deliberate gesture, like dragging a slider, before confirming actions.

```html
<label for="secureAction">Slide to confirm:</label>
<input type="range" id="secureAction" min="0" max="100" oninput="checkGesture(this.value)">
<script>
function checkGesture(value) {
if (value == 100) {
alert("Confirmed! Action executed.");
}
}
</script>
```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seriously, a slider on every page? Really? Because prior to X-FRAME-OPTIONS and CSP frame-ancestors, we had to put the anti-frame busting JavaScript on every bloody page, so I don't see why this would any different. You can't do something that is going to require an explicit action every time a page loads.

✅ Users must actively confirm before execution.

✅ Prevents forced clicks leading to unintended actions.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, what is so wrong about dropping Yibelo's suggested client-side defense here?

    (function(){
    if (window.matchMedia && window.matchMedia("(hover: hover)").matches) {
        var buttons = document.querySelectorAll('form button, form input[type="submit"]');
        buttons.forEach(button => button.disabled = true);
        
        function enableButtons() {
            buttons.forEach(button => button.disabled = false);
        }
        
        document.addEventListener("mousemove", enableButtons);
        document.addEventListener("keydown", e => {
            if(e.key === "Tab") enableButtons();
        });
    }
})();

Presumably that at least is effective against his PoC. He'd lose a lot of credibility if it wasn't? At a bear minimum, I think we should include it.

Also, is there any reason why the standard anti-frame busting script that most companies use (and it probably still mentioned for standard clickjacking in this Cheat Sheet, although no longer as a preferred mechanism), not effective against double-clickjacking as well? Based on the small part that I understand about it, I think that it would.

Copy link
Collaborator

@kwwall kwwall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of these proposed solutions that require intrusive user behavior should be removed and replace by Yibelo's client-side suggestion.

Furthermore, until @jmanico looks at this and provides his feedback, I am not approving this even if those changes are made. This is complicated and requires an AppSec person with much more expertise in JavaScript than I have.

@kwwall
Copy link
Collaborator

kwwall commented Feb 11, 2025

@mackowski wrote:

@caffeine-rohit do you have PoC of this exploit somewhere? I am wondering if COOP https://web.dev/articles/security-headers#coop and CORP https://web.dev/articles/security-headers#corp can help to mitigate that.

See Yibelo's Poc at https://www.paulosyibelo.com/2024/12/doubleclickjacking-what.html?m=1. Search for "Proof of Concept (PoC) Code" there.

I don't think that either COOP or CORP will be 100% effective as clickjacking attacks do not necessarily need to be "cross-site" even though they generally are. If one of those headers work, the more common SameSite: Lax/Strict cookies approach would probably suffice. Just my opinion. I'm waiting to hear from @jmanico on this.

@mackowski
Copy link
Collaborator

@jmanico can you also review this?

@jmanico
Copy link
Member

jmanico commented Feb 19, 2025

@jmanico can you also review this?

I am not comfortable pushing this work live yet. It's very bleeding edge. I'd like more experts in this area to review this and chime in. @kwwall concerns are very valid.

@kwwall
Copy link
Collaborator

kwwall commented Feb 20, 2025

@jmanico can you also review this?

I am not comfortable pushing this work live yet. It's very bleeding edge. I'd like more experts in this area to review this and chime in. @kwwall concerns are very valid.

Jim, you need not "approve" this PR, but I was hoping that perhaps that you could at least provide some specific feedback, especially regarding to the JavaScript snippets. In the meantime, please ask any expert that you know to take a look at this.

I will also reach out to @jeremylong and see if he's willing to give this a look. If I could find any contact info for Paulos Yibelo, I'd reach out to him and invite his feedback. (Although I did find a promising lead, so will try it.)

@jmanico
Copy link
Member

jmanico commented Feb 20, 2025

const observer = new IntersectionObserver(entries => {
    entries.forEach(entry => {
        if (!entry.isIntersecting) {
            alert("Warning: A hidden iframe may be attempting a Clickjacking attack!");
        }
    });
}, { threshold: 0.5 });
document.querySelectorAll("iframe").forEach(iframe => observer.observe(iframe));

This will likely cause a lot of false alarms. There are legit reasons for an iFrame to be off screen, like when a user scrolls away.

@kwwall
Copy link
Collaborator

kwwall commented Feb 20, 2025

const observer = new IntersectionObserver(entries => {
    entries.forEach(entry => {
        if (!entry.isIntersecting) {
            alert("Warning: A hidden iframe may be attempting a Clickjacking attack!");
        }
    });
}, { threshold: 0.5 });
document.querySelectorAll("iframe").forEach(iframe => observer.observe(iframe));

This will likely cause a lot of false alarms. There are legit reasons for an iFrame to be off screen, like when a user scrolls away.

@jmanico , is it possible to redeem this JS by enhancing it to check if the intersecting iframe is transparent (or almost transparent)? However, even that is possible, this seems like a relatively expensive check that could be abused as an intentional DoS attack, so maybe not. Like I said, I'm not a JS expert and neither did I stay at a Holiday Inn Express last night.

@caffeine-rohit
Copy link
Contributor Author

caffeine-rohit commented Feb 20, 2025

@jmanico @kwwall Thanks for your input! The original approach was meant to detect hidden iframes but, as noted, it could indeed produce false positives.

A potential enhancement could be to check not only visibility but also opacity (getComputedStyle(iframe).opacity) and display properties to determine whether an iframe is intentionally hidden rather than just off-screen due to natural scrolling. However, adding transparency detection might introduce performance overhead, as mentioned.

Regarding DoS concerns, continuous checks on multiple iframes could be optimized with debouncing or rate limiting to prevent abuse. Do you have suggestions on how to improve efficiency while maintaining security?

@caffeine-rohit
Copy link
Contributor Author

To refine this approach, we can:

  1. Enhance detection by checking visibility, display, and opacity alongside isIntersecting to ensure the iframe is truly hidden.

  2. Reduce false alerts by logging hidden iframes instead of triggering immediate alerts and verifying via user interaction.

  3. Optimize performance with debouncing (e.g., 500ms) to prevent excessive checks and minimize DoS risks.

Would these refinements address the concerns?

@kwwall
Copy link
Collaborator

kwwall commented Feb 20, 2025

I managed to connect with Paulos Yibelo via LinkedIn and asked him if he could take a look at this PR and maybe comment on it. He said he is unable to respond at the moment, but will see if he can follow up in a few weeks. However, I did ask if I could pass along his comments and he agreed. Note that I have made some minimal edits to protect his privacy:

Hi Kevin, thanks for reaching out. ... I did peak at the link and see some references to iframes. DoubleClickjacking does not use iframes at all. It uses windows, hence why it can bypass mitigations that can only affect iframes. SameSite, CSO, XFO, coop, corp, etc can't defend against it for this reason. The first couple lines of my blog should highlight how it works plus with the reproduction steps. The PoC script needs to be hosted on an http/s page to work and won't work if u try it hosted on file:///

I thought these videos explained it pretty well:

https://youtu.be/pnQQ7NQ1ZPA?si=Ywu-fl2pR5QKvZBo
and
https://youtu.be/MpdTo2Csmi0?si=aeYtGt8Lqiai29A4

My mitigation works pretty well and is implemented by PayPal, GitHub, video, Stripe, Exodus, Dropbox ...

https://labs.sqrx.com/two-clicks-to-chaos-how-double-clickjacking-hands-over-control-of-apps-without-users-knowing-e921039816e9

All my code does is, if no gesture is detected, disables the button. From end-user experience there is zero disruption.

@mackowski mackowski self-requested a review February 28, 2025 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update: Clickjacking_Defense_Cheat_Sheet.md to address Double Clickjacking
4 participants