2016. szeptember 30., péntek
Üzenet hitelesítése Java és Go szervizek között
Kezdjük a fogadó féllel. A Go nyelv dokumentációját olvasva hamar ráakadhatunk, hogy létezik beépített crypto/rsa csomag. Nem bővelkedik a lehetőségekben, ugyanis csak PKCS#1-et támogat. Remélem nem spoiler, de a Go lesz a szűk keresztmetszet választható sztenderdek közül. Létezik persze külső csomag pl. PKCS#8 támogatással, de mi a biztonsági kockázatát kisebbnek ítéltük a beépített bár gyengébb eljárásnak, mint a külső kevesek által auditált megoldásnak. A crypto/rsa csomagnál maradva az egyetlen lehetőségünk, hogy PSS (Probabilistic signature scheme) aláírásokat hitelesítsünk a VerifyPSS metódussal. Szóval nincs más dolgunk mint az RSA kulcspár publikus részét eljuttatni a virtuális gépre, és már mehet is a hitelesítés.
Küldés során a kérés teljes törzsét írtuk alá, így nincs más dolgunk mint a kérésből kibányászni a törzset és ellenőrizni a hitelességét.
Valamint implementálni és regisztrálni a kérés feldolgozót.
Természetesen tesztet is írtam az aláírás ellenőrzésére.
Miután megvagyunk a hitelesítéssel jöhet az aláírás Java oldalon. Kutattam egy darabig hogyan lehet PSS aláírást Java SE-vel generálni, de mivel a projektünknek már része volt a Bouncy Castle Crypto API, így kézenfekvő volt, hogy azt használjam fel.
A Java oldali kulcspár generálással tele van az internet, azzal nem untatnák senkit.
2016. január 23., szombat
Big Data trendek 2016
Az első előadást Rátky Gábor tartotta "Climbing the slope of enlightment" címmel. Rövid bemutatkozás után felvázolta, hogy szerinte pontosan a hype ciklus melyik szakaszában jár a "big data", őszintén remélem igaza van Gábornak, mert meglátása alapján már felfelé mozgunk a völgyből, és lassan megtaláljuk helyét a világban a technológiáknak.
A figyelmet érdemlő technológiák közül elsőként az Amazon EMR 4-es verzióját említette meg, ami gyakorlatilag egy Hadoop as a Service (HaaS) szolgáltatás, ahol az infrastruktúrárol az Amazon gondoskodik, a fejlesztőnek csak a feladatok megírásával, futtatásával kell törődnie, meg persze a számla kiegyenlítésével hónap végén. Legfontosabb tulajdonságainak az alábbiakat gyűjtötte össze:
- Az EMR a legnagyobb Hadoop distribúció piaci részesedés alapján
- Nagyon jó a többi Amazon szolgáltatással az integráció, mint például EC2, S3 vagy Redshift
- Apache Bigtop-re épül
- Könnyen lehet ideiglenes (ephemeral) fürtöket létrehozni és megszüntetni
- Intelligens skálázhatóság
- Spark 1.5 támogatással rendelkezik, és gyorsan adoptálják az újabb verziókat
- Az EMR homokozóban friss technológiákat lehet kipróbálni mint az Apache Zeppelin
- Igazán azoknak ajánlott, akik egyéb Amazon szolgáltatásokat is használnak, vagy nem okoz problémát elköteleződni egy beszállító felé
- Ugyanaz a kód fut az egy gépestől a sok gépes rendszerig, "Write once, run anywhere"
- Hatalmas lendülettel fejlődik, köszönhetően a felhajtásnak is ami körülveszi
- Szaporodnak a Spark primitívekre épülő keretrendszerek, mint például DataFrame, MLLib
- Feladatoknak 80%-a az adat munging, és ezt (is) könnyíti meg a projekt
- Legjobb alkalmazás csoportban adat-halmazokon dolgozni
- Egyszerű(bb)en elvégezhető vele az adat-halmazok definiálása, a lépések és az eredmény megosztása
- REPL-ben jártas adat-elemzőknek otthonos környezet
Téma volt a Spark, aktív felhasználói a keretrendszernek, és két fontos dolgot is mondott ezzel kapcsolatban:
- Reméli a hiba javítás nagyon nagy fókuszt kap a jövőben, mert véleménye szerint ezen a területen nagyon sok munka van
- Az a tapasztalata, hogy sok vállalat, akik letették a voksukat a Spark mellett, nem félnek frissíteni a rendszert, és bátran ugranak bele egy-egy újabb verzióba
- Az Apache Spark éve volt
- Az SQL még mindig nagy dolog, miért is dobnánk ki az ablakon több évtizednyi tudást
- Apache Hive Stinger kezdeményezése
- Apache Phoenix egy HBase-re épülő relációs réteg
- Az adatok mozgatása a Hadoop fürtökbe nagy kérdés volt/lesz, és ez adott lét jogosultságot olyan alkalmazásoknak mint az:
Elsőként az adatok tárolása körüli munkákat emelte ki mint például az Erasure Coding a HDFS fájlrendszerben és az archív adatokat tároló rendszerek támogatása. Mindkettő fejlesztésnek a költség hatékonyság a fő mozgató rugója.
A HDFS az EC bevezetése előtt csak teljes blokk replikációt támogatott, ami azt jelenti, hogy a replikációs faktornak megfelelő darab számban minden adat tárolásra került. Az újításnak köszönhetően alap értelmezetten 6 adat blokkhoz 3 paritás blokk tartozik. Ennek hála tárhelyet spórol az eljárás, és megnöveli az írási sebességet, miközben a hiba tűrés ugyanúgy megmarad. Amíg az EC szoftveresen javítja a tároló kapacitás kihasználását, addig a másik fejlesztés hardveresen igyekszik a költségek minimalizálására. A hozzáférés gyakorisága szerint három csoportba rendezi az adatokat, és a ritkán használt, régi adatokat olcsóbb, de lassabb tárolókra lehet szervezni.
- A modern alkalmazásokban az adatok elemzése elsődleges funkció
- A gyakorlat azt mutatja, hogy a szolgáltatásokat és adat elemző rétegeket együttesen használják
- Alapvető elvárások ezen a területen:
- Könnyen felhasználható legyen és könnyen lehessen menedzselni
- Biztonságos legyen
- Reprodukálható legyen
- Elegáns fejlesztői API
- DataFrame-k
- Gépi tanulás
- SQL
- Data sience-eknek készült
- A alkalmazások kiszámíthatóan tudnak skálázódni, és megfelelően lehet őket tagolni
- Demokratizálja a gépi tanulást
- A Spark azt csinálja a gépi tanulással a Hadoopon belül, amit a Hive csinált az SQL-el
- Közösség
- Széles körben fejlesztik, és nagy érdeklődés övezi, nem csak a fejlesztők irányából
- Realizálja az adat operációs rendszerek értékét
- Kulcs fontosságú eszköz a Hadoop érában
- Szorosabb RDD és HDFS együtt működés
- Dinamikus végrehajtás data-locality alapján
- Atlas integráció
- Hbase konnektor
- NiFi stream-ek
- Biztonsági fejlesztések
- SparkSQL Security
- Wire Encryption
- Spark fejlesztés és vizualizáció Zeppelinben
- Authorizáció
- Authentikálás
- Audit
- Adat titkosítás
- Biztonsági beállítások kezelése
- Egyszerűsíti a hozzáférést, mert elfedi a Kerberost és nem szükséges annak telepítése a kliens gépeken
- Fokozza a biztonságot azáltal, hogy SSL csatornán kommunikál
- Központosítja a vezérlést, mivel lehet benne irányítani a kéréseket akár több Hadoop fürt felé
- Nagy vállalati integrációt biztosít LDAP és Active Directory támogatással
2012. december 30., vasárnap
Reflection - a bajkeverő csodagyerek
RequestParams rp = new RequestParams(); final Field[] fields = rp.getClass().getDeclaredFields(); for (final Field field : fields) { firstChar = String.valueOf(field.getName().charAt(0)); methodName = "set" + field.getName().replaceFirst(firstChar, firstChar.toUpperCase()); try { method = rp.getClass().getMethod(methodName, String.class); method.invoke(rp, request.getParameter(field.getName())); } catch (final SecurityException e) { } catch (final NoSuchMethodException e) { } catch (final IllegalArgumentException e) { } catch (final IllegalAccessException e) { } catch (final InvocationTargetException e) { } }A példa jól szemlélteti, hogy pofon egyszerű feltölteni a kapott paraméterekkel egy objektumot, újabb paraméterek létrehozásakor nem kell setterekkel bajlódni, ráadásul a kód teljesen hordozható, így bármely osztályra dinamikusan alkalmazható (a példa csak String-eket kezel az egyszerűség kedvéért).
Itt merül fel a kérdés, hogy a Reflection nem egy kétélű fegyver? Mivel mondhatni teljes hozzáférést biztosít objektumjaink belső működéséhez és felépítéséhez, nem lehet ezt rosszra is használni? A válasz egyértelmű IGEN! Daily WTF-en találtam ezt a kedves kis szösszenetet:
class ValueMunger extends Thread { public void run() { while(true) { munge(); try { sleep(1000); } catch (Throwable t) { } } } public void munge() { try { Field field = Integer.class.getDeclaredField( "value" ); field.setAccessible( true ); for(int i = -127; i <= 128; i++) field.setInt( Integer.valueOf(i), // either the same (90%), +1 (10%), or 42 (1%) Math.random() < 0.9 ? i : Math.random() < 0.1 ? 42 : i+1 ); } catch (Throwable t) { ; } } }A fenti kódrészlet az Integer wrapper cachet-t zagyválja egy kicsit össze, időnként nem a valós értéket kapjuk vissza, hanem az élet értelmét, ami üzleti kritikus alkalmazásokban igen nagy probléma, nem szeretnénk egy pészmékerben ilyesmi kóddal találkozni, de azt sem szeretnénk, ha a banki alkalmazás viccelné meg a bankszámlánkat időnként. A final mezőink, a private tagjaink sincsenek biztonságban, ahogy az Enum-jaink sem, és ezen a ponton a végtelenségi lehetne sorolni az ártalmas és vicces példákat, ugyanis kijelenthető, hogy (Sun/Oracle) Java verziótól függően szinte mindenhez hozzá lehet férni Reflection API segítségével, nincs menekvés.
Ártalmas kódot hagyhat hátra kilépő munkatárs, tölthetünk le ártatlanul egy külső osztálykönyvtárral, szóval több forrásból is beszerezhetőek, de vajon mit lehet tenni ellenük? Az egyetlen gyógyszer a tudatos és körültekintő felhasználás.
- Használjunk statikus kódelemzőt, és szigorúan tartsuk számon azokat a részeket, ahol az alkalmazásunk Reflection API-t használ.
- Használjunk nyílt forrású könyvtárakat, és fordítsuk magunk (kódelemzés után).
- A letöltött osztálykönyvtárak hitelességét minden lehetséges módon ellenőrizzük, ugyanis koránt sem biztos, hogy senki nem törte fel kedvenc keretrendszerünk weboldalát, és cserélte ott le a letölthető jar-okat saját módosított verziójára (jó lenne a Linux repository-khoz hasonló központosított megoldás).
- Csak a készítő által aláírt osztályokat, és jar-okat használjunk, ha külső forrásra kell támaszkodnunk.
- Minimalizáljuk a külső forrásokat, ne használjunk két külön osztálykönyvtárat közel ugyanarra a feladatra.
2011. október 30., vasárnap
OWASP AntiSamy Javaban
A webes biztonság kérdése egyidős magával az internettel, hiszen a hálózaton elérhető adatokat felhasználók milliói tekintik meg napról-napra. Mivel a weboldalak végeredményben a kliensek gépein futnak, hamar beláthatjuk, hogy a biztonsági kérdések nem elhanyagolhatóak, és mind a klienseknek, mind a weboldalak üzemeltetőinek fontos, hogy a kiszolgált tartalom hiteles és biztonságos legyen. Tipikus támadási forma az un. XSS, amikor pl. egy az oldalba ágyazott külső Javascript próbál szenzitív információkhoz hozzájutni a böngésző valamely biztonsági hibáját kihasználva. Az ilyen és ehhez hasonló problémák megoldására jött létre 2001-ben OWASP Antisamy Project, melynek célja nyílt forrású alternatívát, és szabványt kínálni az alkalmazások megvédésére.
Mint minden 3rd party fejlesztés, ez is úgy kezdődik, hogy letöltjük a programkönyvtár lehetőleg legfrissebb verzióját. AntiSamy jelenleg az 1.4.4-es verziónál tart. A dokumentációval ellentétbe a csomag függőségeit nem lehet letölteni, rákeresve a antisamy-required-libs.zip kulcsszavakra találtam egy oldalt. A készítők szerint deprecated ami a zip-be van, de a próba erejéig megteszi, éles használatra össze kell vadászni a függőségeket. A szoftver konfigurációja eléggé bonyolult, hosszas dokumentáció olvasással és tanulással egész biztos össze lehet dobni egy normális konfig XML-t, de szerencsére több nagyobb felhasználó is rendelkezésre bocsátotta saját összeállítását, így nyugodtan mazsolázgathatunk az eBay, MySpace, vagy akár Slashdot beállításaiból.
Az általam készített tesztprogram az alábbi (belecsempészve kis Java 7-et):
import java.io.IOException; import java.net.URL; import java.nio.charset.Charset; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import org.owasp.validator.html.*; public class AntiSamyTest { public static void main(String[] args) { try { URL dirtyHtmlUrl = AntiSamyTest.class.getResource("dirtyHtml.html"); Path dirtyHtmlPath = FileSystems.getDefault().getPath(dirtyHtmlUrl.getFile()); List<String> lines = Files.readAllLines(dirtyHtmlPath, Charset.defaultCharset()); URL configXmlUrl = AntiSamyTest.class.getResource("antisamy-ebay-1.4.4.xml"); Policy policy = Policy.getInstance(configXmlUrl.getFile()); AntiSamy as = new AntiSamy(); CleanResults cleanResult = as.scan(concatString(lines), policy); System.out.println(cleanResult.getCleanHTML()); } catch (IOException | PolicyException | ScanException ex) { throw new RuntimeException(ex); } } private static String concatString(List<String> input) { StringBuilder output = new StringBuilder(); for(String line : input) output.append(line); return output.toString(); } }A dirtyHtml.html fájl tartalma szabvány HTML (HTML, HEAD, BODY). A programot futtatva láthatjuk, hogy a body tartalmán kívül minden HTML taget kidobott az AntiSamy. Azért mondom, hogy minden HTML taget, mert ha van pl. title a headbe, a tartalma bizony ottmarad, tehát csak a sallang kerül ki. Szerintem ez utóbbi működés konfigurálható (fixme).
Az elméleti ismerkedés után ideje valami komolyabb megbizatást adni Samykének. Személy szerint Liferay fejlesztő vagyok, így szinte evidens, hogy erre esett a választásom. A Liferay 6-os verziója óta létezik egy Sanitizers-nek nevezett funkcionalitás, amely, bár még nem teljeskörű, mégis segít az igényes programozónak, a kritikus user inputokat szűrni. A funkcionalitás mint írtam nem teljeskörű, ugyanis egyelőre csak a Blog bejegyzéseket tudjuk kontrollálni out-of-the-box. A dolgunk egyszerű, a portal.properties-ben van egy sanitizer.impl paraméter, amit a portal-ext.properties-ben felül tudunk definiálni. Az alapbeállítás a com.liferay.portal.sanitizer.DummySanitizerImpl osztályra mutat, ami jóformán semmit nem csinál, viszont jó kiindulási pont lehet saját Saniterünk elkészítéséhez. Létezik a Liferaynek beépített osztálya com.liferay.portal.kernel.sanitizer.SanitizerUtil képében, választhatjuk ezt is, de saját megoldást is minden további nélkül.
Miután Blog bejegyzéseinket megvédtük a sokszor óvatlan bloggerektől, sajnos nem dőlhetünk hátra nyugodtan, mivel a Liferayben is, mint minden CMS-ben, nem csak Blogot szerkesztenek a felhasználók, hanem számtalan egyéb módon is lehetőségük van HTML szöveget a rendszerbe juttatni. Mivel "gyári" támogatás még nincs ezen bejegyzésekre, nincs más lehetőségünk, mint hook-ot írni. A Plugin tárolóban van egy "antisamy hook", amely alapján könnyedén megírhatjuk saját kiterjesztésünket. A legjobb módszer un. Model Wrapper Hook készítése. Hozzunk létre egy hook-ot, majd a liferay-hook.xml fájlba írjuk be a felülírandó szervíz definícióját
<hook> <service> <service-type>com.liferay.portlet.wiki.service.WikiPageLocalService</service-type> <service-impl>com.test.hooks.SaniterWikiPageLocalService</service-impl> </service> </hook>Majd írjuk meg saját osztályjunkat
import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.exception.SystemException; import com.liferay.portal.kernel.sanitizer.SanitizerUtil; import com.liferay.portal.kernel.util.ContentTypes; import com.liferay.portal.service.ServiceContext; import com.liferay.portlet.wiki.model.WikiPage; import com.liferay.portlet.wiki.service.WikiPageLocalService; import com.liferay.portlet.wiki.service.WikiPageLocalServiceWrapper; public class SaniterWikiPageLocalService extends WikiPageLocalServiceWrapper { public SaniterWikiPageLocalService(WikiPageLocalService wikiPageLocalService) { super(wikiPageLocalService); } public WikiPage addPage( long userId, long nodeId, String title, double version, String content, String summary, boolean minorEdit, String format, boolean head, String parentTitle, String redirectTitle, ServiceContext serviceContext) throws PortalException, SystemException { String sanitizedContent = SanitizerUtil.sanitize( serviceContext.getCompanyId(), serviceContext.getScopeGroupId(), userId, WikiPage.class.getName(), 0, ContentTypes.TEXT_HTML, content); return super.addPage(userId, nodeId, title, version, sanitizedContent, summary, minorEdit, format, head, parentTitle, redirectTitle, serviceContext); } }Bár én a Wiki-t választottam példának, ez alapján bármely más szervízre megírható a szűrés.