user10360773
user10360773

Reputation:

How to protect invalid ads or malicious users using script jQuery?

To protect the ads, think about creating a protective layer, that is, a transparent div after there are two or three clicks by the same user and, thus, avoid more clicks by the same visitor.

$(document).ready(function() {

   $(".ads iframe").load(function() {
      $(".layer-protect").hide();
   });
});
.ads {
    position: relative;
}
.layer-protect {
    position: absolute;
}
iframe {
  position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="ads">
    <iframe src="https://es.stackoverflow.com/"></iframe>
</div>
<div class="layer-protect">
   <p>Hi! Testing...</p>
</div>

But of course this was not enough, so apart from creating a layer I would have to delete all the links that the iframe contains

let i = 0;
$("iframe *").each(function() {
    this.pos = i;
    $(this).on("click", (e) => {
        if (localStorage.getItem("link"+i) == null) {
                localStorage.setItem("link"+i, 1);
        } else {
           let clicks = localStorage.getItem("link"+i);
           if (clicks >= 3) {
               if (typeof e.target.getAttribute("href") == "string" && e.target.getAttribute("href").toLowerCase().search(location.hostname.toString().toLowerCase()) == -1) {
                  e.preventDefault();
               }
           } else {
             localStorage.removeItem("link"+i);
             clicks++;
             localStorage.setItem("link"+i, clicks);
           }
        }
    });
i++;
});

How can I set a validity time to the data stored in localStorage without the user being online or not?


My tests:

I have created a page with the following links: iframe.html

<div>
    <a href="https://example.com" target="_black">1</a>
    <a href="https://example.com" target="_black">2</a>
    <a href="https://example.com" target="_black">3</a>
    <a href="https://example.com" target="_black">4</a>
    <a href="https://example.com" target="_black">5</a>
    <a href="https://example.com" target="_black">6</a>
    <a href="https://example.com" target="_black">7</a>
    <a href="https://example.com" target="_black">8</a>
</div>

Then this page I have loaded in an iframe

<iframe src="http://example.com/iframe.html"></iframe>

As a result it doesn't work, I can give all clicks on the links without any restriction

Note: It is difficult to determine the content of an iframe since ad providers such as google adsense do not define an exact content.

If in most cases the content of the iframe cannot be eliminated, then it will be possible to count the clicks that the iframe receives, and then create a div, a protective layer that covers the entire iframe and, thus avoid more than two or three clicks, according to the rule that I determine.

Upvotes: 1

Views: 446

Answers (3)

GonZo
GonZo

Reputation: 58

Getting into ad iframes and trying to inspect / modify them seems like an extremely complicated job that borders on the impossible.

Therefore, what I suggest is that you create your transparent protective layer that exactly matches the size of the ad and have it always over it, enabled and capturing any clicks along with their relative coordinates. You block the clicks from bubbling down to the ad. You evaluate each click and determine wheter they should go through or not and then transfer the valid ones to the ad at the same coordinates you received them on your layer.

This solution would only work if the attacker's script is emulating user interaction via taps / clicks and not targeting the ad iframe directly.

Also, you could be running the risk of the ad server detecting your transfered clicks as artificial, being script generated.

There is only so much you can really do.

Upvotes: 1

Twisty
Twisty

Reputation: 30893

You may consider using .contents() to be able to examine the items in the HTML of the iFrame element:

$("iframe").contents();

It seems you are looking for Links, so consider the following.

  $("iframe").contents().find("a").each(function(i, el) {
    $(el).on("click", (e) => {
      if (localStorage.getItem("link" + i) == null) {
        localStorage.setItem("link" + i, 1);
      } else {
        let clicks = localStorage.getItem("link" + i);
        if (clicks >= 3) {
          if (typeof e.target.getAttribute("href") == "string" && e.target.getAttribute("href").toLowerCase().search(location.hostname.toString().toLowerCase()) == -1) {
            e.preventDefault();
          }
        } else {
          localStorage.removeItem("link" + i);
          clicks++;
          localStorage.setItem("link" + i, clicks);
        }
      }
    });
  });

It's very difficult to be sure I understand what you are trying to accomplish as you have not provided a complete example. If you want to update your post and include an example of the HTML that would appear in the iframe, people would be able to help further.

See More:

Update

If we break the objective down a bit, we can see all the steps we need to take. You report you want to track when links are clicked and if they are clicked too often or within too quick a time frame, you want to prevent the click action.

Objectives

  • Use Local storage to track the links clicked, number of clicks up on a link, last time a link was clicked
  • When a link is clicked, update the count & last time it was clicked

Example

https://jsfiddle.net/Twisty/61e3m07v/35/

JavaScript

$(function() {
  function getLinkData() {
    var strLinks = localStorage.getItem("links");
    var links = [];
    if (strLinks != null) {
      links = JSON.parse(strLinks);
    }
    return links;
  }

  function saveLinkData(arr) {
    console.log("Saving Data");
    console.log(arr);
    localStorage.setItem("links", JSON.stringify(arr));
  }

  function findLink(h, arr) {
    var result = -1;
    $.each(arr, function(i, v) {
      if (h.toLowerCase() == v.link) {
        result = i;
      }
    });
    return result;
  }

  function saveLinkClick(h) {
    var links = getLinkData();
    var ind = findLink(h, links);
    var result = true;
    if (ind >= 0) {
      // Check your current link stats
      // if meet or exceed threshold, result = false
      links[ind].count++;
      links[ind].last = Date.now();
    } else {
      links.push({
        link: h,
        count: 1,
        last: Date.now()
      });
    }
    saveLinkData(links);
    return result;
  }

  $("a").click(function(e) {
    return saveLinkClick(this.href);
  });
});

As you can see, we have a number of helper functions. These help us store the following data, as an example:

[
  {
    "link": "https://example.com/index.html?adid=8",
    "count": 1,
    "last": 1609804570776
  },
  {
    "link": "https://example.com/index.html?adid=4",
    "count": 1,
    "last": 1609804574405
  },
  {
    "link": "https://example.com/index.html?adid=5",
    "count": 3,
    "last": 1609804583245
  }
]

Complex data of this nature cannot be stored in localStorage like this. In my example, we use JSON.stringify() to create a single String of data that can be stored to localStorage. It will be stored like:

[{"link":"https://example.com/index.html?adid=8","count":1,"last":1609804570776},{"link":"https://example.com/index.html?adid=4","count":1,"last":1609804574405},{"link":"https://example.com/index.html?adid=5","count":3,"last":1609804583245}]

To help us find the URL or link in our data, we have a finder function that returns the Array Index of the link or a -1 if it is not present. We can then update existing data or append new data for a new link.

It is at this point you would want to evaluate what to do if the count is too high or the time passed is too low.

Once you have everything working the way you want for Links in a stand alone page, or test, you then want to apply the same activity to the links inside an iFrame. See my original example.

Upvotes: 1

kmoser
kmoser

Reputation: 9273

Here's a working example in pure JS (no jQuery required) that stores link clicks and last-clicked-dates in localStorage. Links are given keys link1, link2, etc. So the first link has a key of link1 and the value is the number of times it has been clicked. Last-clicked dates are given keys date1, date2, etc. and values of stringified last-clicked date.

This code assumes that the <iframe> tags are always in the same order, and that the <a> tags in them are always in the same order (and go to the same places) with every reload.

For every <iframe> on the page, upon its load event firing (important, otherwise we will try to access its HTML before it has loaded!), we cycle through all the <a> tags and assign them a sequential number via setAttribute(). We use that number in our onClick() handler to identify that link so we have a unique ID for use in localStorage.

There are liberal calls to console.log() which you may want to remove if you think they will help users figure out what's going on.

var MAX_CLICKS = 3; // Can only click a link this many times before it gets disabled
var MAX_HOURS = 12; // Disabled links get re-enabled after this many hours

function getLinkClicks( id ) {
    var clicks = parseInt( localStorage.getItem( 'link' + id ) );
    if ( isNaN( clicks ) ) {
        clicks = 0;
    }

    return clicks;
}

function setLinkClicks( id, clicks ) {
    localStorage.setItem( 'link' + id, clicks );
}

function setLinkDate( id ) {
    localStorage.setItem( 'date' + id, new Date().toString() );
}

function getLinkDate( id ) {
    var s = localStorage.getItem( 'date' + id );
    return new Date( s );
}

var i = 1; // Counter used to assign link ID numbers
var iframes = document.querySelectorAll('iframe');
iframes.forEach(function(iframe){
    iframe.addEventListener('load', function() {
        var links = iframe.contentWindow.document.getElementsByTagName('a');

        // Give this link an ID and add its click handler:
        Array.from(links).forEach(function(link){
            link.setAttribute( 'n', i ); // Tag the link with an ID
            link.addEventListener('click', function(e) {
                var id = e.target.getAttribute( 'n' ); // Get the link's assigned ID
                var clicks = getLinkClicks( id );
                clicks++;

                setLinkClicks( id, clicks );
                console.log(`Setting link ${id} to ${clicks} clicks`);

                // Determine how many hours ago it was last clicked:
                var dt = getLinkDate( id );
                var diff_hours = ( new Date() - dt ) / ( 1000 * 60 * 60 )
                console.log(`Link ${id} hours since last click = ${diff_hours}`);

                if ( 
                    clicks <= MAX_CLICKS
                        ||
                    diff_hours >= MAX_HOURS
                ) {
                    // Allow the click

                    // If we are here only because enough time elapsed, reset this link's clicks to 0:
                    if ( diff_hours >= MAX_HOURS ) {
                        setLinkClicks( id, 0 );
                    }

                    setLinkDate( id );
                    console.log( `Allowing click on link ${id}` );
                } else {
                    // Too many clicks on this link, or not enough elapsed time before it is enabled again, so disallow it:
                    console.log( `Preventing click on link ${id}` );
                    e.preventDefault();
                }
            });
            i++;
        });
    });
});

Upvotes: 1

Related Questions