While developing sites either for myself or clients, I’ll often find myself using AJAX to make requests to PHP.
It’s important to keep the requests secure to prevent abuse or attacks, especially as I tend to use AJAX for making login requests which will pass over user information.
Here is my list of things that you could do to help protect your PHP Scripts from being run when they’re only meant for use via AJAX.
Checking PHP’s server variable
PHP has a variable called $_SERVER, the bit that we want to check is the requested with header, which if the request is done via AJAX, will return the value xmlhttprequest.
To use this within PHP, you could use a similar function to the one below, which will check if the variable returns the right value, and if it doesn’t it uses the die() function to kill the script.
<?php
//Check if it's set first
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH'])){
if(strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == "xmlhttprequest"){
//This should be AJAX
} else {
//Doesn't appear to be an AJAX Call
die();
}
} else {
//Doesn't appear to be an AJAX Call
die();
}
?>Ensure the referring URL is your website
Security Issue
The referring URL is provided by the client, and therefore can’t always be trusted.
Another check that you could add before letting your PHP Script run is a function that checks the requests referring URL. You could ensure that the URL matches the website you’re working on.
<?php
if(!empty($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] !== "domain.com"){
//Doesn't appear to be the right referring URL.
die();
}
?>
You may want to double-check if you would like to add this to your code. Some browsers, scripts or users may opt to hide or mask their referring URL to avoid tracking, so it may not always be set. This is unlikely to have an effect on many users though.
Only use post method when using AJAX
AJAX gives you an option to use either GET or POST, along with some others, but I don’t need to go over those as they aren’t often used. You can make the change pretty easily by settings the type option to POST.
$.ajax({
type: "POST",
url: '/api',
data: data
});You should also only accept information via the $_POST variable, and sanitize any information that’s going to interact with a database as any information can be edited by the client at any time.
Only using HTTPS to send requests, any of them…
You should already be using HTTPS across your website, SSL certificates are easy to obtain, and can also be obtained for free via LetsEncrypt. They also are not very hard to set up, with most hosting companies offering good support or already providing them out of the box, like Shockhosting which provides a number of hosting services.
There’s a reason why I’ve added this bit to this post, it’s because a lot of websites still allow people to send requests via HTTP. You should always redirect users or disallow HTTP access to any of your site’s contents.
Limiting the amount of requests can be made from one IP
Often attackers will use vulnerable APIs to brute force logins and perform other requests repeatedly. Ideally, you’ll need to use a database for this, which if you’re coding an API you’ll likely have access to one.
Each time a user trips an error within the API code, you should log it in a table, let’s call it api_errors which will store information such as:
- IP of the offending user.
- Number of errors from this IP
- Timestamp that will be the first time the IP is reported, but will be updated each time the IP triggers an error.
So, for you to use this, you’ll need to check the database each time there is an error, if the IP exists, and 6-12 hours has not passed then add 1 to the number of errors.
Once that number reaches a specified number, let’s say 10, it will block the IP for a certain amount of time.
This is probably one of the easiest ways to prevent abuse, but most attackers will use proxies or VPNs, so I’d highly suggest using a service like CloudFlare, which would help you prevent abuse from bad IPs. You could even go a step further and use a service called GetIPIntel, which is a service that will check IPs and return a score value.
Using a Token system while sending AJAX Calls
A lot of websites that require good security will make attempts at using a token based login or API system. I personally don’t use tokens on many of my projects, but if you’re interested, you should do some research into JWT, JSON Web Tokens. You can also learn more about tokens & CSRF tokens from this awesome answer on Stack Overflow.
My attempts at implementing a token system have worked, but are not very advanced. It’s important to know that even some advances token based system are easy for some attackers to crack.
How it works?
- Token generated, encrypted using Two Way Encryption. You can find out more from this Stack Overflow answer.
- Each page/API load, the token is given to the user. On my project, I stored in into
localstoragerather than cookies. You can choose whether you want to regenerate your tokens on every load, some sites have token that expire after x hours, and require renewal.
Token Generation
For generating a token in my project, I included the following bits of information, this is used to verify the token when we decrypt the token. I then do a check to make sure the token isn’t expired and that the information is still valid.
- Timestamp of when the token should expire.
- MD5 hash of the client’s user agent.
- User 2-letter country code (Not entirely required).
These 3 bits of information were in a PHP array and then JSON encoded using the json_encode() function. The array was set up like the following, before being JSON encoded.
$data = array("expire" => $expire, "agent" => $agent, "country" => $country);