I offer a number of free scripts that allow Joomla users to search add-on components from the main search feature. In order to drive traffic to my site, I display my website in the results of the search results. Kind of sneaky I know but it does the job. Most users can nearly eliminate any sign of the credit link if they select "When Related" in the credit link options. Nevertheless, I still get requests to remove the link completely. I write the free scripts to attract visitors and the credit link is my reward. The traffic becomes clicks and the clicks become cash, etc...
For my next update of scripts, I would like to offer users the chance to purchase an activation key that would prevent the credit link from being displayed.
Here is a little background on the search scripts.
A package is a ZIP file with and XML document and a PHP document. The XML tells Joomla what the parameters are for the script and adds the appropriate data to the database. The PHP file reads the fixed and user set parameters and then searches the components database tables for related records and send the data to the main search system.
What I did was to insert my link information into the database and perform a search on that table as well. By default, the search has no where clause so the link is always returned. This is by far the simplest section of the code. LOL
What I want to do is generate a different identification code for each script download and store that information in a separate database table. Both the XML and PHP files will be marked with this ID and that ID will correspond to and activation key that is either generated on the fly when they purchase the key or stored in the database when the ID is generated. I can add a parameter to the XML file to allow the insertion of the key and I can have the script check that key against what the key should be for that script's ID.
Obviously most of my users can't hack my code or they would have done it by now but if I do one key for everyone, everyone will be selling them. I also don't want the magic key to be found by simply looking in the database or script.
I can do a number of hashes and other methods to generate the key but usually with a little looking into the code, the method is easy to find and replicate. I had considered doing the process backwards. Create the key and then the ID is the hash of that string. So that to turn the credit link of, the script takes the inputed key, hashes it and if that equals the ID then the key is good. Since the script would generate that which the user already knows only after the key is generated, the key would be more difficult to determine unless extreme measures are taken like reverse MD5 hashing. I you get what I mean?
I don't want to get too complicated and I cannot assume that any libraries are available on the user's server.
Let's begin this little problem by determining what we can deduce for certain from the remote server. Now, unfortunately, because of the way the Interweb works, the only single piece of data that we can know for sure is the IP address of the remote server initiating the request. We could, in theory, rely on the web address as well from the $_SERVER array. However, what if the user were to do this at the top of the script:
$_SERVER['HTTP_HOST'] = '.talkphp.com';
That would, in practice, modify the script's web address in the $_SERVER array and therefore be impractical to be used to secure an entire script.
If we consider though that any web address is associated with an IP address, and as the server makes the request with the IP address in the HTTP packet, this cannot be successfully forged because the packet would not be sent back to the correct location. Thus, if we were to tie the domain to the IP address, then in theory this would be a concrete solution. The packet may look something like so, in pseudo terms:
License Key: fe0a4
WAN IP Address: 220.127.116.11
Web Address: .talkphp.com
Then within the remote database you would have successfully tied a web address to the IP address, and therefore you can now send the web address using the $_SERVER array because if the corresponding IP address does not match then you can assume it is an attempt at cheating the system.
Now, another problem that crops up from the above is what if the initial request to register their license key is fed through a proxy, and thus tying the web address .talkphp.com to a publicly available open proxy. Like this:
License Key: fe0a4
Proxy IP Address: 18.104.22.168
Web Address: .talkphp.com
I'm sure it's clear now that the IP address, because anybody can relay through it, is useless. As long as they set the $_SERVER['HTTP_HOST'] to the web address in which the license was registered via, then they've successfully overcome the feeble security.
Nonetheless, there is something you can do above that! If you perform a lookup on the web address which the script is supposedly running on, you could ensure that the IP address which the script is claiming to be running on, matches the domain's IP address via the lookup request. Here are the results from a typical "nslookup" on talkphp.com:
Thus the remove part of the script, based on your server, must ensure that the IP address 22.214.171.124 matches the IP address the license registered has been initiated from. If it does not match then you should not continue.
The potential downsides to this approach I see are negligible, but there are issues. Namely, if the script is based on the same server, and they knew one another, then they could quite easily modify the script to change the $_SERVER['HTTP_HOST'] array. This is where the encryption would come in for your script. Using an application such IonCube, you could encrypt the license segment of the code, and any other important files, and therefore resultantly preventing users to tamper with your script.
I'm become quite tired at the moment, but I believe that's a really good foundation. My mind has just gone numb, but I was going to go into the possibility of storing files remotely and using eval() to execute the script, but this requires some more thinking about. It all depends on how secure you require it to be.
The man who comes back through the Door in the Wall will never be quite the same as the man who went out.
The Following User Says Thank You to Wildhoney For This Useful Post:
I've been working on a similar script for over a week now. I've created a complete page which stores all the keys I am releasing for my CMS. Over a 100 of them. All randomly base64_ and url_ encoded. For short, it generates and exports a complete list of jibberish. Then, a build in security feature in my CMS decodes the entire file using;
$license = file_get_contents('licensefile');
Next, it checks through eregi (simply because it's insensitive) if, in a for loop, the key is present in the main file.
Now, I know this is not 100% hackproof, but we're getting there. At first, I was thinking of integrating a serial (into my CMS) and then making an external connection to my personal database (phpMyAdmin). Since that is not allowed by a BUNCH of hosts, I can not remotely deactivate or remove a serial. Next to that, what IF my host goes down? Then I'll be spammed with now over a dozen of users complaining why their copy of my CMS isn't working (since it's linked to my database). Customer is always king, so I have to make them happy again, thus giving them something for free.
"Humanity loves the word FREE."
I am linking the perspective Wildhoney has on this one. eval(uating) the script localy (server-side) on the remote host. My site that is. Now it is not even that safe because the only thing to do is export a value or boolean and tell the script it can go on processing the data.
The system we use, Shoppa, uses licenses as well. For modules and the complete CMS. It can be turned of remotely using the "mother of Shoppa's", the core. Simply clicking the green 'V' turns it off. And of course the red 'X' turns it on again. Thats also one way to do it.
This has been a complication for me and others for a long time but we're getting there.