Dokumentáció - wolfi95/szgbizt2020-asdfgh GitHub Wiki
Számítógép biztonság házi feladat dokumentáció
A feladat egy olyan online áruházat elkészítése volt, amiben egyedi formátumú animált képeket lehet vásárolni. A szoftverrel szemben elvárás, hogy a CAFF (CrySyS Animated File Format) formátumot kell támogatnia. További elvárás, hogy a teljes rendszer tartalmazzon HTTP(S) protokollon elérhető távoli szolgáltatást, valamint az ahhoz tartozó webes klienst. A rendszerrel szemben támasztott követelmény, hogy a felhasználók belépés után képesek legyenek CAFF fájlt feltölteni, letölteni, a fájlok között keresni, illetve a fájlokhoz megjegyzést hozzáfűzni. A rendszerben kell hogy legyen adminisztrátor felhasználó, aki a felhasználók adatait láthatja, illetve az összes fájl adatait módosíthatja, törölheti. Az alábbi dokumentuba az elkészült rednzser leírása kerül, a biztonsághoz kapcsolódó funkciókra és kérdésekre fókuszálva.
Architektúra
A rendszer négy fő részből áll: A felhasználói webes felület REST Api-n kommunikál a szerverrel, mely egy SQL adatbázisban tárolja a szükséges adatokat, a szerver pedig egy DLL formájában használja a c++ nyelven íródott parsert.
Backend
A szerver .NET Core nyelven íródott, mely egy REST APIt ajánl ki és SQL adatbázisban tárolja a kívánt adatokat, illetve a fájlrendszeren a CAFF és CIFF fájlokat. A kliens és a szerver közötti kommunikáció biztonságos lebonyolítását a szerver HTTPS konfigurációja biztosítja. A gyakori támadások elleni védelem érdekében a Security Code Scan eszközt használtuk, mely segít kiszűrni az Injection, XSS, Kriptográfiai, stb. kódolási problémákat statikus kódelemzéssel. A következő támadások ellen gondoltuk végig külön a védekezés módjait:
- Man in the middle / information disclosure: HTTPS használatával és modern REST API technológiák alkalmazásával a problém,a elkerülhető.
- DOS/DDOS: Léteznek ugyan az alkalmazás kódjában implementálható technológiák melyekkel korlátozhatóak az api felé tett kérések, ám a mai web szerver alkalmazások már sokkal jobban kezelik az ilyne jellegű támadások elleni védekezést, mint amit kézzel készíteni tudnánk.
- Cross Site Scripting: A .NEt core keretrendszer beépített megoldást nyújt erre a problémára, konfigurálható azoknak a weboldalaknak a listája, melyektől a szerver fogad kéréseket.
- SQL Injection: A Linq keretrendszer automatikus védelmet ad a parancsbeszúrásos támadások ellen.
- Path traversal: A biztonsági tesztelés során ez volt az egyetlen támadási mód melyre nem gondoltunk a fejlesztés előtt és az SCS tool híta fel rá a figyelmünket. A fájl elérés esetén a fájlműveleteket csak úgy szabad végezni, ha a felhasználó által szolgáltatott (pl.) fájlnév validálva lett. Szerencsére erre a problémára is létezik beépített validáló függvény.
- Hamisítás/Megszemélyesítés: Bejelentkezés során JWT tokent használunk, melybe bele vannak téve a felhasználó adatai. Mivel a CPP modult DLL-ként használja a program, a memóriaterület egyezik a két program futásánál, így nem kell tartani hibás memória terület eléréstől.
CPP komponens
A külső komponens leírása itt található
Frontend
A kliens oldal Angular keretrendszerben lett megvalósítva, mely egy TypeScript alapú nyílt forráskódú keretrendszer, melyet a Google fejlesztett ki, illetve hosszútávú támogatottságát élvezi a cégnek. Egy Angular projekt komponensekből épül fel, a komponens logikája a TypeScript fájlban kerül megírásra, melyhez tartozik egy HTML template, illetve CSS stílusleíró fájl. A projektbe npm segítségével lehet behúzni a külső függőségeket. Az Angular keretrendszer beépített funkciókat kínál a biztonságos fejlesztéshez. Ezenfelül a következő lépéseket tettük meg a támadások elkerülése érdekében:
- XSS elkerülése: Az Angular keretrendszer beépített támogatást nyújt ennek elkerülése érdekében: {{}} string interpolációt használunk a sablonokban, mely segít a potenciálisan veszélyes karakterek biztonságos kódolásában és a megbízhatatlan HTML, CSS kifejezéseket megakadályozza. A keretrendszer alapértelmezetten az összes adatot megbízhatatlannak tekinti, így az összes könyvtár úgy van megírva, hogy ezt a bevált gyakorlatot követi.
- [innerHTML] tag használata: Amikor dinamikusan adunk hozzá HTML tartalmat egy komponenshez, akkor annak generálásánál az [innerHTML] jelzőt használjuk. Ez biztosítja, hogy a rendszer az adatokat HTML-ként értelmezi, és megtisztítja, eltávolítja a nem biztonságos tageket, így megakadályozva, hogy bármilyen rosszindulatú script beleavatkozzon a helyes működésbe.
- Nem használunk olyan templatet, aminek kódja felhasználótól érkező inputtal való konkatanációból generálódik.
- Nem használunk natív DOM API-kat ahhoz, hogy interakcióba lépjünk az oldal HTML elemeivel. Ehelyett van az Angular template mechanizmusa, illetve az Angular nyújt ehhez saját API-kat.
- Mivel az Angular projektekbe egyszerűen beimportálhatunk open-source komponenseket, így ezek használatára különösen kell figyelni, hogy megbízható forrásból származzanak. Ilyen a projektben a file-saver.js külső könyvtár.
- A frontend projektre npm audit fix lett futtatva, mely megvizsgálja az alkalmazás függőségei okozta biztonsági réseket, illetve automatikusan telepíti a kompatibilis frissítéseket a sérülékeny függőségekre.
- Hamisítás/Megszemélyesítés elkerülése: A bejelentkezéshez JWT tokent használunk. Mivel ebben felhasználói adatok vannak, így nagyon meg kell gondolni, hogy hol tároljuk el a tokeneket, hiszen kiemelt fontosságú védni őket a CSRF és XSRF támadások ellen. Olyan helyen kell tárolni a tokeneket, ahol a támadók nem tudják elérni. Két lehetséges megoldás van ezek biztonságos tárolására:
- Local storage: Nem sebezhető CSRF támadásokkal. Esetünkben local storageban van tárolva a token.
- HTTPOnlyCookie: Ezek nem elérhetők a kliens oldalról, a kliens nem tudja elolvasni tartalmát
Tesztelés
A alkalmazás frontend részének unit teszteléséhez Jasmin test keretrendszert, a tesztek futtatásához pedig a Karma tesztfuttató került felhasználásra. Ezekkel dolgozni kifejezetten egyszerű, mivel a legenerált applikáció ezeket a függőségeket már alapból tartalmazta.
-
Jasmine
A Jasmine egy viselkedés-vezérelt (BDD) keretrendszer JavaScript kód teszteléséhez. A tesztek előnye, hogy kifejezetten olvashatóak és értelmezhetőek is a fejlesztők és laikusok számára egyaránt. -
Karma A Karma egy automatizált tesztfuttató , mely nagyban megkönnyiti a fejlesztők számára a tesztfuttatást azáltal, hogy nem szükséges segitségével a tesztek manuális egyenkénti elinditása. Egy böngészőablak megnyitása segitségével abban hajtja végre az egyes tesztekben leirtakat.
Példa teszt
describe('CafffileCreateComponent', () => {
let component: CafffileCreateComponent;
let fixture: ComponentFixture<CafffileCreateComponent>;
const caffFileServiceMock = {
uploadCaffFile: () => of,
};
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [CafffileCreateComponent],
imports: [ReactiveFormsModule],
providers: [
{
provide: CafffileService,
useValue: caffFileServiceMock,
},
],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(CafffileCreateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should call upload function with valid form', () => {
spyOn(caffFileServiceMock, 'uploadCaffFile').and.callThrough();
component.uploadForm.setValue({
name: 'caff image name',
file: '',
});
let input = fixture.nativeElement.querySelector('input[type=file]');
const dataTransfer = new DataTransfer();
dataTransfer.items.add(new File(['content'], 'caffFile'));
input.files = dataTransfer.files;
input.dispatchEvent(new Event('change'));
input.dispatchEvent(new Event('input'));
fixture.nativeElement.querySelector('button').click();
expect(caffFileServiceMock.uploadCaffFile).toHaveBeenCalled();
});
Egy teszt felépitesét a fenti kódrészlet szemlélteti.
- a
describe
-bal irjuk le az egyes Test Suite-okoat, ebben az esetben a CAFF file feltöltéséhez tartozó test suite látható beforeEach
ezek a függvények minden test case előtt lefutnak, hogy a tesztesetek ne befolyásolhassák egymást, a függvényben létrehozott objektumok módositása által- ay
it
az egyes Test Spec-eket irja le ezek a tesztesetek, test case-k, ezek tartalmaznak egy vagy több elvárást a teszt kimenetelével szemben expect(something)
részben az előbb emlitett elvárás látható. Ebben a példában az, hogy ay adott függvény, mely a CAFF file-ok feltöltéséért fellelős meghivódjon, hisz minden adott hozzá.caffFileServiceMock
, a tesztelt komponens mint általában minden komponens függőségben áll más komponensekkel, de hogy ezeket elszigeteljük egzmástól, és egyszerre csak egynek a tesztelésével tudjunk foglalkozni egy mock-t készitünk a szükséges egyéb komponensekből, és a megvalóstjuk azok azon metódusait melyre a tesztjeinkhez szükség van, jelen esetben ez aCaffFileService
, melyuplodaCaffFile
függvénye a lehető legegyszerűbb módon megvalósitásra is került.
A fenti teszt suite tehát egyetlen test case-e a file-k feltöltésének működését teszteli, ad neki egy nevet illetve feltölt egy itt létrehozott file-e, ezzel jelképezve a feltölthető CAFF filet-t, majd rákattint a from egyetlen, feltöltés gombjára és ellenőrzi, hogy az elvártnak megfelelő esemény történt-e, meghivásra került-e az upload függvény. Ha minden rendben volt a teszt lefutása sikeres.
Az alkalmazás további tesztjei is ezem a sémán alapulnak.