yttcom.net · Tech · PHP Education
← Back to Guides
Guide 05

Security Basics

Why security matters for PHP endpoints, what the threats actually are, and exactly how yttcom.net defends against them.

Why does a personal server need security?

The moment a PHP file is live on the internet, anyone in the world can call it. Bots scan every IP address constantly looking for open endpoints. If your file_write.php has no protection, someone will find it and start writing files to your server.

Analogy: Putting a PHP file on the internet without security is like putting a door in a public street with no lock. Most people walk past. But some will try the handle.

Tokens — the lock on the door

A token is a long secret string that only authorized callers know. Every request to a yttcom.net endpoint must include the token. The PHP script checks it immediately — if it is wrong or missing, the script stops and returns a 403 error. Nothing else happens.

<?php $SECRET = "yttcom-admin-d60283b1a40a3180ea51e7a579e4d9f2f8fc5f07ac81d89e"; $token = $_POST["token"] ?? ""; // "" if not sent if (!hash_equals($SECRET, $token)) { http_response_code(403); die(json_encode(["status" => "error", "message" => "Unauthorized"])); } // Nothing below this line runs unless the token matched

Why hash_equals() and not just ===?

Regular string comparison === stops the moment it finds a difference. This means it takes slightly longer to reject "yttcom-admin-x..." than to reject "wrong". An attacker can measure these tiny time differences and guess the token one character at a time.

hash_equals() always takes the same amount of time regardless of where the strings differ. This closes that loophole completely.

// AVOID for tokens — leaks timing information if ($SECRET !== $token) { die("Unauthorized"); } // CORRECT — timing safe, always same speed if (!hash_equals($SECRET, $token)) { die("Unauthorized"); }

Path traversal — the sneaky attack

If your endpoint lets callers specify a filename, an attacker might send ../../etc/passwd as the filename. The ../ means "go up one folder" — they are trying to climb out of your directory and read sensitive system files.

// DANGEROUS — never do this $file = $_POST["filename"]; // attacker sends: ../../etc/passwd $path = "/home/yttcooyc/public_html/data/" . $file; // path becomes: /home/yttcooyc/public_html/data/../../etc/passwd // = /etc/passwd — the server's user database! // SAFE — basename() strips any path components $file = basename($_POST["filename"] ?? ""); // "../../etc/passwd" becomes just "passwd" // which won't be in your data/ folder anyway

Rate limiting — stopping brute force

Brute force means trying thousands of different tokens until one works. Rate limiting stops this by tracking how many failed attempts come from each IP address, and blocking that IP after too many failures.

// Simplified version of what yttcom.net does: $IP = $_SERVER["REMOTE_ADDR"]; // who is calling? $MAX = 10; // allow 10 failures $WIN = 300; // per 5 minute window // Read the failure log $log = "/home/yttcooyc/public_html/logs/rate_limit.txt"; $data = file_exists($log) ? json_decode(file_get_contents($log), true) : []; // Check if this IP is currently blocked if (!empty($data[$IP]["blocked_until"]) && time() < $data[$IP]["blocked_until"]) { http_response_code(429); die(json_encode(["status" => "error", "message" => "Rate limit exceeded"])); }

The ?? operator — safe input reading

When you read from $_POST or $_GET, the key might not exist. PHP will throw a warning if you try to read a missing key. The ?? operator gives you a safe default instead.

// Without ?? — warning if "token" was not sent $token = $_POST["token"]; // With ?? — returns "" safely if key is missing $token = $_POST["token"] ?? ""; $filename = $_POST["filename"] ?? ""; $system = $_POST["system"] ?? "default";
yttcom.net security checklist

Every yttcom.net PHP endpoint does all of these:

✅ Token check with hash_equals() — first thing, before anything else
✅ Rate limiting — 10 failures per IP per 5 minutes → HTTP 429
✅ PHP version hidden — header_remove("X-Powered-By")
✅ CORS locked to https://yttcom.net only
✅ basename() on all user-supplied filenames
✅ .htaccess protecting data directories from browser access

Still pending (David action required):
⏳ .htaccess on /sessions/, /transfers/, /systems/, /core/
⏳ CORS fix on save.php and load.php (currently wildcard *)

⚠️ Never put a token in a URL. URLs appear in server logs, browser history, and referrer headers. Tokens always go in POST body or request headers — never in a GET parameter.