Küsimus:
Kas stringi väärtuse char [] ülekirjutamine on turvalisem?
Serverfrog
2014-12-11 02:30:48 UTC
view on stackexchange narkive permalink

Ma räägin Java juurutamisest. Kas peegelduse kasutamine on turvalisem, kui soovite kasutada sisemist välja väärtus tüüpi char [] java.lang.String eksemplar ja kirjutada sisaldavad väärtused üle nagu järgmine näide?

võiks selle üle kirjutada ja parooli kui selge loetava stringi saab mälust otsa.

Rakenduse näide:

  SecureRandom random = SecureRandom.getInstanceStrong (); Stringi allikas = " 1234SecureThingy "Väli charField = String.class.getDeclaredField (" väärtus "); charField.setAccessible (true); char [] müra = uus char [allikas.length ()]; for (int i = 0; i < source.length (); i ++) {müra [i] = (char) random.nextInt (Character.MAX_VALUE + 1);} charField.set (allikas, müra);  

TL; DR: Kas peegeldava stringi väärtuse eemaldamine on turvalisem?

Miks kasutada charsi [] asemel kõigepealt stringi?
Paljusid rakendusi näen kasutatava stringi sisendväärtusena kasutajalt, isegi parooliväljad jne. Vaadake https://docs.oracle.com/javafx/2/api/javafx/scene/control/PasswordField.html ja meetodit getText, mis on minu teada ainus võimalus kasutaja kirjutatud parool saada.
@user2313067-s kasutavad paljud Java API-d (ainult) stringi, ehkki mõned enamasti krüptospetsiifilised, näiteks Keystore.put, kasutavad seda lihtsalt pühkimiseks "char []". @Serverfrog (1) te ei kirjuta midagi üle, Java massiivid on võrdlusobjektid peaaegu (mitte päris) nagu klassid (2) kui kirjutate üle, on juhuslikkus ja eriti krüptorandomism täielik aja raiskamine (ja võimalus ebaõnnestumiseks) (3) ), kui kirjutate String * literal * või muul viisil interneeritud väärtuse üle, nagu teie näide, keerate palju asju, kuid muidugi ei tohiks * päris * parool kunagi olla sõnasõnaline ja seda ei tohiks interneerida. ...
... aga isegi kui pühite hoolikalt kõik need stringid, millele teil on viide, on neid palju rohkem, ja ka StringBuilderi või StringBufferi ja võib-olla isegi samade andmete muid vorme, vahetarkvaras ja sageli taaskasutatud GC-eelsed koopiad, mis mälus valetavad, mida te * ei suuda * realistlikult leida ja kustutada, mis muudab teie jõupingutused suures osas ebaefektiivseks. Vabandust.
Kaks vastused:
Thomas Pornin
2014-12-13 21:50:44 UTC
view on stackexchange narkive permalink

Pisutades eksemplaride String sisemist sisu, on teil oht oma rakendust tõsiselt rikkuda.

Esimene põhjus on see, et String eksemplarid peaksid olema muutumatud , mis tähendab, et eksemplare võidakse uuesti kasutada; "oma" stringi modifitseerimisel võite tegelikult muuta ka muid stressi, mis on kontseptuaalselt erinevad, kuid millel on juhtumisi sama sisu. Sellist taaskasutust võib juhtuda ka sisemiselt, kui String -i eksemplarid viitavad selle massiivi tüki piiritlemiseks aluseks olevale char [] -le koos paari indeksiga. Lisateavet leiate sellelt lehelt. Üldiselt tugineb kood, mis kasutab String -i eksemplare, nende muutumatusele ja selle invariandi purustamine võib viia kaugeleulatuvate ebameeldivate tagajärgedeni.

Teine põhjus on see, et String eksemplare pole dokumenteeritud ja võib muutuda . Tegelikult tegid nad seda juba mitu korda. Kui arvestada ainult Sun / Oracle JVM-i (juba julge samm, kuna seal on ka teisi JVM-e, nt IBMi), siis saavad Java 6 versioonid (alates värskendusest 21) kasutada tihendatud stringe, mis tähendab, et char [] teisendatakse automaatselt byte [] -iks, kui tähemärgid juhtuvad kõigi vahemikku 0..255 (st kõik märgid on tõesti osa ladina-1 -st). "Kokkusurutud stringid" olid mõeldud tippmarkide saamiseks mõnes võrdlusaluses, kuid lükati need hiljem maha (Java 7-l neid pole). Kuid see on piisav, et näidata, et sisemälu formaat võib ilma eelneva teatamiseta muutuda. Ja nad tegid seda uuesti Java 7 värskenduses 6.

Seega võib alternatiivse JVM-i kasutamine või JVM-i lihtsalt uuemale versioonile värskendamine (nagu on väga soovitatav, kui on turvaauke, mida parandada) võib koodi täielikult rikkuda, võib-olla vaikselt , st et teie andmed hävitavad puhta erandi asemel, mis lihtsalt tapab teie rakenduse. See on ebasoovitav, nii et ärge tehke seda. Te ei saa usaldusväärselt muheleda, kuidas String -i eksemplarid on sisemiselt korraldatud. Vahemärkusena võib öelda, et privaatsetele väljadele juurdepääs ei ole Java-aplettide jaoks ka tegelikult otstarbekas variant (te ei saa seda teha näiteks allkirjastamata apletiga).

Kolmas põhjus ja võib-olla kõige veenvam kolm, on see, et tundlike väärtuste ülekirjutamine mälus ei tööta Java-s (usaldusväärselt) . Selle teadmiseks peate mõistma, kuidas prügivedu algoritmid töötavad ( see artikkel on väga kena sissejuhatus põhitõdedesse). Programmeerija seisukohast on asjad lihtsad: objekt on eraldatud, istub seal RAM-is ja kui rakenduskood ei viita sellele, nõuab GC mälu tagasi. Sisemiselt võivad asjad siiski erineda. Eelkõige kipuvad kõige tõhusamad GC algoritmid mälus objekte liigutama, st kopeerivad neid tõepoolest ühest kohast teise. See on teie koodile nähtamatu, kuna GC kohandab viiteid: kuna Java on tipitud, ei saa te tähele panna, et osuti sisemine esitus on muutunud (te ei saa näiteks viidet täisarvule heita). Selline kopeerimine võimaldab kiiremat GC tööd ja paremat asukohta (vahemälude osas). See aga tähendab, et teie väärtuslike andmete mitu eksemplari võivad mujal RAM-is püsida, täiesti teie käeulatusest väljas. Isegi kui saaksite oma String sisu usaldusväärselt üle kirjutada, mõjutaks see ainult selle eksemplari praegust salvestusala, jättes selle kummituseksemplarid puutumata.

(Sun / Oracle JVM-is ilmus objekte sisemiselt kopeeriv GC Java 1.3 ümber. Seda võib näha nende raamatukogu koodi kujunduses; vana kood kasutas paroolide jaoks char [] vältida automaatset taaskasutamist, mis võib juhtuda String -ga, ja edendada käsitsi ülekirjutamist; uuem kood kasutab String -i, kuna raamatukogu kujundajad said aru, et see ülekirjutamine pole nagunii usaldusväärne.)


Kas see tähendab, et Java on oma olemuselt ebakindel? Ei, sest tundlike andmete mällu ülekirjutamise tähtsus on tugevalt liialdatud . Idee, et peate paroolid ja võtmed üle kirjutama, on üks neist päritud dogmadest: midagi, mis oli konkreetse juhtumi jaoks juba ammu asjakohane, kuid mida rakendavad ja rakendavad nüüd paljud inimesed, kes saavad seda jumaliku tarkusena ja ei saa aru, mis see on tegelikult umbes. Mälu ülekirjutamine on ohustatud süsteemides töötava rakenduskoodi jaoks tore asi, kui ründajad pole eriti pädevad: stsenaarium on keskmine koduomanik, kellel on pahavara täis arvuti. Pahavara kontrollib masinat täielikult, kuid olles lihtne automatiseeritud koodijupp, ei kasuta see seda juhtimist tegelikult ära; pahavara otsib RAM-i lihtsalt tähemärkide järjestuste järgi, mis näevad välja nagu krediitkaardi andmed. Nii et me räägime hukule määratud kliendisüsteemidest, mis suudavad ellu jääda ainult seetõttu, et ründajad eelistavad seda niimoodi, ning andmete püüdmist võib (potentsiaalselt) leevendada tundlike andmete kiire ülekirjutamine ainult seetõttu, et pahavarat kontrollivad inimründajad lihtsalt ei tee seda on aega huvitavate bittide väljavõtmiseks korralikult tööd teha ja peate selle asemel lootma kõige jõhkramatele täismälu skannimistele.

Ükski see ei kehti serverirakenduse ega kliendi koodi kohta, mis tegeleb saladustega, mille väärtus ei ole tühine. Kui pahatahtlik ründaja on võimeline otsima RAM-i tundlike andmete jaoks ja need andmed on väärt inimründaja selget tähelepanu 1 või 2 minutit, siis ükski ülekirjutamine ei päästa teid. Seega on paljudes kontekstides, kus turvalisus on oluline, paroolide ja võtmete ülekirjutamine lihtsalt raisatud pingutus, mis annab turvatunde , kuid ei paranda tegelikult asju (ehkki audiitorite austamine võib olla mugav).

Probleemi raskendab asjaolu, et kui teie tundlikud andmed ilmuvad teie Java-koodis, on need juba läbinud mitmesugused kihid, mis pole teie käeulatuses. Näiteks kui loete parooli failist, siis jäävad selle koopiad kerneli vahemäluks kasutatavasse RAM-i ja võib-olla üks või kaks Java-i poolt hooldatavat põrgapuhvrit emakeelse maailma ja Java pakutava abstraktsiooni vahel. Kui parool saadi võrgult SSL-i kaudu, läbis parool uuesti SSL-i teegi sisemise puhverdamise, mida te ei saa kontrollida. Kui me räägime kliendirakendusest ja parooli kirjutas lihtsalt kasutaja, siis käivitab iga pahavara, mis suudab mälu skannida, ka klahvilogerit ja sai parooli juba enne, kui see teie koodini jõudis.

Seetõttu, nagu kokkuvõte: ei, peegelduse kasutamine parooli mällu ülekirjutamiseks EI paranda turvalisust. See muudab teie koodi rikkumise tõenäolisemaks (isegi JVM-i lihtsa väiksema värskenduse korral), kuid ei paku reaalset käegakatsutavat turvalisuse kasvu. Nii et ärge tehke seda.


Märkus: me rääkisime siin Java-st, kuid kõik ülaltoodu kehtib võrdselt enamiku teiste programmeerimiskeelte ja -raamistike kohta, sealhulgas .NET (C #), PHP, Ruby, Node.js, Python, Mine ... Kui soovite tõesti delikaatsete andmete üle silma peal hoida, peate kasutama keelt, mis on piisavalt lähedal paljale metallile (assamblee, C, Forth) ja järgige seda kogu süsteemis, kaasa arvatud baaside teegid, kernel ja seadme draiverid. Kui keskendute lihtsalt rakenduse koodile, on teil garanteeritud see, et te ei pea seda punkti.

Märksõnade lisamine, et otsingumootorite abil oleks seda lihtsam: Heap Inspection
de-jcup
2019-11-19 17:49:48 UTC
view on stackexchange narkive permalink

IMHO on SealedObject -i kasutamine õige viis salajase teabe salvestamiseks JVM-i (Java Virtual Machine) mällu.

See kasutab JRE-s juba standardset turva- ja krüptomehhanismi toetab.

Palun vaadake minu vastust aadressil https://stackoverflow.com/a/58933366/2590615 - ma ei tahtnud sisu kopeerida. Samuti on link toimivale näitele.

Ma ei teadnud SealedObjectist!Aitäh!Kuid huvitav on see, kuidas nad haldavad objekti SealedObject sees oleva objekti mälusisest esitamist.


See küsimus ja vastus tõlgiti automaatselt inglise keelest.Algne sisu on saadaval stackexchange-is, mida täname cc by-sa 3.0-litsentsi eest, mille all seda levitatakse.
Loading...