Die drie lewens van my JWT-ondertekeningsleutel
Een private sleutel onderteken elke token wat ons auth-bediener uitreik. Verloor dit en 'n aanvaller munt 'n geldige token vir enige gebruiker, geen wagwoord nodig nie, en jou logboeke wys 'n skoon aanmelding. Dit is die enkele waardevolste geheim in die stelsel, en oor sy lewensloop het dit twee keer geskuif: dit is binne die toepassingsproses gebore, toe verban na 'n kluis wat dit nie meer kan verlaat nie, en toe herbore as 'n heeltemal ander soort sleutel. Elke skuif het op 'n lewende uitreiker gebeur, met tokens reeds onderweg en valideerders wat 'n toestand in die kas hou waaroor ons geen beheer het nie. Dit is wat daardie skuiwe werklik verg, en die een wat ons die meeste geleer het, was die een wat ons nie aangekondig het nie.
Lewe een: die sleutel wat die bediener in sy sak gehou het
In die begin het die sleutel gewoon waar dit gebruik is. Die bediener het 'n RSA-2048-sleutel gegenereer, dit in geheue gehou, en sy tokens met RS256 onderteken. Dit is byna oral die verstek, en dit werk goed — tot op die oomblik wat jy die woord bewaring hardop sê. Die private sleutel was bereikbaar vir enigiets wat die proses se geheue, sy konfigurasie, of 'n rugsteun van enige van die twee kon lees. Ons wou vir kliënte kon sê dat 'n uitgelekte databasis niks nuttigs blootlê nie, en 'n ondertekeningsleutel wat net een proses weg van daardie databasis sit, het daardie bewering 'n leuen gemaak. Die sleutel moes die gebou verlaat.
Lewe twee: die sleutel wat na 'n kluis getrek het wat dit nie kan verlaat nie
Ons het 'n naat ingevoer — 'n ISignatureProvider wat die bediener roep wanneer dit 'n handtekening nodig het — en 'n KMS daaragter geplaas. Die sleutel word nou binne Vault se transit-enjin gegenereer en word nooit uitgevoer nie. Die toepassing hou dit nie; dit stuur die grepe wat onderteken moet word na die kluis en kry 'n handtekening terug. Dit kan die sleutel gebruik en dit kan dit nie uitsmokkel nie.
Daardie onderskeid is die hele punt. 'n Geheue-dump, 'n gemorste konfigurasielêer, 'n uitgelekte rugsteun — nie een van hulle bevat die sleutel meer nie, want die sleutel was nog nooit op enige van daardie plekke nie. Om die toepassing te kompromitteer koop 'n aanvaller nou die vermoë om die kluis te vra om te onderteken, wat ons kan tempobeperk, ouditeer en herroep. Dit koop hulle nie meer die sleutel self nie, waaroor ons niks kon doen sodra dit weg was nie.
Hier is die deel wat ons nie in die vrystellingsnotas gesit het nie. Dieselfde commit wat die sleutel na die kluis geskuif het, het ook stilweg ons PBKDF2-iterasietelling gehalveer, van 100,000 af tot 50,000. Een diff, twee sekuriteitsveranderinge wat in teenoorgestelde rigtings wys: die opskrif was 'onderteken in die KMS,' en daaronder het 'n werkfaktor vir wagwoordhutsing saamgery wat gehalveer is, in 'n reël waarna niemand gekyk het nie omdat die storie oor iets anders gegaan het. Albei is sekuriteitskode, so albei is as 'n enkele 'meer veilige' verandering hersien en deurgelaat op die krag van die goeie helfte.
Die regstelling was een reël. Die les was nie. 'n Diff wat meer veilig geëtiketteer is, is steeds 'n diff, en die sekuriteitsensitiewe konstantes daarin — iterasietellings, sleutelgroottes, timeouts, algoritmename — erf nie 'n stralekrans van die commit-boodskap nie. Ons behandel nou 'n werkfaktorgetal net soos ons 'n keuse van algoritme behandel: iets wat beweer én nagegaan word, nie iets wat jy vertrou omdat die omringende verandering 'n goeie idee was nie.
Lewe drie: die sleutel wat kleiner geword het om vinniger te wees
Met ondertekening agter 'n KMS is elke handtekening 'n netwerk-heen-en-weer-rit, en RSA-ondertekening is die duur soort. Die sleutel het dus van spesie verander: RS256 oor RSA-2048 het ES256 oor die P-256-kurwe geword. Elliptiese-kurwe-ondertekening is ongeveer 'n ordegrootte goedkoper as RSA, 'n P-256-handtekening is 64 grepe waar RSA-2048 s'n 256 is, en die stel publieke sleutels wat valideerders aflaai krimp ooreenkomstig. Kleiner sleutel, kleiner handtekening, kleiner JWKS, vinniger tokens — alles bloot deur 'n beter kurwe te kies.
Die vangs is dat jy nie die ondertekeningsalgoritme op 'n lewende uitreiker in een klap kan omruil nie. Elke token wat reeds uitgereik is, is met RS256 onderteken en moet aanhou valideer totdat dit verval. Elke valideerder het jou ou publieke sleutel gekas. Verander die algoritme in een skuif en jy maak elke token onderweg én elke gekaste sleutelstel op dieselfde oomblik ongeldig — 'n selftoegediende onderbreking wat as 'n opgradering aangetrek is.
Wat gewerk het, was om op te hou voorgee dat daar ooit net een sleutel was. Die sleutelstoor het algoritme-agnosties geword: dit hou die RSA-sleutel en die EC-sleutel gelyktydig, en publiseer albei in die JWKS, elkeen onder sy eie sleutel-id en algoritme. 'n Aparte aktiewe-sleutel-kieser besluit watter sleutel nuwe tokens onderteken, en dit draai homself van die oue RSA-sleutel af die oomblik wat 'n EC-sleutel bestaan — geen konfigurasievlag, geen ontplooiing wat afgestem is om met 'n rotasie saam te val nie. Deur die oorvleueling adverteer discovery albei publieke sleutels, sodat tokens wat met enige van die twee onderteken is, aanhou valideer. Sodra die laaste RS256-token verval het, adverteer discovery net ES256 en validering pen ValidAlgorithms = ES256 vas, wat ook die deur toeslaan op algoritme-verwarringsaanvalle wat 'n valideerder probeer ompraat om die verkeerde skema te aanvaar. Die migrasie is 'n crossfade wat die uitreiker op homself uitvoer, nie 'n skakelaar wat iemand oorhaal nie.
Die les, gedistilleer
'n Ondertekeningsleutel lyk soos 'n konstante: een geheim, een keer gestel, vir ewig verwys. Ons s'n was nie. In sy lewe het dit van bewaring verander, van die proses na 'n KMS, en dit het van spesie verander, van RSA na elliptiese kurwe, en albei skuiwe moes gemaak word met tokens onderweg en valideerders wat dinge kas wat nie ons s'n is nie. Die eienskap wat elke skuif oorleefbaar gemaak het, was albei kere dieselfde: die stelsel het nooit aangeneem daar was presies een sleutel, een algoritme, of een tuiste nie. Bou die sleutelstoor om verskeie sleutels te hou en eerlik te adverteer watter ene dit hou, en rotasie — van waar die sleutel woon of van watter soort sleutel dit is — hou op om 'n onderbreking te wees wat jy skeduleer en word 'n eienskap wat die uitreiker op sy eie bestuur.
As jy auth bedryf, behoort die ding wat jou tokens onderteken die vervelendste, mees inspekteerbare, minste slim voorwerp te wees wat jy besit. Ons s'n het drie lewens gevat om daar te kom. Dit was elke een werd.