How to block the link from malicious bot visitors? - javascript

I'm producing an event registration website. When someone click on a link:
Reserve id=10 event
The system is doing a "lock" on this event for ten minutes for this visitor. In that case no one else can reserve this event in next ten minutes. If the payment is done in that time, everything is OK, else the event is unlocked again. I hope the idea is clear.
PROBLEM: When bot (google bot, malicious bot, or angry customer script :P) visits this page, he see this link. Then he enters the page. Then the lock is done...
Also if someone visit recursive: /reserve/1, /reserve/2, /reserve/3, ... He can lock all the events.
I thought about creating a random md5 string for each event. In that case, every event has (next to id) unique code, for example: 1987fjskdfh938hfsdvpowefjosidjf8243
Next, I can translate libraries, to work like this:
<a href="/reserve/1987fjskdfh938hfsdvpowefjosidjf8243" rel="nofollow">
Reserve
</a>
In that case I can prevent the "bruteforce" lock. But the link is still visible for bots.
Then I thought about entering the captcha. And that is the solution. But captchas are... not so great in case of usability and user experience.
I saw few websites with reservation engine working like this. Are they protected? Maybe there is a simple ajax / javascript solution to prevent the bots from reading this as a pure text? I thought about:
Reserve
<script type="text/javascript">
$('#reserve').click(function(e) {
e.preventDefault();
var address = ...;
// something not so obvious to follow?
// for example: md5(ajaxget(some_php_file.php?salt=1029301))
window.location('/reserve/' + address);
});
</script>
But I'm not sure what shall I do there to prevent bots form calculating it. I mean stupid bots will not be able even to follow javascript or jquery stuff, but sometimes, someone wants to destroy something, and if the source is obvious, it can be broken in few lines of code. And whole database of events will be locked down with no reservation option for noone.

CRFS + AJAX POST + EVENT TOKEN generated on each load.
Summary: don't rely on GET requests especially through a elements.
And better if you add some event block rate limits (by IP for instance).
EDIT: (this is a basic sketch)
replace all the href="..." with data-reservation-id=ID
delegate click on the parent element for a[data-reservation-id]
in the callback, simply make a POST ajax call to the API
in the API's endpoint check rate limits using IP for instance
if OK, block the event and return OK, if not return error.

IP-Specific maximum simultaneous reservations
Summary: Depend on the fact that many simple bots operate from one host. Limit the number of simultaneous reservations for a host.
Basic scetch:
Store the requesting IP alongside the reservation
On reservation request count the IP's which have a non-completed reservation.
SELECT Count(ip) FROM reservations WHERE ip=:request_ip AND status=open;
If the number is above a certain threshold, block the reservation.
(this is mostly an expansion of point 4 given in avetist's excellent answer)

Related

How to call API only when user reload/leave site from the browser alert and not on click of cancel?

I am trying to do an API call when the user is trying to close/reload the browser/tab. I don't want to call the API if the user clicks on cancel. I followed JavaScript, browsers, window close - send an AJAX request or run a script on window closing, but it didn't solve my issue. I followed catching beforeunload confirmation canceled? for differentiating between confirm and cancel. I have no idea how to make the API call when the user reloads/closes the browser and not to call the API when user clicks on cancel. I followed JavaScript, browsers, window close - send an AJAX request or run a script on window closing and tried like
For showing alert on reload or close the tab
<script>
window.addEventListener("onbeforeunload", function(evt){
evt.preventDefault()
const string = '';
evt.returnValue = string;
return string;
})
</script>
and on click of cancel, nothing should happen. If the user is forcefully closing the browser or reloading, the API should be called
<script type="module">
import lifecycle from 'https://cdn.rawgit.com/GoogleChromeLabs/page-lifecycle/0.1.1/dist/lifecycle.mjs';
lifecycle.addEventListener('statechange', function(event) {
if (event.originalEvent === 'visibilitychange' && event.newState === 'hidden') {
var URL = "https://api.com/" //url;
var data = '' //payload;
navigator.sendBeacon(URL, data);
}
});
</script>
But it's not happening. Any help is appreciated. Thanks
Your problem is happening because you're using beforeunload to present a prompt.
I can see that you're handling the beforeunload event properly, so you must already be aware that browser vendors have deliberately limited the ability of script authors to do custom stuff when the user wants to leave the page. This is to prevent abuse.
Part of that limitation is that you don't get to find out what the user decides to do. And there will not be any clever workarounds, either. Once you tell the browser to present the beforeunload prompt, you lose all your power. If the user clicks the Okay button (i.e. decides to leave the page), the browser will refuse to run any more of your code.
Presenting the prompt creates a fork in the road that you are prevented from observing. So, put a laser tripwire there instead of a fork:
window.addEventListener("onbeforeunload", function(evt) {
navigator.sendBeacon(url, payload)
})
This is guaranteed to run when the user actually leaves the page, and only when the user actually leaves the page. But, you sacrifice the ability to try to talk the user out of leaving. You can't have it both ways.
You can't always get what you want, but if you try, sometimes you just might find you get what you need. -- The Rolling Stones
I can only think of one way to accomplish what you need, but it requires help from the server. This is not an option for most people (usually because the beacon goes to a third-party analytics provider who won't do this), but I'm including it here for completeness.
before the beforeunload handler returns, fire a beacon message that says "user is maybe leaving the page"
after firing that beacon, and still before returning, set up a document-wide mousemove handler that fires a second beacon message that says "the user is still here" (and also de-registers itself)
return false to present the prompt
modify your server so that it will reconcile these two events after some kind of delay:
if the server receives beacon 1 and then also receives beacon 2 (within some reasonably short time-frame, e.g. 5 minutes), it means the user tried to leave but then changed their mind, and so the server should delete the record of beacon 1
if the server receives beacon 1 but doesn't receive beacon 2 within the time-frame, then it means the user really did leave, and so the server would rewrite the previous beacon datapoint to say "user actually departed"; you wouldn't need to actually write beacon 2 to your datastore
(Or, depending on expected traffic and your infrastructure, maybe the server just holds the beacon 1 datapoint in RAM for the 5 minutes and commits it to your datastore only if beacon 2 never shows up. Or you could write both beacons to the database and then have a different process reconcile the beacons later. The outcome is identical, but they have different performance characteristics and resource requirements.)
P.S.: Never use "URL" (all caps) as a variable name in javascript. "URL" is actually a useful web API, so if you use that exact variable name, you're clobbering a useful ability. It's just like if you did let navigator = 'Henry'. Yes, it will execute without error, but it shadows a useful native capability.

Password protection for a page with a simple function - what are the downsides?

I am doing work on an e-commerce platform, and I was asked to come up with a solution so that a certain group of customers could enter a password protected page on the site. The platform doesn't allow for this, as in the functionality is not available, so according to customer support, it's something you would have to create a custom template for and build from scratch. It doesn't need to be fancy, or hacker proof, just secure enough. So instead of doing that, I dropped the script below into the body of the page.
My first version: I use a prompt to ask for an input (password). If you click "prevent this page from creating additional dialouges", it creates sort of an infinite reload loop for that tab (not ideal, but problem?). Are there other serious problems? Easy hacks for your average person?
$("body").hide();
var passwordCheckFunction = function() {
var testPassword = window.prompt("YOU SHALL NOT PASS");
if (testPassword === "thisPredefinedPassword") {
$("body").show();
} else {
location.reload();
}
};
passwordCheckFunction();
Any advice would be much appreciated, and thank you for your time.
Create your secret page as a category.
Customize it to your heart's desire by choosing a custom template
file for it.
Finally, restrict it to only the authorized customer group
by removing it from view from guests and every group except the
authorized one.
Using this method, the customer only has to sign into his/her own customer account. BigCommerce will prevent access to the page by reading the assigned customer group of the customer.
I realize this isn't your desired method, but you might consider instead just making your page inactive in the admin area of your BC store, then instead of a password provide the direct url for users that are able to see that page.
I'm not sure about the implications for google indexing with an inactive page, but I would assume that they are set not to index it, and if not you could set it in robots.txt

VBScript Locate user in Directory; Return results (Found or Not Found)

I want to begin by apologizing for not including any code. VBScript is completely out of my realm of knowledge and I have been asked to use it for a small program here at work.
The goal: I have been asked to search part of the active directory (I am told that it is an OU in our active directory) and compare the user that is attempting to login to the computer with the OU. If that person DOES exist in the specified OU, I need to do something. If the person DOES NOT exist, I need to do something else.
The specifics: I work at a hospital. The point of this is to keep nurses from using the laptops designated for the physicians on the floors. When a nurse badges in to said computer, if the person logging in exists in the "Physicians" OU (which is my OU), then continue with the login, else log the person out (which would be to key an F4 in Imprivata). This being said, we use a program called Imprivata that logs the user in when they swipe their badge. Imprivata can also perform keystrokes like keying in the user's password, clicking buttons, etc. The Imprivata program allows for code to be written in the background in VBScript, WSH, and I believe JavaScript and then executed when a condition exists (a person logging on a computer). Unfortunately, I know NOTHING about any of these languages.
I have been searching the web and trying different things for a week now with no luck. In fact, I have even got close to anything working so any help would be greatly appreciated and again I apologize for the lack of code.
The easiest thing would be getting the current users OU, which can be done with
Set objSysInfo = CreateObject("ADSystemInfo")
strUserName = objSysInfo.UserName
Now you can check if your physicians OU is part of that. That is of course not the exactly same thing as checking whether that user is in the physicians OU because there could be cases where the same username exists in both OUs. However if the same user in both OUs is something that happens you have problems either way.
After you got the users OU just do a simple string compare. I always use a little helper function for that
Function contains(sourceStr, checkStr)
contains=InStr(1, sourceStr, checkStr, vbTextCompare) > 0
End Function
That does nothing more than a case insensitive check if a string is substring of another. so
contains(strUserName, "OU=Finance,OU=North America,OU=Pacific Coast,dc=fabrikam,dc=com")
with the DN of your OU might already be enough.
If you are new to vbscript a good point to start would be the old "Hey Scripting Guy" blogs where everything is explained in a lot of detail. This one for example is about checking a user's OU.
Windows has settings for this.
Allow log on locally
This logon right determines which users can interactively log on to this computer. Logons initiated by pressing CTRL+ALT+DEL sequence on the attached keyboard requires the user to have this logon right. Additionally this logon right may be required by some service or administrative applications that can log on users. If you define this policy for a user or group, you must also give the Administrators group this right.
Default on workstations and servers:
Administrators
Backup Operators
Users.
Default on domain controllers:
Account Operators
Administrators
Backup Operators
Print Operators
Server Operators.

Creating user turn based game in Javascript

I've created a whiteboard web app where a multitude of registered users, login and start drawing on the html5 canvas. I devised the 'multiplayer' aspect of the game through python websockets and the login is made with php, currently the canvas page has a 'session_start();' so I can be able to add a feature to see who's currently using the application and I feel it may come in hand for the 'turn based' aspect as well.
Now I'm trying to prevent users from being able to draw on the canvas at the same time, if possible i'd like every user to have a fair turn at drawing on the canvas. I'm not sure how I'd accomplish this but I feel that Javascript will most definitely be the logic behind this.
Any advise or suggestions as to how I'd go about achieving this feature?
EDIT
Ok since nobody has any answers or suggestion I'll try and provide to you what I've attempted so far, I think it may be on the right direction even though it doesn't work:
var player = document.getElementById("inputnameid").value;
var currentPlayer = player; // player class
//array of player objs.
var array1 = [player]; // list that OnCurrentPlayerEndTurn cycles through to choose user
// call this at the start of the app
function OnStartTurn()
{
currentPlayer.OnBeginTurn();
var inputs=document.getElementById('inputty');
for(i=0;i<inputs.length;i++){
inputs[i].disabled=false;
}
//This function will activate the GUI so the user can now act
}
// call this function when setTimeout is 10 seconds
function OnCurrentPlayerEndTurn()
{
setTimeout('OnCurrentPlayerEndTurn();', 10*1000);
change currentPlayer variable to the next player in line
OnStartTurn(); // will cause the next player to begin his turn
}
Your question seems to be focused on the front-end code, which, while important, is not the critical part of this problem. As you've noted, the core of a turn-based game is the round-robin passing of active players. You probably want this to be done server-side: it's much easier to coordinate the various players from there.
You'll maintain a list of the players in a given game on the server. Before the game starts each client will register with the server and an identifying user id is stored there. Then in each round, the server allows each player a turn. The turn order is of course up to the specifics of the game, but the general idea is the same whether turn order is fixed or fluid.
As each player's turn comes around, the server sends a ticket to that player's client. This is essentially a one-time pad (OTP) concept: generate a random token that is hard to guess (so don't use just an increasing integer, but instead some cheap hash function or the like). The client then sends this ticket along with the request for the move they would like to make, and the server validates that the ticket corresponds to the currently active player before taking any action.
Depending on the rules and requirements of the game, the server can then immediately invalidate the ticket (e.g., chess), can wait until an 'end of turn' move, or can invalidate the ticket after some amount of time. The server then generates a new ticket for the next player to go.
The client-side code follows naturally from this architecture. All inputs can be disabled by default, and only enabled when the client holds a valid ticket. If the ticket is designed to time out, you probably want a method of querying the server to determine if it is still valid. If the user is always responsible for ending their own turn (explicitly or implicitly) you can get away without that.

Best way to prevent a user clicking 'like' multiple times

I'm implementing a like feature for a site I'm working on. A user doesn't have to be logged in and they can either like or dislike a particular page. At the end of it all I'd like to be able to populate a list of articles or stories with the most likes.
I have a very simple method that currently uses an onclick javascript function to update a database via ajax and a php function.
This is working ok. What I'd like to do is prevent a user from spamming the button.
At first I thought of maybe getting the IP address, storing that in the database and then running a check. Is there a better way?
Technically there isn't a bomb proof way to do so. You could get pretty close by allowing one vote per ip-useragent combination. You'd have to implement this on the server side.
PHP Example
$concienceKey = md5($_SERVER['REMOTE_ADDR'] . $_SERVER['USER_AGENT']);
$query = "SELECT COUNT(*) FROM clickConcience WHERE key = `" . $concienceKey . "`";
//run your query
//.....and get the $count;
//
//already voted!
if($count > 0){
echo 'already voted';
return false;
}
//remember entry
$insert = "INSERT INTO clickConcience (key, datetime) VALUES (`" . $concienceKey . "`, NOW())";
//run your query
//.....and insert
//
return true;
straight forward answer, you won't be able to do it.
If I really want to SPAM your "like" button, I will find a way to do so, especially if you're not forcing me to be signed in (I used to write pretty good bots and were pretty efficient spamming big link submission sites).
Javascript will only stop mediocre spammers or sock puppet account holders. As a spammer I can circumvent your Javascript pretty easily, either by programming a time-based robot to like your post, or by sending requests directly to your server (I will not even load your site).
What you need to do, if you really want to prevent spammers from spamming this feature efficiently (efficiency is the keyword here because spammers can still spam your feature, but their likes won't count) is to log every IP that likes a post along with its geographical information (it's not always 100% accurate, but it's a good start) and then run a process in the background that checks for suspicious origins and penalize such likes (either by assigning them less value, or just subtracting them from the total count).
For example if your main audience is people living in the United States, but one post gets a bunch of likes from Mexico, Salvador, India, Australia, Russia, then it's more than likely that there's a spammer behind a proxy or a network similar to TOR and he/she can change his/her IP address at his/her will.
After a few hundred thousand records, you'll have a good base to start blacklisting IP addresses. I usually use R programming language to get statistical information about my databases.
But then again, a good spammer could use a list of IP addresses of compromised computers coming from your audience's country or geographical location, and use those IPs to abuse the feature. Those bots are harder to spot, but you can analyze previous posts and come up with useful metrics as "Likes/comment ratio".
If one post has a huge number of likes, but low number of comments, then it's very probable that someone spammed it, but then again I can program my bot to like AND post a comment so the numbers look natural.
I'm not sure what kind of project you're working on, but if it's something similar to link submission, do not rank (whatever your users are liking) by the number of likes.
The number of likes should only be a factor, you can take a look at how HackerNews or Reddit rank the posts (those projects are open source), but it's a combination between multiple factors.
Just hide the button after it has been clicked for the first time.
It does even makes more sense, when using an AJAX handler for sending the click...
Use cookies. Lets say you have a button where the user can like article 123456789
<button id="like" articleID="123456789">Like</button>
script :
function setLike(articleID) {
document.cookie=articleID+'=y';
}
function hasLiked(articleID) {
var cookies=document.cookie.split(';');
for (var i=0;i<cookies.length;i++) {
var cookie=cookies[i].split('=');
if (cookie[0]==articleID) return true;
}
return false;
}
var button=document.getElementById('like');
button.onclick=function() {
var articleID=this.getAttribute('articleID');
if (!hasLiked(articleID)) {
//register the like in your system
//...
//
setLike(articleID);
} else {
alert('You cant like or dislike an article twice');
}
}
Of course the user can delete all his or hers cookies - but a user can also like the same page / article from 100 different computers. The above prevents the most common scenario : People repetetively clicking like or dislike a lot of times from the same computer in a short distant of time.

Categories

Resources