Kodėl char [] pirmenybė teikiama slaptažodžiams?

„Swing“ slaptažodžio lauke yra getPassword() metodas (grąžina char[] ), o ne įprastas „ getText() metodas (grąžina String ). Be to, aš susidūriau su pasiūlymu nenaudoti String slaptažodžiui tvarkyti.

Kodėl naudojant slaptažodžius String kelia pavojų saugumui? Naudoti char[] yra nepatogu.

3016
16 янв. nustatė Ahamed Jan 16 2012-01-16 17:20 '12, 12:20 pm 2012-01-16 17:20
@ 18 atsakymų

Stygos yra nekintamos . Tai reiškia, kad sukūrus String , jei kitas procesas gali nuvalyti atmintį, nėra jokio būdo (išskyrus atspindį ), galite atsikratyti duomenų prieš pradedant šiukšlių surinkimą .

Naudodami masyvą, galite aiškiai ištrinti duomenis po to, kai tai atliksite. Masyvą galite perrašyti bet kokiu būdu, o slaptažodis nebus rodomas bet kurioje sistemos vietoje, net prieš šiukšlių surinkimą.

Taigi tai yra saugumo problema, tačiau net naudojant char[] tik sumažina užpuoliko galimybes ir tik šiam konkrečiam atakos tipui.

Kaip pažymėta komentaruose, yra įmanoma, kad šiukšlių surinkimo įrenginio perkeltos matricos paliks neaktyvias atminties duomenų kopijas. Manau, kad tai yra konkretus įgyvendinimas - šiukšlių surinkėjas gali išvalyti visą atmintį, kad būtų išvengta tokio pobūdžio dalykų. Net jei taip yra, vis dar yra laiko, per kurį char[] yra faktiniai simboliai kaip atakos >

3853
16 янв. Atsakyti į Jon Skeet sausio 16 d 2012-01-16 17:26 „12 at 17:26 pm 2012-01-16 17:26

Nors kiti sakiniai čia atrodo tikrai, yra dar viena įtikinama priežastis. Naudodami įprastą String , dažniau atsitiktinai spausdinsite žurnalų , monitorių ar kitų nesaugių vietų slaptažodį . char[] mažiau pažeidžiamas.

Apsvarstykite tai:

 public static void main(String[] args) { Object pw = "Password"; System.out.println("String: " + pw); pw = "Password".toCharArray(); System.out.println("Array: " + pw); } 

Spausdinti

 String: Password Array: [C@5829428e 
1114
16 янв. atsakymas pateikiamas Konrad Garus 16 sausis 2012-01-16 22:37 '12, 10:37 pm 2012-01-16 22:37

Norėdami cituoti oficialų dokumentą, „ Java“ kriptografijos architektūros vadovas kalba apie „ char[] ir slaptažodžių naudojimą. String (apie slaptažodžiu pagrįstą šifravimą, bet tai, žinoma, apie slaptažodžius):

Atrodo logiška rinkti ir saugoti slaptažodį į java.> tipo objektą. Tačiau čia yra atsargumas: Object tipo Object yra nekintamas, t.y. Nėra jokių metodų, kurie nustatytų, kas leidžia keisti (perrašyti) arba iš naujo nustatyti String turinį po naudojimo. Ši funkcija leidžia String objektams netinkami saugoti slaptą informaciją, pvz., Vartotojo slaptažodį. Visada turėtumėte rinkti ir saugoti konfidencialią saugumo informaciją.

„Java 4.0“ programavimo kalbos saugaus kodavimo vadovo 2-2 instrukcijoje taip pat yra kažkas panašaus (nors tai iš pradžių buvo žurnalo sudarymo kontekste):

2-2 gairė: neregistruokite itin jautrios informacijos.

Kai kuri informacija, pvz., Socialinio draudimo numeriai (SSN) ir slaptažodžiai, yra labai jautri. Ši informacija neturėtų būti laikoma ilgiau nei būtina ir, jei įmanoma, net administratoriai. Pavyzdžiui, jis neturėtų būti siunčiamas į žurnalo failus ir jo buvimas neturėtų būti aptiktas paieškos metu. Kai kurie tranzitai gali būti saugomi kintamųjų duomenų struktūrose, pvz., Šriftų matricose, ir išvalomi iš karto po naudojimo. Duomenų struktūrų išvalymas sumažino našumą įprastose „Java“ vykdymo sistemose, nes objektai perkeliami į atmintį skaidriai programuotojui.

Šis vadovas taip pat turi įtakos žemo lygio bibliotekų, neturinčių semantinių žinių apie juos tvarkant, įgyvendinimui ir naudojimui. Pavyzdžiui, analizuojant žemesnio lygio bibliotekoje galima užregistruoti tekstą, kuriuo jis veikia. Programa gali analizuoti SSN su biblioteka. Tai sukuria situaciją, kai SSN yra prieinama administratoriams, turintiems prieigą prie žurnalo failų.

634
17 янв. Atsakymą Bruno pateikė sausio 17 d. 2012-01-17 06:20 '12 6:20 2012-01-17 06:20

Simbolių matricos ( char[] ) gali būti išvalytos po naudojimo, kiekvienam simboliui nustatant nulį, bet linijos nėra. Jei kas nors gali matyti vaizdą atmintyje, jie gali matyti slaptažodį paprastu tekstu, jei vartojamos stygos, bet jei naudojamas char[] , išvalius duomenis iš 0, slaptažodis yra apsaugotas.

319
16 янв. atsakymas, kurį pateikė alephx Jan 16 2012-01-16 17:27 '12, 17:27, 2012-01-16 17:27

Kai kurie žmonės mano, kad reikia perrašyti atmintį, naudojamą slaptažodžio saugojimui, kai tik to nereikia. Tai sumažina laiko, per kurį užpuolikas turi perskaityti slaptažodį iš jūsų sistemos, ir visiškai ignoruoja tai, kad užpuolikas jau turi prieigą, kad užfiksuotų JVM atmintį. Užpuolikas, turintis tokią prieigą, gali sugauti jūsų svarbiausius įvykius, todėl jis yra visiškai nenaudingas (AFAIK, todėl prašau pataisyti mane, jei aš klystu).

Atnaujinti

Komentarų dėka turiu atnaujinti savo atsakymą. Atrodo, kad yra du atvejai, kai tai gali padidinti (labai) nedidelį saugumo pagerinimą, nes tai sumažina laiką, kai slaptažodis gali nusileisti standžiajame diske. Tačiau manau, kad daugeliu atvejų tai per daug.

  • Jūsų tikslinė sistema gali būti netinkamai sukonfigūruota, arba jūs turėtumėte daryti prielaidą, kad ji yra, ir jūs turite būti paranojiškas apie pagrindinius sąvartynus (gali būti galioja, jei sistemos nėra tvarkomos administratoriaus).
  • Jūsų programinė įranga turėtų būti pernelyg paranoiška, kad būtų išvengta duomenų nutekėjimo, kai užpuolikas pasiekia prieigą prie aparatūros, naudodamas tokias funkcijas kaip „ TrueCrypt“ (nutrauktas), „ VeraCrypt“ arba „ CipherShed“ .

Jei įmanoma, pagrindinės sąvartynų ir ieškos failų išjungimas rūpinsis visomis problemomis. Tačiau jiems reikės administratoriaus teisių ir gali sumažinti funkcionalumą (mažiau atminties) ir pašalinti iš operacinės sistemos esančią atmintį vis dar bus rimtų problemų.

194
16 янв. atsakymą pateikė josefx 16 sausis 2012-01-16 17:32 '12, 17:32, 2012-01-16 17:32
  • Stygos „Java“ nekeičiamos , jei išsaugosite slaptažodį paprastu tekstu, jis bus atmintyje, kol šiukšlių surinkėjas jį išvalys, ir kadangi eilutės naudojamos eilutės talpykloje pakartotiniam naudojimui, tikimybė, kad ji išliks atmintyje ilgą laiką, o tai kelia pavojų saugumui. Kadangi kiekvienas, turintis prieigą prie atminties sąvartyno, jį gali rasti aiškiu tekstu.
  • Java rekomendacija naudojant getPassword() metodą JPasswordField, kuris grąžina char [] metodą ir pasenusį getText() , kuris grąžina slaptažodį teksto formoje, nurodydamas saugumo priežastį.
  • toString () visada kyla pavojus, kad log ir konsolės failuose įvedate paprastą tekstą, bet jei naudojate „Array“, negalėsite spausdinti masyvo turinio, o jo atmintis bus išspausdinta.

     String strPwd = "passwd"; char[] charPwd = new char[]{'p','a','s','s','w','d'}; System.out.println("String password: " + strPwd ); System.out.println("Character password: " + charPwd ); 

    Slaptažodžių eilutė: passwd

    Simbolių slaptažodis: [C @ 110b2345

Baigiamosios mintys: nors naudojant „char“ [] yra ne tik pakankamai, turite ištrinti turinį, kad jis būtų saugesnis. Aš taip pat siūlau dirbti su slaptu arba užšifruotu slaptažodžiu vietoj paprasto teksto ir atlaisvinti jį iš atminties, kai tik bus baigtas autentifikavimas.

125
27 дек. atsakymą pateikė Srujan Kumar Gulla 27 d. 2012-12-27 23:22 '12 11:22 pm 2012-12-27 23:22

Nemanau, kad tai yra teisingas sakinys, bet bent jau galiu atspėti, kodėl.

Manau, kad motyvacija yra ta, kad jūs galite greitai ir patikimai ištrinti visus slaptažodžio pėdsakus atmintyje ir pasitikėdami po jo naudojimo. Su char[] jūs galite perrašyti kiekvieną masyvo elementą tuščią arba kažką tiksliai. Tokiu būdu negalite redaguoti String vidinės vertės.

Tačiau tai nėra geras atsakymas; kodėl gi ne tik įsitikinti, kad nuoroda į char[] ar String neišnyksta? Tada nėra saugumo problemos. Tačiau faktas yra tas, kad String objektai gali būti intern() teoriškai ir saugomi pastoviame baseine. Manau, kad naudojant char[] neigiama ši funkcija.

76
16 янв. atsakymą pateikė Sean Owen , 16 d. 2012-01-16 17:27 '12, 17:27, 2012-01-16 17:27

Atsakymas jau pateiktas, bet norėčiau pasidalinti problema, kurią neseniai atradau su standartinėmis „Java“ bibliotekomis. Nors dabar jie labai atsargiai pakeičia char[] slaptažodžių eilutes (kurios, žinoma, yra geros), kiti svarbūs svarbūs duomenys, atrodo, yra nepastebėti, kai reikia išvalyti ją iš atminties.

Aš turiu omenyje, pavyzdžiui, klasę PrivateKey . Apsvarstykite scenarijų, kuriame galite atsisiųsti RSA privatų raktą iš PKCS # 12 failo, naudodami tam tikrą operaciją. Šiuo atveju slaptažodžio šnipinėjimas pats savaime nepadės, kol fizinė prieiga prie pagrindinio failo nebus tinkamai apribota. Kaip užpuolikas, jums bus daug geriau, jei gausite raktą tiesiogiai, o ne slaptažodį. Norima informacija gali būti praleista daug, pagrindiniai sąvartynai, debugger sesijos arba ieškos failai yra tik keletas pavyzdžių.

Ir, kaip paaiškėjo, nėra nieko, kas leistų iš asmeninės informacijos iš „ PrivateKey iš atminties išvalyti, nes nėra API, kuri leistų ištrinti baitus, kurie sudaro atitinkamą informaciją.

Tai bloga padėtis, nes šiame dokumente aprašoma, kaip ši aplinkybė gali būti naudojama.

Pavyzdžiui, OpenSSL biblioteka prieš įrašydama slaptus raktus perrašo kritines atminties dalis. Kadangi „Java“ renka šiukšles, mums reikia aiškių metodų, kaip išvalyti ir panaikinti „Java“ raktų asmeninę informaciją, kuri turėtų būti taikoma iškart po rakto naudojimo.

61
19 янв. pateiktas atsakymas emboss 19 d 2012-01-19 22:39 '12, 22:39 pm 2012-01-19 22:39

Kaip teigia Johnas Skeetas, nėra jokio požiūrio, išskyrus refleksiją.

Tačiau, jei refleksija yra jūsų pasirinkimas, galite tai padaryti.

 public static void main(String[] args) { System.out.println("please enter a password"); // don't actually do this, this is an example only. Scanner in = new Scanner(System.in); String password = in.nextLine(); usePassword(password); clearString(password); System.out.println("password: '" + password + "'"); } private static void usePassword(String password) { } private static void clearString(String password) { try { Field value = String.class.getDeclaredField("value"); value.setAccessible(true); char[] chars = (char[]) value.get(password); Arrays.fill(chars, '*'); } catch (Exception e) { throw new AssertionError(e); } } 

paleidžiant

 please enter a password hello world password: '***********' 

Pastaba: jei String char [] buvo nukopijuota kaip GC ciklo dalis, yra tikimybė, kad ankstesnė kopija yra kažkur atmintyje.

Ši senoji kopija nebus rodoma šiukšliadėžėje, bet jei turite tiesioginę prieigą prie žaliavos atminties, galite ją pamatyti. Apskritai, turėtumėte vengti bet kurio naudotojo prieigos.

44
08 июля '15 в 12:26 2015-07-08 12:26 atsakymą pateikė Peter Lawrey liepos 8 d., 15 val. 12:26 2015-07-08 12:26

Redagavimas: grįžus prie šio atsakymo po metų saugumo tyrimų, suprantu, kad tai sukelia tam tikrų gana nemalonių pasekmių, kurias kada nors lygintumėte paprastuosius tekstinius slaptažodžius. Prašome ne. Naudokite saugų vienpusį druskos maišą ir pagrįstą iteracijų skaičių . Pagalvokite, kaip naudotis biblioteka: sunku suprasti!

Originalus atsakymas: Atsižvelgiant į tai, kad String.equals () naudoja trumpojo jungimo vertinimą ir todėl yra pažeidžiamas laikinai atakai? Tai gali būti mažai tikėtina, tačiau teoriškai galite palyginti laiką su slaptažodžiu, kad nustatytumėte tinkamą simbolių seką.

 public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; // Quits here if Strings are different lengths. if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; // Quits here at first different character. while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } 

Keletas laiko nustatymo išteklių:

37
08 апр. Atsakymą pateikė Graph Theory, balandžio 08 2015-04-08 03:04 '15 - 03:04 2015-04-08 03:04

Tai yra visų priežasčių, todėl turite pasirinkti char [] masyvą vietoj String for password.

1. Kadangi eilutėje „Java“ keičiamos eilutės, jei išsaugosite slaptažodį paprastu tekstu, jis bus atmintyje, kol šiukšlių surinkėjas jį išvalys, ir kadangi eilutė naudojama eilutėje, kad būtų galima pakartotinai naudoti, yra gana didelė tikimybė kad jis ilgą laiką išliks atmintyje, o tai sukelia saugumo riziką.

Kadangi kiekvienas, turintis prieigą prie atminties sąvartyno, gali rasti slaptažodį aiškiu tekstu, tai dar viena priežastis, kodėl turėtumėte naudoti šifruotą slaptažodį, o ne paprastą tekstą. Kadangi stygos yra nekintamos, neįmanoma keisti styginių turinio, nes bet kokie pakeitimai sukurs naują eilutę, o jei naudosite char [], vis tiek galite nustatyti visus elementus tuščius arba nulinius. Taigi slaptažodžio saugojimas simbolių rinkinyje aiškiai sumažina slaptažodžio vagystės saugumo riziką.

2. „ Java“ pati rekomenduoja naudoti JPasswordField getPassword () metodą, kuris grąžina char [], o ne pasenusį getText () metodą, kuris grąžina slaptažodžius aiškiame tekste, nurodydamas saugumo sumetimus. Gerai sekti „Java“ komandos rekomendacijas ir laikytis standartų, o ne prieš juos.

3. Naudojant eilutę, visada kyla pavojus, kad į teksto įrašą į žurnalą ar konsolę įrašysite paprastą tekstą, bet jei naudojate „Array“, negalėsite spausdinti masyvo turinio, o jo vieta bus atspausdinta. Nors tai nėra tikroji priežastis, ji vis dar yra prasminga.

 String strPassword="Unknown"; char[] charPassword= new char[]{'U','n','k','w','o','n'}; System.out.println("String password: " + strPassword); System.out.println("Character password: " + charPassword); String password: Unknown Character password: [C@110b053 

Nuoroda į šį dienoraštį . Tikiuosi, kad tai padės.

36
08 мая '14 в 13:17 2014-05-08 13:17 atsakymas yra pateiktas žmogui „Gegužės 08 d. 14, 13:17 2014-05-08 13:17

Nėra nieko, kad „char“ masyvas jums suteiktų „vs String“, jei po naudojimo neautomatiniu būdu neišvalysite, ir aš nematau, kad kas nors tai padarytų. Todėl man, pirmenybė char [] ir String yra šiek tiek perdėta.

Pažvelkite į čia plačiai naudojamą pavasario saugumo biblioteką ir paklauskite savęs - „Spring Security“ vaikinai yra nekompetentingi ar slaptažodžiai [] neužtenka. Kai kai kurie bjaurus įsilaužėliai užfiksuoja atminties atmintį, įsitikinkite, kad jis gauna visus slaptažodžius, net jei naudojate sudėtingus būdus, kaip juos slėpti.

Tačiau „Java“ visą laiką keičiasi, o kai kurios baisios funkcijos, pvz., „ Java 8“ eilutės deduplikacijos funkcija, gali nustatyti styginių objektus be jūsų žinios. Tačiau tai yra skirtingi pokalbiai.

33
24 янв. Atsakymas pateikiamas Oleg Mikheev 24 sausis 2015-01-24 10:43 '15 - 10:43 2015-01-24 10:43

Stygos yra nekintamos ir negali būti pakeistos po jų sukūrimo. Slaptažodžio kaip eilutės kūrimas sukels likutinę prieigą prie slaptažodžio krūva arba eilutės talpykloje. Dabar, jei kas nors užima „Java“ procesų krūvą ir atidžiai tikrina, jis gali atspėti slaptažodžius. Žinoma, šios nepanaudotos linijos surinks šiukšles, tačiau tai priklauso nuo to, kada prasideda GC.

Kita vertus, char [] pasikeičia, kai tik atliekamas autentifikavimas, galite juos perrašyti bet kokiu simboliu, kaip ir visi M arba backslashes. Dabar, net jei kas nors užima krūvą krūvų, jis gali negalėti gauti slaptažodžių, kurie šiuo metu nėra naudojami. Tai suteikia jums daugiau kontrolės, jei norite išvalyti objekto turinį savaime arba laukti, kol baigsis GC.

29
28 июля '15 в 13:46 2015-07-28 13:46 atsakymą pateikė Geek liepos 28 d., 15 val. 13:46 2015-07-28 13:46

Trumpas ir paprastas atsakymas bus tas, kad char[] yra keičiantis, o String objektai - ne.

Strings „Java“ yra nekintami objektai. Štai kodėl jie negali būti keičiami po kūrimo, todėl vienintelis būdas pašalinti jų turinį iš atminties yra rinkti juos su šiukšlėmis. Tai bus tik tada, kai atmintinė, kurią atlaisvins objektas, gali būti perrašyta ir duomenys išnyks.

Dabar „Java“ šiukšlių surinkimas nevyksta jokiu garantiniu intervalu. Taigi, String gali būti laikoma atmintyje ilgą laiką, ir jei procesas per šį laiką nepavyksta, eilutės turinys gali baigtis atminties sąvartyne arba tam tikrame žurnale.

Naudodami simbolių masyvą, galite perskaityti slaptažodį, išeiti iš jo kuo greičiau ir iš karto pakeisti turinį.

17
09 дек. atsakymą pateikė Pritam Banerjee 09 dec. 2016-12-09 22:02 '16 at 10:02 pm 2016-12-09 22:02

1) Kadangi stygos „Java“ yra nekintamos, jei išsaugosite slaptažodį kaip paprastą tekstą, jis bus atmintyje, kol šiukšlių surinkėjas jį išvalys, ir kadangi eilutė naudojama eilutėje, kad būtų galima pakartotinai naudoti, yra gana didelė tikimybė kad jis išliks atmintyje ilgą laiką, o tai sukelia saugumo riziką. Kadangi kiekvienas, turintis prieigą prie atminties sąvartyno, gali rasti slaptažodį aiškiu tekstu, ir dėl šios priežasties visada turėtumėte naudoti šifruotą slaptažodį nei paprastas tekstas. Kadangi stygos yra nekintamos, negalite keisti styginių turinio, nes bet kokie pakeitimai sukurs naują eilutę, o jei esate char [], vis dar galite nustatyti visą jo elementą tuščią arba nulinę. Taigi slaptažodžio saugojimas simbolių matricoje sumažina slaptažodžio vagystės saugumo riziką.

2) „Java“ pati rekomenduoja naudoti JPasswordField getPassword () metodą, kuris grąžina char [] ir pasenusią getText () metodą, kuris grąžina slaptažodį aiškiu tekstu, nurodydamas saugumo priežastį. Gerai sekti „Java“ komandos patarimus ir laikytis standarto, o ne prieštarauti.

16
07 сент. atsakymą pateikė Neeraj Gahlawat 07 Sep. 2017-09-07 13:47 '17, 13:47 pm 2017-09-07 13:47

Styga nekeičiama ir eina į eilutės baseiną. Po rašymo tai negalima perrašyti.

char[] yra masyvas, kurį turite perrašyti po to, kai naudojote slaptažodį, ir tai turėtų būti daroma:

 char[] passw = request.getPassword().toCharArray() if (comparePasswords(dbPassword, passw) { allowUser = true; cleanPassword(passw); cleanPassword(dbPassword); passw=null; } private static void cleanPassword (char[] pass) { for (char ch: pass) { ch = '0'; } } 

Vienas scenarijus, kuriame užpuolikas gali jį naudoti, yra crashdump - kai JVM sugenda ir iškelia atmintį, galite matyti slaptažodį.