PHP adat küldés B-ből A-ba (amatőr kérdés..)

Üdv!

Első körben, sorry a lámaságért.

Adott egy olyan felállás, hogy legyen A szerver. Ezen van egy komplett SQL adatbázis, miegyéb a főszoftver ezen fut. Jelenleg is.

Ebbe kerülne jópár adat, totálisan random helyekről és random "tűzfal" és egyéb környezetből.

Ami a lényeg, legyen az egyik hely B hely. B helyen időnként lefut egy php script, ami adatokat gyűjt be.
Ezeket kellene eljuttatni A szervernek (A szerver ezt majd szépen feldolgozná).

Viszont ami lényeg lenne, hogy B kliens szimplán 80-as (és vagy 443-as) HTTP* kommunikációval tudja ezt továbbítani az _A_ szerverhez, ahol ő majd a fogadott adatokkal csinál amit akar.

Azért lenne fontos a HTTP(s) kommunikáció, mert az nagy eséllyel bárhonnan átmegy.

Milyen "megoldások" fele indulhatnék el? Az adatok viszonylag egyszerűek, de kiszámíthatatlan az, hogy "hány sornyi adat".

Gyakorlatilag ilyesmi adat"halmaz" menne át B-ből -> A -ba. :

id=2,count=100,valamimas=1214,stb=4556
id=3,count=120,valamimas=3214,stb=1122
stb

Ezt megkapja _A_ szerver, elkezdi nézegetni, ellenőrizgetni, feldolgozni, majd SQL-be betöltögetni.

Csak ötleteket kérnék, bár ha valaki előáll egy faék egyszerű "kliens/szerver" kóddal az ne tartsa magában :) Köszi előre is!

ps.: s még mielőtt esetleg beesnek a trollok, nem, nem vérpistike php kóder vagyok, totál nem webprogramozással foglalkozom, ez saját projekt, hobby, semmi más.

Hozzászólások

a legegyszerűbb, talán a http post, body-ba, JSON-ben formázva.
--
blogom

Szerver oldalra teszel egy scriptet, ami vár egy postolt fájlt, körbe rakod valami auth-al (pl. basic auth + ssl), aztán akár curl-al rádobsz egy csv fájlt (szerver oldal ~5 sor apache konfig és ~10 sor kód PHP, a kliens onnantól, hogy meg van a CSV-d, egy egysoros curl hívás, vagy PHP-ból ~15)

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

ha jól értem, B szerver állítja elő és küldi el A-nak adatot. Ez esetben:

B oldal:
$data = array('alma', 'korte');
$data_json = json_encode($data);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://example.com/postdata.php");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

A oldal (http://example.com/postdata.php):
$data = json_decode($_POST);
foreach($data as $k => $v) {
// feldolgozás
}

nem ellenőriztem, de kb. valami ilyesmi fapados verzió működik - már ha van telepítve a curl PHP modul :)

Szerintem az "A" oldalon a $_POST nem tartalmazza a json stringet. Helyette én a teljes request body-t így nyerném ki:

$data = json_decode(file_get_contents("php://input"));

(Nem ellenőriztem a te példádat, lehet hogy úgy is működik, csak még nem találkoztam a $_POST tömb ilyen használatával...)

Mi lenne a kérdés?
* Hogyan tud "B" HTTP(S) kérést indítani "A" felé? Pl cURL-el: http://php.net/manual/en/book.curl.php
* Hogyan legyenek becsomagolva az adatok? Szerintem a JSON egy jó formátum lehet erre, de lehet hogy ez is ágyúval verébre (sima urlencodeolt key=value párok is lehetnek tömbök).

Ha részletezed hogy mivel akadtál el, akkor biztosan gyorsan tud itt valaki segíteni.

Csak egy kiegészítés a fentiekhez: ha nincs olyan a fentiekben nem ismertetett részlet, ami miatt mindenképp a B helyen kell lennie az új kódnak (A szerverhez is hozzáférsz, módosíthatod), akkor én javaslom B hely(ek)en csak készüljön el egy fájl, amit viszont A szerver ránt be időnként. Még cURL se kell, file_get_contents kezeli a http-t megbízhatóan, időzíthető a forgalom, nincs adhoc terhelés (gondolom most még ez nem probléma, de egész hamar eljöhet ez a pont is), és akkor A szerveren adminisztráljátok a betöltendő fájlok helyeit "odakint". Az A szerver így maradhat a világ felé zárt és bunkó, szóba se kell álljon senkivel, nem fogad semmit, csak néha ő kér.

(Kieg.: A fentiekben írt cURL-nél rugalmasabb megoldás a file letöltés, ez is segíthet a későbbiekben, ha épp faragás alatt van a project és képlékeny az adat formája.)

Ez is egy járható út lehet (bizonyos helyeken), de sajnos B hely az csak és kizárólag kliens oldalként tud működni.

C helyen pl. konkrétan _A_ szerver SQLjébe tudok kompletten bedolgozni C oldalról. Bár ugye _A_ szerver itt sem tud hozzáférni semmihez (mmint C oldalán). Ami jól is van így.

Nincs lehetősége az A szervernek semmi féle módon hozzáférni B bármilyen erőforrásához. (tűzfal, szabályzat, stb. miatt)

Google a barátod:

PHP scripts that can access remote files are potentially vulnerable to arbitrary code injection. When the allow_url_fopen directive is enabled, you can write scripts that open remote files as if they are local files. For example, you can use the file_get_contents function to retrieve the contents of a web page.

Maga a direktíva még nem egy sebezhetőség önmagában, viszont alapvetően fájlműveletekre való funkciók működését bővíti ki azáltal, hogy csinál egy http/https stream wrappert.
Egy nem elég körültekintő fejlesztő, aki valamilyen user input alapján dönti el, hogy milyen fájlt olvasson fel a fájlrendszerről (pl template fájlok, valamilyen adatfájl, stb) könnyedén okozhat valós sebezhetőséget. Ha pl egy serialize() függvény kap meg egy ismeretlen külső forrást, az távoli kódfuttatást is lehetővé tesz.

Én személy szerint minden olyan wrapper megoldást, aminek az egyetlen célja a lusta fejlesztők kiszolgálása messziről kerülök. Itt is volt nem rég hír a PHPMailer sebezhetőségéről, ami valójában a PHP mail() függvényének köszönhető és magában hordozza a távoli kódfuttatás potenciális veszélyét (a szabadon paraméterezhető sendmail miatt).

Ok, de itt már inkább az adja a problémát, hogy a user input alapján történik közvetlenül az olvasás. A payload post-olt adatban is lehet káros célú, és az sem elképzelhetetlen, hogy valaki tudja mit és hova küldjön, maradva a példádnál az a programozó aki elköveti a user input nem biztonságos kezelését, lehetővé teheti azt is, hogy post-ban bekapott adat legyen nem megfelelően kezelve.

Persze, nem kérdés hogy a hibás validáció okozza a problémát. Viszont nekem azzal van a bajom, hogy alapesetben a validáció lokális fájlra kellene vonatkozzon, míg a különböző stream wrapperek megléte mellett ezt a validációt adott esetben ki kell egészíteni (ráadásul van még kismillió egyéb wrapper, plusz te is regisztrálhatsz sajátot ha olyanod van). Szerintem a fájl írási/olvasási funkciókat jobb meghagyni arra mire valók és nem hagyni ellustulni a fejlesztőket.

De megközelíthető más irányból is: az a fejlesztő aki kifejezetten egy URL-t akar így megnyitni (file_get_contents($url);) könnyen eshet abba a hibába, hogy lokális fájlt olvas fel és szolgálja ki a tartalmát - szintén validációs/tervezési hiba miatt.

Lehet hogy más lenne a véleményem, ha futásidőben lehetne ezt bekapcsolni, mert akkor tudható hogy a fejlesztőnek kifejezett célja http-n betölteni egy adott fájlt. Mondjuk belegondolva ez is vezethet biztonsági réshez, szóval lehet akkor meg azzal nem értenék egyet, passz... :)

Részben egyetértünk, szerintem látom a nézőpontodból is, de ebben a kérdésben is azt látom, hogy ugyan az a fejlesztő elkövetheti a post-ban jövő tartalmak hibás validálását, nem lesz feltétlen nem-biztonságos az allow-tól, vagy legalábbis nem jobban, mint egy egyszerű post fogadástól (kicsit egyszerűsítek persze).

Csak hogy adjak egy harmadik pontot (egy amúgy elvetett megoldáshoz, mert a kérdezőnek nem jó megoldás): nem a php app töltögeti le a fájlokat, hanem egy php hatáskörén kívül eső cronjob, wget-el. A php oldaláról hardcoded, validálás egészében ki van emelve, a megoldás viszont hasonló (nem külső fél kezdeményezi a flow-t).

Nem áll szándékomban meggyőzni senkit, biztosan vannak esetek amikor én is bátran használnám - de nem szoktam, inkább kerülöm ha lehet.

Alapvetően fejlesztő vagyok, de foglalkozunk üzemeltetéssel is. Nálunk alapértelmezetten ki van kapcsolva ez is és egy csomó más feature is - aztán ha valamihez mégis kell, akkor egyeztetünk az adott fejlesztővel, hogy áthidalható-e a megoldása valahogy. Ha nem (mert pl valami külső lib amibe nem akarunk belenyúlni), akkor arra a vhostra lehet engedélyezni - szigorú audit után.

Tobb megoldas is letezik, annak fuggvenyeben hogy mit szeretnel csinalni es mennyi adatod van. A legegyszerubb nyilvan a HTTP, de ott elegge arcon tud vagni ha sok adat jon egyszerre es nem tudod ey request ideje alatt feldolgozni. Alternativakent meg lehet nezegetni a kulonbozo queue megoldasokat, de azoknal latni kell, hogy a PHP-s AMQP megvalositasok a tragyadomb kategoriaba tartoznak, nem lehet normalisan leallitani a feldolgozast kulonbozo hackelesek nelkul.

--
Pásztor János
Sole Proprietor @ Opsbears | Development Lead @ IXOLIT | Refaktor Magazin | Refactor Zone