This Website acts as the sign-in page to my Minecraft server, hosted at the same address. Signing in adds your IP address to the list of allowed addresses which can access the server.
The motivation behind this project, was that I noticed a large number of automated Minecraft bots attempting to join my server. Even though I have a Whitelist enabled on the server (see Whitelist-Bot project page), I was still receiving a large volume of unwanted traffic to my server, which was clogging up my logs. Additionally, as I host my server on my own network, as a security measure, I want to reduce unwanted traffic as much as possible to limit any exposure to potential attack vectors I could be more susceptible to.
This implementation ensures that unwanted traffic isn't just turned away, but ignored and given no information at all, so to a user who hasn't logged in through this website, it appears as if I'm not hosting a Minecraft server at all. This hopefully makes it much harder to launch an attack, but also more importantly, it deters attention from my server in the first place.
This project works using a combination of backend technologies. The goal of this project was to give me more familiarity with tools like PHP, SQL/Databases, and Node.js I wanted to leverage the developer experience of Node.js, while keeping the functionality of PHP, so I decided to combine the best of both, by using PHP for the main routing and logic of the program, and using the Node.js servers for internal API calls and communication between servers in my network. For extra security, these API calls are only responded to when send from specific IP addresses within my network, and with the correct KEY, stored securely on each machine.
I use PHP with Apache to manage the main logic of the Website. I used PHP for its easy integration with Apache, which helps to enforce restrictions on directory access, and easy implementation for user sessions. I also wanted to ensure I had exposure to a variety of backend technologies, given PHP's continued prevalence in Web applications today.
PHP is used to manage user logins, logouts, signups, and page permissions, which is made easier with PHP's native session handling and page redirection.
PHP also makes it easy to connect with the MySQL database I use to store user data, with prepared statements to limit the risk of SQL injection.
Additionally, using Apache configurations, I can store the sensitive database credentials in the $_SERVER
variable, accessible within the PHP, but not visible in the source code.
I use three Node.js servers, two running on the Web server, and one on the Minecraft server:
One on the Web server handles password hashing and checking, as I found this can be most safely and easily implemented in Node.js making use of the 'crypto'
library.
To ensure that user data is safely and securely stored, I use a combination of some cryptographic techniques.
The first technique is storing a hash of the user's password in the database, as opposed to the actual password, so that in the event of a database leak, my users' passwords aren't exposed. When a user logs in, I check the hash of their entered password against the stored hash, which should only be the same if their password is correct.
This still creates issues when users use common passwords, or use the same password as other users, so to make sure each hash is unique, I generate a random unique "salt" for each user to add to their password before hashing it. This salt is then stored with the user's password so that I can check the hash as before. This would make it much harder for an attacker to figure out a user's password given access to the database, but still not impossible, especially if the user has a common password.
To mitigate this issue, I also store a special key outside of the database, a "pepper", in a file only accessible by the servers. When a user creates an account, this pepper is also added to their password before it is hashed, but it is not stored in the database. This means that even if an attacker were to have access to the entire database, it would still be very difficult for them to figure out any individual user's password, as without the pepper, which they wouldn't have access to, they wouldn't be able to generate a matching hash for any password they tried.
The security of all of these methods is made much more secure with the use of the scrypt
function from the 'crypto'
library, which uses a computationally intensive hashing function with many iterations, to significantly slow
down any hash-cracking attempt.
Lastly, for extra security, I make use of the timingSafeEqual
function, which prevents revealing timing information when comparing hashes, to mitigate this vector of attack.
The Node.js server on the Minecraft server handles requests to allow new IP addresses to view the Minecraft server. It only responds to requests with the correct source IP and correct API key.
These credentials are stored in a separate directory on the Web server accessible to the PHP code through the $_SERVER
variable, and in .env files for the Node.js server, accessible with the 'dotenv'
library.
It responds to POST requests which specify an IP
and Username
, and executes the necessary commands to add that IP to the Firewall with access to port 25565 (Minecraft), adding a comment with the Username for clearer logging.
Lastly, I have one Node.js server set up to serve content for a specific directory on the Web server, currently /node, however, this was mostly for my own learning and it doesn't serve a real purpose for the project.