A következő címkéjű bejegyzések mutatása: Security. Összes bejegyzés megjelenítése
A következő címkéjű bejegyzések mutatása: Security. Összes bejegyzés megjelenítése

2016. szeptember 30., péntek

Üzenet hitelesítése Java és Go szervizek között

Java fejlesztés mellett időm egy részét Go programozással töltöm, és egy olyan feladaton volt szerencsém dolgozni, amely mindkét platformot érintette. Napjaink modern alkalmazásai kisebb szervízekre vannak bontva, és igen gyakori, hogy az egyes szervízek eltérő technológiával kerülnek implementálásra. Konkrét esetben az volt az elvárás, hogy a szervízek közti kommunikációt aláírással hitelesítsem, a küldő fél Javaban, míg a fogadó Goban írodott. Mivel nem valami egzotikus kérést kellett megvalósítani gondoltam másoknak is hasznos lehet a megoldás. Előljáróban még annyit kell tudni a rendszer architektúrájáról, hogy a Java kód indít virtuális gépeket, és az ezeken a gépeken futó Go szolgáltatáson keresztül végez beállítási műveleteket, ráadásul mindkét komponens nyílt forráskódú. Ezen két adottságból adódóan nem volt mód sem szimetrikus titkosítást használni, vagy egyéb más érzékeny adatot eljuttatni a futó virtuális gépre, sem pedig valami közös "trükköt" alkalmazni. Maradt az aszinkron kulcspárral történő aláírás, mi az RSA-t választottuk. Nem is szaporítanám a szót, ugorjunk fejest a kódba.

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

Remélem nem vagyok még nagyon elkésve egy ilyen témájú bejegyzéssel, csak most kezdődik az év, úgy gondolom belefér egy kis jövendő mondás. Nem kell megijedni, nem a kristály-gömbömből fogok olvasni, hanem a szakma neves képviselőinek jóslatait igyekszem közvetíteni. A Budapest Big Data Meetup idei első találkozója alkalmából a szervezők három embert kértek fel, hogy osszák meg gondolataikat a közösséggel, én pedig szeretném összefoglalni az ott hallottakat. Mielőtt az előadások elkezdődtek volna volt pár köz érdekű információ, melyek közül szerintem a legfontosabb, hogy megalakult a Budapest Spark Meetup. Csatlakozzatok, terjesszétek, stb.

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é
Megkerülhetetlen szereplő az Apache Spark, ha 2016-os trendekről beszélünk, Gábor sem hagyhatta figyelmen kívűl. Csapatuk, a Secure Sauce Partners is aktívan használja, dübörögő technológia, sok területen hódít, és nem méltán örvend ekkora népszerűségnek. Egy mondatban összefoglalva a Spark egy olyan keretrendszer, amivel elosztott alkalmazásokat lehet fejleszteni, és megfelelő programozással az elosztott futtatásról a Spark gondoskodik. Első pontnak is ezt emelte ki, de lássuk mi volt a többi:
  • 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
Gábor személyes kedvencére tért még ki az előadásában az Apache Zeppelinre, ami egy hiánypótló, web alapú, interaktív adat elemző eszköz. A projekt jelenleg az Apache inkubátorban fejlődik roham léptekkel. Gábor véleménye szerint az egész adat analízis eddig a programozói interfészeken keresztűl történt, történik, és ő reméli, hogy a 2016-os év az ökoszitéma köré épülő felhasználói felületek éve lesz. Ennek a területnek egyik úttörője a Zeppelin, mert:
  • 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
Végül pár pontban összeszedte mit vár a 2016-os évtől:
  • Konszolidáción mennek keresztül az eszközök, és így az egész ökoszisztéma
  • Az SQL alapú megoldások erősödni fognak
  • A már említett kiegészítő eszközök sokasodnak
  • +1-nek pedig az IoT
A következő előadást a RapidMiner képviseletében Prekopcsák Zoltán tartotta. Sajnos írásos anyag híján csak az emlékezetemre támaszkodhatok, hogy miről is beszélt pontosan.

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
Zoltán szerint is az SQL technológiák nagyobb térnyerése lesz jellemző az évre, valamint a biztonságot - mind adat, mind rendszer szinten - célzó fejlesztések lesznek a közép pontban.

Harmadikként Mátyás János adott elő a Hortonworks színeiben. A Hortonworks egy teljesen nyílt forrású Hadoop disztribúció, a HDP fejlesztésére és támogatására szakosodott szilícium-völgyi vállalat. A szokásos bemutatkozás után János összefoglalta miről is szólt a 2015-ös év big data szempontból:
  • 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
  • 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:
A 2016-os előrejelzések terén rengeteg tényezőt kell figyelembe venni, amit külön nehezít, hogy a HDP több mint 22 Apache projektet ölel körbe, ezért János inkább technológiai szempontból szedte össze az érdekesebb trendeket.

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.

Következőkben az adat trendekről beszélt az előadó, úgy mint:
  • 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
    • Spark + HBase
    • Flume + Storm + Hive + Tableau
  • Alapvető elvárások ezen a területen:
    • Könnyen felhasználható legyen és könnyen lehessen menedzselni
    • Biztonságos legyen
    • Reprodukálható legyen
Ezután az előadó a YARN fontosságát emelte ki, a YARN.next már a hagyományos konténerek mellett Docker konténerek használatát is támogatja, és ezzel lehetővé vált, hogy ne csak Hadoop komponensek futását kezelje a YARN, hanem bármilyen más konténerizált alkalmazásét. Ilyen alkalmazások lehetnek a Tomcat, MySQL, vagy akár saját alkalmazásaink. Ez egy nagyon fontos lépés volt, hiszen ezzel az újítással fürtjeinket nem csak Hadoop műveletekre tudjuk használni, hanem gyakorlatilag a YARN-on keresztűl teljes erőforrás menedzsmentet kapunk.

A YARN után a Spark került elő, "Miért szeretjük a Sparkot a Hortonworksnél" címmel. Nekem talán a legfontosabb üzenet az volt ezzel a témával kapcsolatban, hogy ha már a Spark "YARN ready", és az alkalmazásunk egyébként is kapcsolódik más (Hadoop) szolgáltatásokkal, akkor nyugodtan bízzuk a YARN-ra a Spark erőforrások kiosztását is, mert meghálálja magát a dolog. De mi is jellemzi a Sparkot:
  • 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
A 2016-os évben nagy erőkkel fog zajlani a Spark mélyebb integrációja a Hadoop ökoszisztémával, számtalan fejlesztésre kitért az előadó (a teljesség igénye nélkül):
  • 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
Utolsó témakörként a biztonság került még szóba. Erről a témáról nem lehet eleget beszélni, és rengeteg fronton helyt kell állni. Négy főbb projektet emelt ki az előadó, melyek együttes használatával fel lehet adni a leckét a támadónak, és az adatok belső védelme is megoldható.

Az Apache Ranger egy központosított biztonsági keretrendszer, ami az alábbiakról gondoskodik:
  • Authorizáció
  • Authentikálás
  • Audit
  • Adat titkosítás
  • Biztonsági beállítások kezelése
Az Apache Knox a HTTP és REST interfészeket hivatott megvédeni. Egy Hadoop fürt védelmében kulcs szerepet játszik, hogy a tűzfalon minden befelé irányuló porton tiltani kell az adat forgalmat, elzárva a rendszert a külvilágtól. Amennyiben felhasználóink mégis szeretnének a rendszerhez hozzáférni, a Knox egy biztonságos átjárót biztosít külső hálózatok felé.
  • 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
Szóba került az előadásban az Apache Atlas projekt is, ami egy integrációs keretrendszer, és nagy vállalati rendszereket segít Hadoop-pal összekötni, valamint az Apache Metron, amely jelenleg még inkubátor projekt, és biztonsági analízist végez, ami alapján értesítéseket tud küldeni.

Az előadása végén János pár szóban beszélt a Hortonworks szárnyai alatt Magyar országon fejlesztett HaaS megoldásról a Cloudbreakről. A támogatott felhő platformok között nem kisebb nevek szerepelnek mint az Amazon AWS, Google GCE, Microsoft Azure, vagy az OpenStack. A Cloudbreak lényegében minimális felhasználói interakcióval gondoskodik az infrastruktúra beüzemelésétől, az Apache Ambari fürt beállításán át, a teljes Hadoop környezet felépítéséig mindenről.

Az előadások végeztével megkezdődött a kötetlen beszélgetés, pizza sör ilyenek :). Sokan részt vettek a meetupon, és jó volt látni, hogy ennyi embert foglalkoztatnak az idei trendek. Ha idáig eljutottál, valószínűleg te is közéjük tartozol, ne habozz megosztani a véleményed!

2012. december 30., vasárnap

Reflection - a bajkeverő csodagyerek

Albert Hoffmann szavai csengnek a fülemben, amikor a Reflection-re gondolok: "bajkeverő csodagyerek". Egyfelől milyen hasznos, hogy futásidőben példányosítani lehet osztályokat, hogy feltérképezhetjük őket, hogy módisíthatjuk őket, stb. Aki dolgozott már modern webes keretrendszerrel az tisztában van a Reflection minden előnyével, hisz ez a legegyszerűbb módja feltölteni egy objektumot a kéréssel érkező paramétereknek, vagy egy proxy segítségével megváltoztatni egy adattag viselkedését. Ilyen értelemben elképzelhetetlen lenne a (mai értelemben vett) Java EE terjedése, mert Reflection nélkül még mindig a kőkörban élnénk.
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.
Ha van még ötletetek, milyen módszerekkel védhetjük még a hátsónkat, kérlek ne tartsátok vissza magatokat, és írjátok meg, nekem hirtelen ennyi jutott eszembe. A bejegyzésben taglalt téma nem újkeletű, de azt hiszem sosem lehet róla eleget beszélni.

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.