Kombinované využití principů MVC a OOP. Vraťme se k implementaci MVC. Obsluha vzdáleného vkládání souborů

Představte si web sestávající ze dvou stránek. Na hlavní stránce se zobrazí nějaký text:

Druhá stránka představuje její editor:


Na něm můžeme měnit obsah hlavní stránky a změny ukládat.

V horní části stránek je hlavička webu, která se skládá ze dvou prvků. První je nezměněn a odráží název webu. Druhá obsahuje název aktuální stránku: Buď Číst, nebo Upravit.

Pod záhlavím je menu, které je stejné pro všechny stránky webu a obsahuje odkazy na tyto stránky.

Nezměněné je také „zápatí“ stránky, které se zobrazí další informace o webu, například adresa, telefonní číslo, informace o tvůrci stránky.

Centrální část stránky „Čtení“ zabírá text, který můžeme nastavit na stránce „Úpravy“ pomocí běžného HTML formuláře s prvkem textarea

Výchozí body

Musíme zkombinovat dva přístupy – MVC a OOP. K tomu se při vývoji architektury systému budeme řídit následujícími pravidly.

  • Podle šablony MVC design Soubory řadiče, modelu a zobrazení budou rozděleny do tří samostatných adresářů.
  • Každý ovladač bude představen samostatný soubor, který bude deklarovat třídu řadiče, která zapouzdřuje logiku řadiče a poskytuje metody pro zpracování HTTP požadavku uživatele.
  • Každá stránka webu bude mít samostatný kontroler zodpovědný za její výstup.
  • Systémové modely budou také implementovány jako třídy.
  • Pohledy budou implementovány jako běžné soubory PHP se značkami HTML proloženými kódem PHP pro zobrazení hodnoty proměnných skriptu.
  • HTTP požadavky do systému budou prováděny přes speciální vstupní bod - soubor index.php.
  • Ačkoli toto téma již bylo diskutováno, znovu opakujeme, že je důležité mít jasno v rozdílech mezi účelem tříd regulátorů a tříd modelu. Třídy řadičů se používají ke zpracování HTTP požadavku uživatele, tedy k příjmu vstupních parametrů požadavku a přípravě výsledné HTML stránky. K této práci používají regulátory modelové třídy, které představují jednotlivce funkční bloky: práce s databází, práce se soubory, práce s uživatelskými účty atd. Každý takto logicky propojený blok je reprezentován jako samostatná třída. Váš systém může mít například databázovou třídu, která bude ukládat popisovač k aktuálnímu databázovému připojení a poskytuje sadu metod pro dotazování na databázi a získávání různé sady data.

    Vstupní bod

    Vstupní bod je skript, ze kterého může uživatel volat přímo adresní řádek prohlížeč. Téměř všechny příklady, které jste napsali dříve, obsahovaly více vstupních bodů. Nicméně, na momentálně Ve webovém programování se považuje za dobrou praxi používat jeden vstupní bod na web. Veškerá logika pro přechod mezi stránkami je implementována pomocí dalších parametrů předávaných skriptu a také prostřednictvím relací a souborů cookie. V jediném vstupním bodě může programátor definovat akce specifické pro každou stránku webu. Může to být autentizace uživatele, navázání připojení k databázi, inicializace globálních proměnných a další úkoly.

    V našem příkladu také použijeme jediný vstupní bod – soubor index.php. Podívejme se na jeho obsah:

    Pojďme vyřešíme práci tohoto scénářeřádek po řádku.

    Include_once("inc/C_View.php"); include_once("inc/C_Edit.php");

    První dva řádky obsahují soubory ovladače pro stránky „Čtení“ a „Úpravy“.

    Přepnout ($_GET["c"])

    Zde je analyzován parametr GET s názvem c:

    Případ "edit": $controller = new C_Edit();

    přerušení; Li tento parametr

    ukládá řetězec "edit", pak je proměnné $controller přiřazen objekt třídy C_Edit, jehož popis je v souboru inc/C_Edit.php, zařazeném na samém začátku skriptu.

    Pokud parametr c není zadán nebo má jinou hodnotu než "edit", provede se další větev příkazu switch:

    Výchozí: $controller = new C_View();

    Zde je proměnné $controller přiřazena instance třídy C_View. Nakonec poslední řádek volá metoduŽádost()

    pro vytvořený objekt:

    $controller->Request(); Vezměte prosím na vědomí, že zde můžeme vidět typický příklad polymorfismu Nakonec poslední řádek volá metodu. Proměnná $controller může ukládat jak instanci třídy C_Edit, tak instanci třídy C_View. Proto nemůžeme předem znát metodu která třída bude ve skriptu volána. Jediné, na čem záleží, je to správné fungování

    Obecně je úkol vstupního bodu jednoduchý - předat řízení jednomu z ovladačů. Který z nich je určen pomocí parametru požadavku GET s názvem c .

    Hierarchie ovladačů

    Začneme navrhovat systém a nejprve určíme, které ovladače v něm budou přítomny. Ze souboru index.php můžete vidět, že systém má minimálně dva řadiče, reprezentované jako třídy C_Edit a C_View . Úkolem třídy C_Edit je organizovat zobrazení stránky „Úpravy“ a třída C_View má zobrazovat stránku „Čtení“. Zpracování vstupní parametry a výstup stránky je zapouzdřen uvnitř metody Nakonec poslední řádek volá metodu, který musí být přítomen ve třídách C_View i C_Edit. To může navrhnout vytvoření společné rodičovské třídy pro dva řadiče. Implementace C_View bude skutečně stejná jako C_Edit, takže oddělení základní třídy řadiče je užitečným krokem.

    Došli jsme tedy k myšlence potřeby vytvořit základní třídu řadiče. Říkejme tomu C_Base. Bude abstraktní a nebude mít konkrétní implementace. Zavádíme jej tak, aby z něj zdědily ostatní třídy řadičů. Třída C_Base bude ukládat základní vlastnosti a metody specifické pro každý řadič daného webu.

    Pojďme se zamyslet, jaké parametry jsou společné pro každou stránku webu? Za prvé, toto je název webu. Za druhé, text umístěný ve spodní části každé stránky. To také zahrnuje položky nabídky, které jsou stejné pro každou stránku webu. Abychom to shrnuli, můžeme říci, že za to odpovídá řadič C_Base základní šablona místo.

    Je zřejmé, že každý ovladač bude obsahovat metodu Nakonec poslední řádek volá metodu, odpovědný za vyřízení žádosti. Proto lze jeho deklaraci také umístit do třídy C_Base a učinit abstraktní, takže k implementaci této metody jsou vyžadovány dědičné třídy.

    Možná má smysl některé více zdůraznit obecné vlastnosti nebo metody pro všechny řadiče webu. Přemýšlejte o tom sami. Zdůrazňujeme, že C_Base je základní třída, která kombinuje vše společné prvky každý správce konkrétního webu.

    Ale zkusme jít ještě dál a zamyslete se, je možné vytvořit třídu řadiče, která by zapouzdřovala logiku, která je neměnná pro jakýkoli řadič na libovolném místě? Do takové třídy již nebudeme moci přenést vlastnost site name, ale například metodu Nakonec poslední řádek volá metodu, odpovědný za zpracování požadavku a vygenerování výsledné stránky, musí být vždy přítomen v každém správci.

    Nenechme si vás uvíznout a demonstrovat hierarchii tříd řadičů, které vám doporučujeme vzít jako vzor:

    Tento diagram se používá v popisu jazyk UML a nazývá se diagram tříd. Každý obdélník na něm odpovídá samostatné třídě. V horní části obdélníku je název třídy zvýrazněn tučně. Šipky označují dědičné vztahy. Vlastnosti třídy jsou uvedeny kurzívou a její metody jsou kurzívou. Znak – před vlastnostmi nebo metodami označuje, že vlastnost nebo metoda je deklarována s modifikátorem private, znak # odpovídá chráněnému modifikátoru a + odpovídá modifikátoru public.

    Třída ovladačů

    Ovladač je základní třída regulátoru, který je navržen tak, aby zapouzdřil nejběžnější prvky charakteristické pro regulátory všech lokalit. Zde jsme zahrnuli řadu pomocných funkcí:

  • Šablona()- nahradit sadu proměnných do šablony a zobrazit ji na obrazovce;
  • IsGet()- zkontrolovat, zda byl požadavek GET dokončen;
  • IsPost()- zkontrolovat, zda byl požadavek POST dokončen.
  • Třída Controller obsahuje deklaraci nám již známé metody Nakonec poslední řádek volá metodu.
    Podívejme se na jeho implementaci:

    Veřejná funkce Request() ( $this->OnInput(); $this->OnOutput(); )

    V metodě Nakonec poslední řádek volá metodu zpracování požadavků rozdělujeme na dvě části: zpracování vstupních dat (metoda OnInput()) a vytvoření výsledné stránky (metoda OnOutput()). Toto rozdělení je docela pohodlné a navrhujeme jej použít v budoucích projektech. Metody OnInput() A OnOutput() musí být v dětských třídách přepsány.

    Třída C_Base

    C_Base je základní řadič pro náš konkrétní web. Ve většině případů potřebujete jeden základní ovladač pro celý web. Třída C_Base je zodpovědná za základ HTML šablona, může definovat základní proměnné pro celý web, například název webu.

    Kromě toho ve třídě C_Base musíte přepsat metody OnInput() A OnOutput() a zahrnout do nich akce společné pro všechny správce lokality. Kontroléry, které zdědí z třídy C_Base, přepíší tyto metody, ale budou moci volat rodičovské metody pomocí klíčové slovo rodič.

    Navrhujeme následující implementaci metod OnInput() A OnOutput() ve třídě C_Base.

    Chráněná funkce OnInput() ( $this->title = "Domovská stránka"; $this->content = ""; } protected function OnOutput() { $vars = array("title" => $this->title,"content" => $this->content); $page = $this->Template("main", $vars); echo $page; } !}

    V metodě OnInput() můžeme inicializovat proměnné šablony výchozí hodnoty. V metodě OnOutput() nejprve vytvoříme pole proměnných šablony a poté použijeme metodu Šablona(), který je definován ve třídě Controller a je zodpovědný za substituci proměnných v šabloně. Jeho realizace je na vás. Podle naší představy metoda Šablona() má dva parametry: první z nich je název šablony, která se má připojit, druhý parametr je pole proměnných, které je třeba do šablony dosadit. Nakonec se vygenerovaná stránka zobrazí na obrazovce. Jak si dokážete představit, toto je poslední operace, kterou musí skript provést. Proto funkce OnOutput() třída C_Base by měla být volána na samém konci našeho PHP skriptu.

    Ovladače C_View a C_Edit

    C_View a C_Edit - ovladače konkrétní stránky místo, mají přednost před metodami OnInput() A OnOutput(), ale také přenést řízení na ovladač C_Base.

    Podívejme se na příklad implementace těchto metod pro třídu C_View.

    Chráněná funkce OnInput() ( parent::OnInput(); $this->title = $this->title . " :: Reading"; $this->text = $this->getText(); ) chráněná funkce OnOutput( ) ( $vars = array("text" => $this->text); $this->content = $this->Template("theme/v_view.php", $vars); parent::OnOutput(); )

    V metodě OnInput() nejprve probíhá hovor rodičovská metoda, pak určí název stránky a načte její text pomocí metody getText(). Konkrétní implementace metody getText() pro nás nyní není důležitá. Může přijímat text z databáze nebo ze souboru, nebo dokonce vracet nějakou předdefinovanou konstantu. Důležité je, že ve výsledku uložíme text do nějakého pole třídy.

    Metoda OnOutput() začíná vytvořením pole, které je předáno funkci generování šablony Šablona(). Výsledek jeho provedení se uloží do pole obsahu. Poté se zavolá rodičovská metoda OnOutput(). Návrat k textu metody OnOutput() třídy C_Base a všimněte si, že ve skutečnosti používá hodnotu pole obsahu, kterou tvoříme v aktuální metodě OnOutput() třída C_View.

    Pokud se znovu podíváte na kód, všimnete si, že volání rodičovských metod OnInput() A OnOuput() druh rámců smyčka zpracování požadavků ve třídě C_View.

    Cyklus zpracování žádosti

    Nyní se podívejme na celkový pohled zpracování žádosti, kterou jsme obdrželi. Spouštění skriptu začíná ze souboru index.php. Zde se vybere požadovaný ovladač a přenese se na něj řízení volání metody Nakonec poslední řádek volá metodu.

    Tato metoda zahajuje dvě fáze zpracování požadavku:

  • Volání modelu (OnInput());
  • Generování HTML (OnOutput()).
  • První fáze by měla fungovat v následujícím pořadí:
  • Základní ovladač (C_Base);
  • Konkrétní ovladač (C_View nebo C_Edit).
  • Dále začíná fáze generování HTML, měla by probíhat v opačném pořadí:
  • Konkrétní ovladač (C_View nebo C_Edit);
  • Základní ovladač (C_Base).
  • Na diagramu tento cyklus lze reprezentovat takto:


    Na závěr

    Tím příběh o aplikaci končí OOP spolu s konceptem MVC. Zbývající funkční bloky webu budete muset implementovat sami. Nenechte se zastrašit vysokou obtížností úkolu. Postupně vám budou nové pojmy důvěrně známé a budete se v nich moci orientovat mnohem jistěji.

    Programování nebylo nikdy pro nikoho snadné. S každým dnem cvičení, s každým novým PHP skriptem získáváte vlastní neocenitelné zkušenosti, které vám v budoucnu umožní rychle, kompetentně a efektivně rozvíjet internetové systémy jakékoli složitosti. Klíčem k této příležitosti je Jedná se o profesionální přístup k vývoji webu.

    LFI je schopnost používat a provádět místní soubory na straně serveru. Zranitelnost umožňuje vzdálenému uživateli získat přístup pomocí speciálně vytvořeného požadavku k libovolným souborům na serveru, včetně těch, které obsahují důvěrné informace.

    Jednoduše řečeno se jedná o zranitelnost při otevírání souborů ze serveru + nedostatečné filtrování, které umožňuje otevřít libovolný soubor.

    Zahrnutí vyhledávacího souboru

    Nejprve pojďme zjistit, jak určit parametry, které jsou zodpovědné za zahrnutí souborů.

    Parametry vyhledávání
    Existují dvě možnosti vyhledávání parametrů: automatické nebo ruční vyhledávání.

    Automatické vyhledávání
    Automatické vyhledávání lze provést pomocí stejného pavouka v burpsuite Článek o burpsuite najdete na naší wiki.

    Manuální vyhledávání
    Nyní budu mluvit o ručním vyhledávání. Předpokládejme, že jsme našli parametr GET:

    Http://site.ru/folder/index.php?file=gallery

    Nahraďte řetězec „index“ za parametr:

    Http://site.ru/folder/index.php?file=index

    Pokud jste otevřeli jeden z indexových souborů (jakékoli přípony) umístěných na webu, pak můžeme s jistotou říci, že soubor je zodpovědný za výměnu souborů.

    Toto jsou parametry, které potřebujeme.

    Definování filtrů
    Poté, co jsme obdrželi seznam parametrů, musíme zkontrolovat, zda mají filtrování.

    Nulová filtrace
    Zkusme nahrát soubory, které jsme neočekávali, že se zobrazí =)

    Ekvivalentem takového souboru v Linuxu je soubor /etc/passwd

    (V v tomto případě vzali jsme http://site.ru/folder/index.php?file=index.html jako řádek s parametrem)

    Zkusme to napumpovat:

    Http://site.ru/folder/index.php?file=/../../../../../../etc/passwd

    Vysvětlím, co se děje – přechod do složky /../ znamená posun v hierarchii nahoru (přesněji se jedná o zranitelnost procházení cesty). Protože složka atd leží v kořenové složce, pak se k ní musíme dostat hádáním: to znamená, že čím častěji stoupáme, tím vyšší je šance, že skončíme v kořenové složce (pak musíme několikrát napsat /../).

    Pokud se objeví soubor. Pak zvažte, že jste našli LFI. V tomto případě není žádný filtr.

    Nulový bajt
    V tomto případě jsme vzali http://site.ru/folder/index.php?file=index jako řádek s parametrem, tedy s chybějící koncovkou.
    Ale i bez filtru mohou nastat problémy. Například může být na konec parametru přidána přípona.

    Například s požadavkem /../../../../../../etc/passwd lze převést na

    /../../../../../../etc/passwd.php

    Ale tentokrát je tu možnost opravit linku ve starém verze PHP Stále existuje taková nevýhoda jako Null Byte Injection.
    Jedním z nich je přiřazení nulového bajtu. Parametry, když jsou přenášeny přes http, jsou šifrovány v šifrování URL. A v tomto kódování vypadá nulový bajt přesně jako %00.

    A protože V PHP a mnoha dalších jazycích, když je řádek načten přesně do nulového bajtu, můžeme jej přiřadit ke středu řádku, takže další část řádku je zahozena.

    Pokud v tomto případě zadáme do parametru /../../../../../../etc/passwd.php%00, dostaneme následující řádek:

    Http://site.ru/folder/index.php?file=/../../../../../../etc/passwd%00

    A řádek v paměti serveru bude vypadat takto:

    /../../../../../../etc/passwd%00.php ==> /../../../../../../etc/ passwd

    A nakonec jsme mohli zahodit koncovku a získat požadovaný soubor.

    Limit řetězce
    Další možnost zahození koncovky je možná u String Limit - zkrácení řetězce.
    A jaký je z toho přínos? Ale co když tu část řádku s koncovkou zahodíme, tak získáme řádek, který potřebujeme, ale bez koncovky.

    Tentokrát nám může pomoci linka /./. Vysvětlím, co se děje:

    /./././././index === index

    Přesněji řečeno, v bash jsou tyto dvě linie totožné. Dovolte mi uvést příklad, jak to může pomoci.

    1) Máme parametr, jehož řetězec je zkrácen na 100 znaků 2) Zkusme zobrazit soubor index.txt za předpokladu, že je přiřazena koncovka.php 3) Zkusme zadat index.txt - ve výsledku Výstupem je index.txt.php 4) Chcete-li obejít ochranu, musíte zadat index.txt/././././../....../././ 5) Výsledkem je ukáže se, že k této dlouhé řadě je přidán .php, který je následně zahozen 6 ) Zisk!

    php filtr
    Pro mě je pro lfi nejzajímavější možnost lfi s php filtrem. Hned vám dám příklad.

    Http://site.ru/folder/index.php?file=php://filter/convert.base64-encode/resource=index

    V důsledku toho se v našem prohlížeči nespustí php soubor a zobrazí se jeho zdroje base64.
    Toto je in v poslední době se na soutěžích objevuje stále častěji.

    Využití zranitelnosti

    Pokud čtete tento odstavec, pak jste s největší pravděpodobností již našli LFI. Pak zjistíme, jak nám to může být užitečné.

    Příjem důležité soubory(ne skripty)
    No, nejtypičtější věcí pro lfi je stahování souborů, které bychom podle plánu správce neměli stahovat. Zde je příklad úkolu:

    Úkol: V rámci služby hostování souborů existuje několik účtů - admin a uživatel (a test hesel). Musíte si stáhnout soubor flag.txt uložený v účtu správce. Řešení: 1) Nahrajte soubor a podívejte se na odkaz ke stažení. Bude to vypadat takto: http://site.ru/download.php?file=user/image.png 2) Složka uživatele skutečně existuje. Ale při stahování z odkazu http://site.ru/user/image.png je chyba 403, což je docela logické. 3) Pro každý případ vytvořte odkaz s jasně chybějícím souborem uživatelská složka

    , a pokud je odpověď 404, pak chápeme, že odpověď je 403 == odpověď je 200. 4) Zkontrolujeme, zda je pravda, že náš soubor by měl být na cestě admin/flag.txt: http://site .ru/admin/flag vrátí 403 (pamatujte na předchozí bod).
    5) Proč ne, protože nemůžeme stahovat, nasměrovat skript download.php na soubor, který potřebujeme? Pokusíme se přejít na http://site.ru/download.php?file=admin/flag.txt a získat soubor. 6) Zisk! Získávání zdrojů
    Při získávání zdrojů mohou nastat určité problémy. Například při provozu se zdroje nezobrazují, ale spouštějí. V tomto případě nám pomůže následující:

    krát php
    filtr.

    Příklady zde jsou docela jednoduché, takže nevidím smysl je uvádět.

    LFI -> RCE

    Protože Vzhledem k tomu, že tato sekce již přechází do nebezpečnější sekce RCE, je celkem logické přesunout diskuzi o této problematice právě do ní. Hledej na webu =)

    Mnoho příkladů

    SharifCTF 2016 - technews Řešení na architektuře MVC (Model-View-Controller, Model-Display-Controller) na PHP 5.1 s využitím možností knihovny SPL (Standard PHP Library, Standard PHP Library).

    Zavedení

    Vítejte v prvním úplném průvodci pro PHP 5. Budete potřebovat PHP 5.1 s nainstalovaná knihovna SPL, protože některé z nich budeme používat nejčastěji nejnovější příležitosti PHP 5.

    V tomto tutoriálu vám ukážu, jak vytvořit jednoduchý systém MVC (architektura MVC je nejběžnějším návrhovým vzorem pro velké webové aplikace). Provedu vás všemi kroky od začátku do konce vytvoření kompletního systému MVC.

    Jeden vstupní bod

    Jednou z důležitých věcí na MVC je, že existuje jeden vstupní bod do aplikace namísto hromady souborů PHP, které dělají něco takového:

    Budeme mít jeden soubor, který zpracuje všechny požadavky. To znamená, že se nebudeme muset potýkat s připojením global.php pokaždé, když potřebujeme vytvořit nová stránka. Tento „jediný vstupní bod“ se bude jmenovat index.php a prozatím to bude takto:

    Jak vidíte, tento skript zatím nic nedělá, ale chvíli počkejte.

    Všechny dotazy směřovat na domovskou stránku, použijeme mod_rewrite a nastavíme direktivu RewriteRule v .htaccess. Vložme následující kód do souboru .htaccess a uložme jej do stejného adresáře jako index.php:

    RewriteEngine na RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule ^(.*)$ index.php?route=$1

    Nejprve zkontrolujeme, zda požadovaný soubor existuje pomocí direktivy RewriteCond, a pokud ne, přesměrujeme požadavek na index.php. Tato kontrola existence souboru je nezbytná, protože jinak se index.php pokusí zpracovat všechny požadavky na web, včetně požadavků na obrázky. A to je přesně to, co nepotřebujeme.

    Pokud nemáte možnost používat .htaccess nebo mod_rewrite, budete muset ručně adresovat všechny požadavky na index.php. Jinými slovy, všechny odkazy budou muset vypadat jako „index.php?route=[request-here]“. Například "index.php?route=chat/index".

    Nyní, když všechny požadavky procházejí jedním vstupním bodem, můžeme začít psát skript index.php. První věc, kterou musíme udělat, je inicializovat systém. Vytvořme si adresář include a v něm soubor startup.php (bude to náš inicializační soubor). Do index.php vložíme následující kód:



    
    Nahoru