CodeGym/Java blog/Véletlen/Biztonság a Java-ban: legjobb gyakorlatok
John Squirrels
Szint
San Francisco

Biztonság a Java-ban: legjobb gyakorlatok

Megjelent a csoportban
A szerveralkalmazások egyik legfontosabb mérőszáma a biztonság. Ez egyfajta nem funkcionális követelmény . Biztonság a Java-ban: legjobb gyakorlatok - 1A biztonság számos összetevőt tartalmaz. Természetesen több cikkre lenne szükség ahhoz, hogy az összes ismert biztonsági alapelvet és biztonsági intézkedést teljes mértékben lefedjük, ezért a legfontosabbakon fogunk kitérni. Az ebben a témában jártas személy beállíthatja az összes releváns folyamatot, elkerülheti az új biztonsági rések létrehozását, és minden csapatban szükség lesz rá. Természetesen nem szabad azt gondolnia, hogy jelentkezése 100%-ban biztonságos lesz, ha követi ezeket a gyakorlatokat. Nem! De biztosan biztonságosabb lesz velük. Gyerünk.

1. Biztosítson biztonságot a Java nyelv szintjén

Először is, a Java biztonsága a nyelv képességeinek szintjén kezdődik. Mit tennénk, ha nem lennének hozzáférés-módosítók? Nem lenne más, csak anarchia. A programozási nyelv segít nekünk biztonságos kódot írni, és számos implicit biztonsági funkciót is felhasznál:
  1. Erős gépelés. A Java egy statikusan tipizált nyelv. Ez lehetővé teszi a típushoz kapcsolódó hibák futás közbeni elkapását.
  2. Hozzáférés módosítók. Ezek lehetővé teszik számunkra, hogy szükség szerint testreszabjuk az osztályokhoz, metódusokhoz és mezőkhöz való hozzáférést.
  3. Automatikus memóriakezelés. Ehhez a Java fejlesztőknek van egy szemétgyűjtőjük, amely megszabadít attól, hogy mindent kézzel kelljen beállítani. Igen, néha felmerülnek problémák.
  4. Bájtkód-ellenőrzés : A Java bájtkódba van fordítva, amelyet a futási környezet a végrehajtás előtt ellenőriz.
Ezen kívül vannak az Oracle biztonsági ajánlásai is . Természetesen nem magasztos nyelvezeten íródott, és előfordulhat, hogy az ember többször elalszik olvasás közben, de megéri. Különösen fontos a Secure Coding Guidelines for Java SE című dokumentum. Tanácsot ad a biztonságos kód írásához. Ez a dokumentum hatalmas mennyiségű rendkívül hasznos információt közöl. Ha van rá lehetőség, feltétlenül olvassa el. Íme néhány érdekes tipp, hogy felkeltse érdeklődését ez az anyag:
  1. Kerülje a biztonsági szempontból érzékeny osztályok sorba rendezését. A szerializálás felfedi az osztályinterfészt a sorosított fájlban, nem is beszélve a sorosított adatokról.
  2. Próbálja meg elkerülni a változó adatosztályokat. Ez biztosítja a változtathatatlan osztályok összes előnyét (pl. menetbiztonság). Ha van változtatható objektuma, az váratlan viselkedéshez vezethet.
  3. Készítsen másolatot a visszaadott, változtatható objektumokról. Ha egy metódus hivatkozást ad vissza egy belső, változtatható objektumra, akkor az ügyfélkód megváltoztathatja az objektum belső állapotát.
  4. Stb…
Alapvetően a Secure Coding Guidelines for Java SE tippek és trükkök gyűjteménye a Java kód helyes és biztonságos megírásához.

2. Szüntesse meg az SQL injekciós sebezhetőségeit

Ez a sebezhetőség egy speciális fajtája. Különleges, mert egyszerre az egyik leghíresebb és az egyik leggyakoribb sebezhetőség. Ha soha nem érdekelt a számítógépes biztonság, akkor nem fog tudni róla. Mi az SQL injekció? Ez egy adatbázis-támadás, amely további SQL-kód beszúrásával jár ott, ahol ez nem várható. Tegyük fel, hogy van egy metódusunk, amely elfogad valamilyen paramétert az adatbázis lekérdezéséhez. Például egy felhasználónév. A sebezhető kód így nézne ki:
// This method retrieves from the database all users with a certain name
public List findByFirstName(String firstName) throws SQLException {
   // Connect to the database
   Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);

   // Compose a SQL database query with our firstName
   String query = "SELECT * FROM USERS WHERE firstName = " + firstName;

   // Execute the query
   Statement statement = connection.createStatement();
   ResultSet result = statement.executeQuery(query);

   // Use mapToUsers to convert the ResultSet into a collection of users.
   return mapToUsers(result);
}

private List mapToUsers(ResultSet resultSet) {
   // Converts to a collection of users
}
Ebben a példában egy SQL-lekérdezés előzetesen egy külön sorban van előkészítve. Szóval mi a probléma, igaz? Lehet, hogy az a probléma, hogy jobb lenne a String.format használata ? Nem? Nos, akkor mi van? Helyezzük magunkat egy tesztelő helyébe, és gondoljuk át, mi adható át a keresztnév értékeként . Például:
  1. Átadhatjuk, amit várunk – egy felhasználónevet. Ezután az adatbázis minden felhasználót visszaad ezzel a névvel.
  2. Átadhatunk egy üres karakterláncot. Ezután minden felhasználó visszakerül.
  3. De a következőket is átadhatjuk: "'; DROP TABLE USERS;". És itt most nagy gondjaink vannak. Ez a lekérdezés töröl egy táblát az adatbázisból. Minden adattal együtt. AZ EGÉSZET.
El tudja képzelni, milyen problémákat okozhat ez? Ezen kívül azt írhatsz, amit akarsz. Megváltoztathatja az összes felhasználó nevét. Törölheti a címüket. A szabotázs lehetőségei óriásiak. Ennek elkerülése érdekében meg kell akadályoznia egy kész lekérdezés befecskendezését, és ehelyett paraméterekkel kell kialakítani a lekérdezést. Ez az egyetlen módja az adatbázis-lekérdezések létrehozásának. Így szüntetheti meg ezt a sebezhetőséget. Például:
// This method retrieves from the database all users with a certain name
public List findByFirstName(String firstName) throws SQLException {
   // Connect to the database
   Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);

   // Create a parameterized query.
   String query = "SELECT * FROM USERS WHERE firstName = ?";

   // Create a prepared statement with the parameterized query
   PreparedStatement statement = connection.prepareStatement(query);

   // Pass the parameter's value
   statement.setString(1, firstName);

   // Execute the query
   ResultSet result = statement.executeQuery(query);

   // Use mapToUsers to convert the ResultSet into a collection of users.
   return mapToUsers(result);
}

private List mapToUsers(ResultSet resultSet) {
   // Converts to a collection of users
}
Így elkerülhető a sebezhetőség. Azok számára, akik szeretnének mélyebbre merülni ebben a cikkben, íme egy nagyszerű példa . Honnan tudod, hogy megérted-e ezt a sebezhetőséget? Ha megérted a viccet az alábbi képregényben, akkor valószínűleg tisztában vagy azzal, hogy miről is szól ez a sebezhetőség :DBiztonság a Java-ban: legjobb gyakorlatok - 2

3. Vizsgálja meg és tartsa naprakészen a függőségeket

Az mit jelent? Ha nem tudja, mi az a függőség, elmagyarázom. A függőség egy olyan kóddal rendelkező JAR archívum, amely egy projekthez kapcsolódik automatikus összeállítási rendszerekkel (Maven, Gradle, Ant), hogy újra felhasználhassa valaki más megoldását. Például a Project Lombok , ami futás közben generál nekünk gettereket, settereket stb. A nagy alkalmazásoknak sok-sok függősége lehet. Némelyik tranzitív (vagyis minden függőségnek megvannak a maga függőségei stb.). Ennek eredményeként a támadók egyre jobban odafigyelnek a nyílt forráskódú függőségekre, mivel ezeket rendszeresen használják, és sok kliensnek lehetnek problémái miattuk. Fontos megbizonyosodni arról, hogy nincs ismert sebezhetőség a teljes függőségi fában (igen, úgy néz ki, mint egy fa). Ennek többféle módja van.

Használja a Snyk-et a függőségfigyeléshez

A Snyk ellenőrzi az összes projektfüggőséget, és megjelöli az ismert sebezhetőségeket. Regisztrálhat a Snyken, és importálhatja projektjeit a GitHubon keresztül. Biztonság a Java-ban: legjobb gyakorlatok - 3Továbbá, amint a fenti képen látható, ha egy sérülékenységet egy újabb verzióban javítanak, akkor a Snyk felajánlja a javítást, és lekérést hoz létre. Ingyenesen használhatja nyílt forráskódú projektekhez. A projekteket rendszeres időközönként, például hetente, havonta egyszer szkenneljük. Regisztráltam és hozzáadtam az összes nyilvános tárolómat a Snyk vizsgálathoz (ebben nincs semmi veszélyes, hiszen már mindenki számára nyilvánosak). A Snyk ezután megmutatta a vizsgálat eredményét: Biztonság Javaban: legjobb gyakorlatok – 4És egy idő után a Snyk-bot több lehívási kérelmet készített azokban a projektekben, ahol a függőségeket frissíteni kell: Biztonság a Java-ban: legjobb gyakorlatok - 5És még:Biztonság a Java-ban: legjobb gyakorlatok - 6Ez egy nagyszerű eszköz a sebezhetőségek felkutatására és az új verziók frissítéseinek figyelésére.

Használja a GitHub Security Labot

Bárki, aki a GitHubon dolgozik, kihasználhatja annak beépített eszközeit. Erről a megközelítésről bővebben a GitHub Security Lab bejelentése című blogbejegyzésükben olvashat . Ez az eszköz természetesen egyszerűbb, mint a Snyk, de semmiképpen sem szabad elhanyagolni. Ráadásul az ismert sebezhetőségek száma csak nőni fog, így a Snyk és a GitHub Security Lab is tovább bővül és fejlődik.

Engedélyezze a Sonatype DepShield funkciót

Ha a GitHubot használja a tárolók tárolására, hozzáadhatja projektjeihez a Sonatype DepShield alkalmazást, a MarketPlace egyik alkalmazását. Használható projektek függőségek keresésére is. Ezenkívül, ha talál valamit, egy GitHub-probléma jön létre megfelelő leírással, az alábbiak szerint:Biztonság a Java-ban: legjobb gyakorlatok - 7

4. Óvatosan kezelje a bizalmas adatokat

Alternatív megoldásként használhatjuk az „érzékeny adatok” kifejezést. Az ügyfél személyes adatainak, hitelkártyaszámainak és egyéb érzékeny adatoknak kiszivárogtatása helyrehozhatatlan károkat okozhat. Mindenekelőtt alaposan nézze meg az alkalmazás kialakítását, és döntse el, hogy valóban szüksége van-e erre vagy arra az adatra. Talán valójában nincs szüksége a birtokában lévő adatok egy részére – olyan adatokra, amelyeket egy olyan jövőre adtunk hozzá, amely még nem jött el, és nem valószínű, hogy megérkezik. Ezenkívül sokan véletlenül kiszivárogtatják ezeket az adatokat a naplózás során. Az érzékeny adatok naplóiba való bejutásának megakadályozásának egyszerű módja a tartományi entitások (például felhasználó, tanuló, tanár stb.) toString() metódusainak átvizsgálása. Ezzel elkerülheti, hogy véletlenül bizalmas mezőket adjon ki. Ha a Lombokot használja a toString() generálásáhozmetódus esetén a @ToString.Exclude annotációval megakadályozhatja, hogy egy mezőt a toString() metódus kimenetében használjon . Ezenkívül legyen nagyon óvatos, amikor adatokat küld a külvilágnak. Tegyük fel, hogy van egy HTTP-végpontunk, amely az összes felhasználó nevét mutatja. Nincs szükség a felhasználó egyedi belső azonosítójának megjelenítésére. Miért? Mert a támadó arra használhatja, hogy más, érzékenyebb információkat szerezzen a felhasználóról. Például, ha a Jackson-t használja egy POJO sorozatosítására/deserializálására JSON- ra/-ről , akkor használhatja a @JsonIgnore és @JsonIgnoreProperties paramétereket .megjegyzések, amelyek megakadályozzák az egyes mezők szerializálását/deserializálását. Általában különböző POJO osztályokat kell használnia különböző helyeken. Az mit jelent?
  1. Ha adatbázissal dolgozik, használjon egy típusú POJO-t (egy entitást).
  2. Ha üzleti logikával dolgozik, alakítson át egy entitást modellvé.
  3. Amikor a külvilággal dolgozik és HTTP-kéréseket küld, használjon különböző entitásokat (DTO).
Így egyértelműen meghatározható, hogy mely mezők legyenek kívülről láthatók és melyek nem.

Használjon erős titkosítási és kivonatolási algoritmusokat

Az ügyfelek bizalmas adatait biztonságosan kell tárolni. Ehhez titkosítást kell használnunk. A feladattól függően el kell döntenie, hogy milyen típusú titkosítást kíván használni. Ezenkívül az erősebb titkosítás több időt vesz igénybe, ezért ismételten mérlegelnie kell, hogy az igény mennyire indokolja a rá fordított időt. Természetesen saját maga is írhat titkosítási algoritmust. De ez felesleges. Ezen a területen használhatja a meglévő megoldásokat. Például a Google Tink :
<!-- https://mvnrepository.com/artifact/com.google.crypto.tink/tink -->
<dependency>
   <groupid>com.google.crypto.tink</groupid>
   <artifactid>tink</artifactid>
   <version>1.3.0</version>
</dependency>
Nézzük meg, mit tegyünk a következő titkosítási és visszafejtési példa segítségével:
private static void encryptDecryptExample() {
   AeadConfig.register();
   KeysetHandle handle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_CTR_HMAC_SHA256);

   String plaintext = "Elvis lives!";
   String aad = "Buddy Holly";

   Aead aead = handle.getPrimitive(Aead.class);
   byte[] encrypted = aead.encrypt(plaintext.getBytes(), aad.getBytes());
   String encryptedString = Base64.getEncoder().encodeToString(encrypted);
   System.out.println(encryptedString);

   byte[] decrypted = aead.decrypt(Base64.getDecoder().decode(encrypted), aad.getBytes());
   System.out.println(new String(decrypted));
}

Jelszavak titkosítása

Ehhez a feladathoz a legbiztonságosabb az aszimmetrikus titkosítás használata. Miért? Mert az alkalmazásnak valójában nincs szüksége a jelszavak visszafejtésére. Ez a standard megközelítés. A valóságban, amikor a felhasználó beír egy jelszót, a rendszer azt titkosítja, és összehasonlítja a jelszótárolóban találhatóval. Ugyanezt a titkosítási folyamatot hajtják végre, így természetesen a megfelelő jelszó megadása esetén számíthatunk egymásra :) Ide a BCrypt és a SCrypt megfelelő. Mindkettő egyirányú függvény (kriptográfiai kivonat), számításilag összetett algoritmusokkal, amelyek hosszú ideig tartanak. Pontosan erre van szükségünk, mivel a közvetlen számítások örökké tartanak (na jó, hosszú-hosszú ideig). A Spring Security számos algoritmust támogat. Használhatjuk a SCryptPasswordEncoder-t és a BCryptPasswordEncoder-t. Ami jelenleg erős titkosítási algoritmusnak számít, az jövőre gyengének minősülhet. Ennek eredményeként arra a következtetésre jutottunk, hogy rendszeresen ellenőrizni kell az általunk használt algoritmusokat, és szükség szerint frissíteni kell a titkosítási algoritmusokat tartalmazó könyvtárakat.

Konklúzió helyett

Ma a biztonságról beszéltünk, és természetesen sok minden a színfalak mögött maradt. Épp most nyitottam ki az ajtót egy új világra, egy olyan világra, amelynek megvan a maga élete. A biztonság olyan, mint a politika: ha nem foglalkozol a politikával, akkor a politika is veled fogja elfoglalni magát. Hagyományosan azt javaslom, hogy kövessen engem a GitHub-fiókon . Ott posztolom a különféle technológiák felhasználásával készült alkotásaimat, amelyeket tanulok és alkalmazok a munkahelyemen.

Hasznos Linkek

  1. Guru99: SQL-befecskendezési oktatóanyag
  2. Oracle: Java Security Resource Center
  3. Oracle: Secure Coding Guidelines for Java SE
  4. Baeldung: A Java biztonság alapjai
  5. Közepes: 10 tipp a Java biztonság fokozásához
  6. Snyk: 10 Java biztonsági bevált gyakorlat
  7. GitHub: A GitHub Security Lab bejelentése: közösen biztosítjuk a világ kódját
Hozzászólások
  • Népszerű
  • Új
  • Régi
Hozzászólás írásához be kell jelentkeznie
Ennek az oldalnak még nincsenek megjegyzései