The script is called from a passed A HREF with query string:
<a href="/cgi-bin/data.pl?name=joe&location=north>joe's details</a>
What the monkeys are doing is modifying the address URL field in Explorer and chaning name=joe&location=north to name=jim&location=north, name=jim&location=south etc.
I tried inserting the following at the begining of the scripts:
***********
$domain = 'www.mydomain.com';
$check_loc = $ENV{'HTTP_REFERER'};
unless ($check_loc =~ m#$domain# ) {
print header;
print "<HTML><BODY>";
print "<P><B>WARNING</B>. Not running from authorised site.</P>";
print "</BODY></HTML>";
exit;
}
#rest of my code is here.....
#only genuine visitors get to run the code
#monkeys get the warning above
***********
It seems to work ok most of the time but I was getting genuine customers saying they were getting this warning page.
Is the script good? Is there a better one?
I'm going to change it all to PHP soon but I really need a good interim quick patch.
Using the HTTP_REFERER can be "iffy". Some ISPs, proxy servers, and user client programs (such as
Norton Internet Security) block the HTTP_REFERER, and all you'll get is "-" in your server logs.
You may have to modify your script to allow the referer to be either your domain OR blank. Also,
don't warn the hackers too thoroughly - you don't want to encourage them to fish around to figure
out ways to get by your filter. Just redirect them somewhere (like to your home page) so it looks
like your script is broken. It does feel good to say "I caught you," but it gives them an efficient
test tool...
HTH,
Jim
I was guessing that some of the punters were using stuff like nortons to block the referer.
So how can I get around this quickly? I had a monkey hit a run of about 300 database records this evening. I've blocked his IP but he's on dynamic dial up - next time he'll be given a new IP.
If anyone knows of a way for perl to read in passed chars without displaying on the URL field I'd be grateful.
I'm not passing the vars via a form so I can't have hidden fields.
I know I gotta move to PHP but thats going to take me some time.
Your point about not warning them is a good one. I'll just produce a dummy page stuck on one record.
Any other "identifying marks or features"?
Can you block by User-agent?
Some combination of Referer, User-agent, and IP address block? Limit the damage to bona-fide
visitors, but get this guy off your site for awhile to give you some time to come up with a better
approach?
Something like:
Accept all requests with non-blank referer field and referer=your site.
Block requests with blank referer and some combination of IP_address or Remote_Host and User-Agent?
Well, I'm out of my league here scripting-wise, so if nothing else, this will bump your thread...
Best,
Jim
If anyone knows of a way for perl to read in passed chars without displaying on the URL field I'd be grateful.
It's the browser displaying the address bar.
I don't know how many links you would have to change, but you could use mod-rewrite.
Rewrite something like
/data/joe/north.html
to
/cgi-bin/data.pl?name=joe&location=north
Of course you'd have to change all the links, which might not be a solution for you, although it might be possible with a global search and replace on your static pages.
Say joeŚnorth becomes 6874726f6e7c656f6a. It's the text with an escape character and in hex backwards. Then add a CRC or hash of the code within the code at a "random" location.
That is, say joe is converted to 656f6a and north is 6874726f6e. The escape (to separate the two fields) is the 7c in-between.
North is 448630255470 in decimal and joe is 6647658. Length of North in decimal is 12, and joe is 7. Product of 12 and 7 = 54 in hex.
The whole string now:
6874726f6e7c54656f6a
Change any part, it will not match. Of course my checksum is quite terrible because there are several duplicates that would produce the same results. You could use a real hash, I just wanted to get the point across.
So, a bit of coding, and anyone changing the URL will have a hell of a good time working it out.
The length is variable, the escape location is variable, the checksum position is variable, and you can even vary the checksum method depending on the record type or the phase of the moon, etc...
Make data.pl check that the ticket it gets is associated with a recent time. This only allows them to work for a little while.
If you're really concerned, only allow the ticket to be used once.
Oh yeah, crontab a script to clean out old entries from your ticket table occasionally.
Does that cut it?
Use:
header ("Location: [blah");...]
instead
>Make the script add a random number variable
>'ticket' to the query string.
Or better, add a "time" id to the form.
$ttime =time;
print qq¦ <your form here><input type=hidden name=ttime value=$ttime>¦;
Then the receiver script checks the time value and stuffs it if it is close (say, 20-30 mins).
$dif =$FORM{'ttime'};
$allowedtime =60*60*30; #30mins.
if (time -$dif > $allowedtime) ... then go error.
I like the encryption method. I think I'll work on a version of that.
I'm trying to squeeze maxmimum speed out of the darn server though. I'm one of those speed freaks who has everything tuned to the max (man, I even overclock the toaster and coffee machine).
The timestamp idea is ok, but I dont know if it will work with this setup:
[search.html]
user enters a name to search for - has form which passes 'JOE' to search.pl
[search.pl]
scans search database all displays matching names
user clicks on link which then runs data.pl
******************************
Enter name to search: JOE
------
Results of your search:
<a href="/cgi-bin/data.pl?user=joe&location=north">joe montana</a>
<a href="/cgi-bin/data.pl?user=joey&location=south">joey tribiana</a>
<a href="/cgi-bin/data.pl?user=joebox&location=east">joe boxers</a>
<a href="/cgi-bin/data.pl?user=joe90&location=north">joe ninety</a>
******************************
See that the page with the list is generated on the fly.
I think that the monkey has either laboriously clicked on one, and then modified the URL address box to try every combination of Joe and location, else he has a script running on his own location which is accumulating the data. BTW, thousands of records in there!
Anyway, thanks again for mucking in guys.
First I really wanted to do some encryption similar to cgi-bin/data.pl?chunk=0EA7523FCB1
That would be really cool. But I can't do this because most of the links are generated off line by Clipper database app. Clipper doesn't know crypt(), encode() etc.
What I decided to do was to shove a simple checksum on the end of each url:
cgi-bin/data.pl?name=joe&location=north&id=123&length=138471
It is $id which the monkeys are changing to steal the data. $length (not using the obvious $checksum as that would give clues), is a function of $id
$length = (($id * key1) + key2);
in the data.pl I just check for the right checksum
if($id ne (($length - key2) / key1)) {
$id = 1;
}
What this does is to check the checksum. If it is incorrect then the $id has changed in the URL box and the monkey is always presented with database record 1.
Ok, it probably won't take long to work out the key2 and key1 fields but I'm thinking of changing the keys every half hour.
Run a script via crontab which creates random numbers for key1 and key2 and writes to a keys file. The search and data.pl then get the randomly changing keys from the keys file.