PHP script সাধারণত user input, একটি database, আর একটি login system handle করে — যার মানে এগুলো হাতেগোনা কিছু ভালোভাবে বোঝা attack-এরও সাধারণ target। প্রতিটার একটি নির্দিষ্ট, practical defense আছে।
SQL string-এ সরাসরি user input insert করে একটি query বানালে একজন attacker নিজের SQL inject করতে পারে — আগের MySQL lesson-এ PDO prepared statement-এর ব্যবহার ঠিক এটাই প্রতিরোধ করে, আর কেন তা বোঝার যোগ্য।
// দুর্বল — কখনো এটা করবেন না
$username = $_GET['username'];
$sql = "SELECT * FROM users WHERE username = '$username'";
// একজন attacker জমা দিলে: ' OR '1'='1
// এটা প্রতিটি row match করা একটি query-তে পরিণত হয়// নিরাপদ — একটি prepared statement
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = ?');
$stmt->execute([$_GET['username']]);
// Input SQL থেকে আলাদাভাবে পাঠানো হয় — এটাতে যাই থাকুক
// কখনো query-র অংশ হিসেবে interpret করা যায় নাএখানে সবচেয়ে গুরুত্বপূর্ণ একটি নিয়ম
যেকোনো user input সরাসরি একটি SQL query-তে string-concatenate করা একক সবচেয়ে common গুরুতর PHP security bug। একটি prepared statement কোনো optional উন্নতি না — user input থাকা প্রতিটি query-র জন্য এটাকে বাধ্যতামূলক ধরুন।
Escape না করে user input একটি পেজে echo করে ফেরত দেওয়া হলে, একজন attacker HTML বা JavaScript জমা দিতে পারে যা অন্য একজন visitor-এর browser-এ চলে — তাদের session চুরি করে, বা তাদের হয়ে কাজ করে।
// দুর্বল
echo "Welcome, " . $_GET['name'];
// একটি নাম <script>stealCookies()</script> আসল JavaScript হিসেবে চলে
// নিরাপদ — output-এর আগে escape করুন
echo "Welcome, " . htmlspecialchars($_GET['name']);
// script tag নিরীহ টেক্সট হিসেবে দেখানো হয়, চালানো হয় নাশুধু সন্দেহজনক অংশ না, সবকিছু escape করুন
মূল নিয়ম: "risky দেখতে" input-এর জন্যই না, প্রতিবার htmlspecialchars() দিয়ে output-এ escape করুন। Input নিরীহ হলেও এতে কিছু খরচ হয় না।
Protection ছাড়া, একটি malicious site একটি logged-in user-এর browser-কে আপনার site-এ একটি form জমা দিতে trick করতে পারে — browser স্বয়ংক্রিয়ভাবে user-এর session cookie যোগ করে, যা request-কে বৈধ দেখায়। একটি CSRF token এটা হারায়: session-এ সংরক্ষিত আর প্রতিটি form submission-এ দরকার হওয়া একটি random মান।
// Form render করার সময়
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
echo '<input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">';
// Form submission process করার সময়
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
die('Invalid request.');
}একটি password কখনো plain text হিসেবে বা MD5-এর মতো একটি সাধারণ hash দিয়ে সংরক্ষণ করা উচিত না — PHP-র built-in password_hash() ঠিক এই জন্য বানানো একটি শক্তিশালী, salted, ইচ্ছাকৃতভাবে ধীর algorithm ব্যবহার করে।
// একজন user register করলে
$hashed = password_hash($_POST['password'], PASSWORD_DEFAULT);
// $hashed database-এ সংরক্ষণ করুন — কখনো plain password না
// একজন user login করলে
if (password_verify($_POST['password'], $storedHash)) {
// সঠিক password
}| সমস্যা | Defense |
|---|---|
| SQL Injection | Prepared statement — কখনো SQL-এ input concatenate করবেন না |
| XSS | User input থাকা output-এর প্রতিটি অংশে htmlspecialchars() |
| CSRF | Session-এ একটি random token, প্রতিটি state-বদলানো form submission-এ check করা |
| Plain-text password | সংরক্ষণ করতে password_hash(), check করতে password_verify() |
সম্পর্কিত, অন্য দিক থেকে
এই lesson নির্দিষ্ট PHP-level defense কভার করে। এই সাইটের অন্য জায়গায় Cybersecurity কোর্স phishing, password manager, আর account security user-এর দিক থেকে কভার করে — এটার সাথে জোড়ার যোগ্য।