Online-käyttäjistä on tulossa yhä vastustuskykyisempi perinteisiin sähköposti- / salasanan rekisteröintiprosesseihin. Yhden napsautuksen sosiaalinen sisäänkirjautumistoiminto Facebookin, Googlen tai GitHubin kautta osoittautuu paljon toivottavammaksi vaihtoehdoksi. Siihen liittyy kuitenkin kompromissi.
Plussat sosiaalisen median sisäänkirjautumisen integraatiosta:
Haitat sosiaalisen median sisäänkirjautumisen integraatiosta:
Tässä artikkelissa esitellään uusi kirjautumistapa blockchain-kehitys : Yhden napsautuksen salattu ja kryptografisesti suojattu kirjautumisvirta MetaMask-laajennus , kaikki tiedot on tallennettu omaan takapäähän. Kutsumme sitä: 'Kirjaudu sisään MetaMaskilla'.
Tuhannen sanan arvoinen kuva, tässä on demo sisäänkirjautumisvirrasta, jonka aiomme rakentaa:
Näyttää hyvältä? Aloitetaan!
Perusajatuksena on, että tilin omistaminen on kryptografisesti helppoa todistaa allekirjoittamalla tieto yksityisellä avaimella. Jos onnistut allekirjoittamaan tarkan palan tuottamamme datan, takapää pitää sinua kyseisen julkisen osoitteen omistajana. Siksi voimme rakentaa viestien allekirjoittamiseen perustuvan todennusmekanismin, jonka käyttäjän tunniste on käyttäjän julkinen osoite.
Jos se ei vaikuta selvältä, se on kunnossa, koska selitämme sen pikku bittiä:
Huomaa, että kun käytämme Ethereum blockchain (MetaMask, Ethereumin julkiset osoitteet), tämä kirjautumisprosessi ei todellakaan tarvitse lohkoketjua: Se tarvitsee vain sen salaustoiminnot. Tästä huolimatta MetaMaskista tulee niin suosittu laajennus , näyttää nyt olevan hyvä aika esitellä tämä kirjautumisvirta.
Jos tiedät jo mikä MetaMask on, ohita tämä osio.
MetaMask on selainlaajennus, joka on saatavana nimellä MetaMask Chrome -laajennus tai Firefox-lisäosa . Ytimessä se toimii Ethereum-lompakkona: Asentamalla sen saat pääsyn ainutlaatuiseen Ethereumin julkiseen osoitteeseen, jolla voit aloittaa eetterin tai rahakkeiden lähettämisen ja vastaanottamisen.
Mutta MetaMask tekee jotain muuta kuin Ethereumin lompakko. Selainlaajennuksena se voi olla vuorovaikutuksessa selaamasi verkkosivun kanssa. Se tekee niin injektoimalla JavaScript-kirjaston nimeltä web3.js jokaisella vierailemallasi verkkosivulla. Injektion jälkeen a web3
objekti on saatavana window.web3
-palvelun kautta tämän sivuston JavaScript-koodissa. Jos haluat katsoa, miltä tämä esine näyttää, kirjoita window.web3
Chrome- tai Firefox DevTools -konsolissa, jos MetaMask on asennettu.
Web3.js on Java-käyttöliittymä Ethereumin estoketjuun. Toimintoja on:
web3.eth.getBlockNumber
)web3.eth.coinbase
)web3.eth.getBalance
)web3.eth.sendTransaction
)web3.personal.sign
)Kun MetaMask on asennettu, mikä tahansa käyttöliittymäkoodi voi käyttää kaikkia näitä toimintoja ja vuorovaikutuksessa blockchainin kanssa . Niitä kutsutaan dapps tai DApps (hajautetuille sovelluksille - joskus jopa tyylillä ”ĐApps”).
Liittyy DApp-kehitykseen: Aikalukitut lompakot: Johdanto Ethereum Smart -sopimuksiinSuurin osa web3.js: n toiminnoista on lukutoimintoja (hae lohko, saa tasapaino jne.) Ja web3
antaa vastauksen välittömästi. Jotkin toiminnot (kuten web3.eth.sendTransaction
ja web3.personal.sign
) tarvitsevat kuitenkin nykyisen tilin allekirjoittamaan joitain tietoja yksityisellä avaimellaan. Nämä toiminnot käynnistävät MetaMaskin näyttämään vahvistusnäytön ja tarkistamaan, että käyttäjä tietää, mitä hän allekirjoittaa.
Katsotaanpa, miten MetaMaskia käytetään tähän. Tee yksinkertainen testi liittämällä seuraava rivi DevTools-konsoliin:
web3.personal.sign(web3.fromUtf8('Hello from ApeeScape!'), web3.eth.coinbase, console.log);
Tämä komento tarkoittaa: Kirjoita viestini, muunnettuna utf8: sta hex-muotoon, coinbase-tilillä (eli nykyisellä tilillä) ja tulosta takaisinsoittona allekirjoitus. Näkyviin tulee MetaMask-ponnahdusikkuna, ja jos allekirjoitat sen, allekirjoitettu viesti tulostetaan.
Käytämme web3.personal.sign
sisäänkirjautumisvirrassamme.
Viimeinen huomautus tästä osiosta: MetaMask pistää web3.js: n nykyiseen selaimeesi, mutta on olemassa muita itsenäisiä selaimia, jotka myös injektoivat web3.js: tä, kuten Sumu , esimerkiksi. Mielestäni MetaMask tarjoaa kuitenkin tänään parhaan käyttöliittymän ja yksinkertaisen siirtymän tavallisille käyttäjille dappien tutkimiseen.
Aloitetaan Miten . Miten toivottavasti vakuutan teille, että se on turvallinen, joten pidän miksi osa lyhyt.
Kuten yleiskatsauksessa todetaan, unohdamme lohkoketjun. Meillä on perinteinen Web 2.0 asiakas-palvelin RESTful -arkkitehtuuri. Teemme yhden oletuksen: että kaikilla käyttöliittymäsivullamme vierailevilla käyttäjillä on MetaMask asennettuna. Tämän oletuksen avulla näytämme, kuinka salasanaton salauksellisesti turvallinen kirjautumisvirta toimii.
Ensinnäkin User
mallissa on oltava kaksi uutta pakollista kenttää: publicAddress
ja nonce
. Lisäksi publicAddress
täytyy olla ainutlaatuinen. Voit säilyttää tavalliset username
, email
ja password
kentät - varsinkin jos haluat toteuttaa MetaMask-kirjautumistunnuksesi rinnakkain sähköpostin / salasanan kirjautumiseen - mutta ne ovat valinnaisia.
Rekisteröintiprosessi eroaa myös hieman, koska publicAddress
on pakollinen kenttä rekisteröitymisen yhteydessä, jos käyttäjä haluaa käyttää MetaMask-kirjautumista. Voit olla varma, että käyttäjän ei koskaan tarvitse kirjoittaa publicAddress
manuaalisesti, koska se voidaan noutaa web3.eth.coinbase
Luo satunnaismerkkijono kullekin tietokannan käyttäjälle nonce
ala. Esimerkiksi nonce
voi olla iso satunnainen kokonaisluku.
Oletetaan, että MetaMask on läsnä, käyttöliittymämme JavaScript-koodissa meillä on pääsy window.web3
Siksi voimme soittaa web3.eth.coinbase
saadaksesi nykyisen MetaMask-tilin julkisen osoitteen.
Kun käyttäjä napsauttaa kirjautumispainiketta, käynnistämme sovellusliittymäkutsun takapäähän saadaksesi julkiseen osoitteeseensa liittyvän noncen. Jotain reittiä suodatinparametrilla GET /api/users?publicAddress=${publicAddress}
Pitäisi tehdä. Tietenkin, koska tämä on todentamaton API-kutsu, takapää tulisi konfiguroida näyttämään vain julkista tietoa (mukaan lukien nonce
) tällä reitillä.
Jos edellinen pyyntö ei palauta tulosta, se tarkoittaa, että nykyinen julkinen osoite ei ole vielä rekisteröitynyt. Meidän on ensin luotava uusi tili POST /users
kautta, välittämällä publicAddress
pyynnön esittävässä elimessä. Toisaalta, jos tulos on, tallennamme sen nonce
.
Kun käyttöliittymä vastaanottaa nonce
edellisen API-kutsun vastauksessa se suorittaa seuraavan koodin:
web3.personal.sign(nonce, web3.eth.coinbase, callback);
Tämä kehottaa MetaMaskia näyttämään vahvistusikkunan viestin allekirjoittamista varten. Nonce näkyy tässä ponnahdusikkunassa, jotta käyttäjä tietää, ettei hän allekirjoita haitallisia tietoja.
Kun hän hyväksyy sen, soittopyyntö kutsutaan allekirjoitetulla viestillä (kutsutaan signature
) argumenttina. Käyttöliittymä soittaa sitten toisen API-kutsun POST /api/authentication
: lle ja kulkee rungon molempien signature
kanssa ja publicAddress
.
Kun takapää saa POST /api/authentication
pyynnön, se hakee ensin käyttäjän tietokantaan, joka vastaa publicAddress
pyynnön antaneessa elimessä. Erityisesti se hakee siihen liittyvän nonce.
Ottaa nonce, julkinen osoite ja allekirjoitus, takapää voi sitten varmista salaus että käyttäjä on allekirjoittanut nonce-tiedoston oikein. Jos näin on, käyttäjä on todistanut julkisen osoitteen omistajuuden, ja voimme pitää häntä todennettuna. JWT- tai istuntotunniste voidaan sitten palauttaa käyttöliittymään.
Estämme käyttäjää kirjautumasta sisään uudestaan samalla allekirjoituksella (jos se vaarantuu), varmistamme, että seuraavan kerran, kun sama käyttäjä haluaa kirjautua sisään, hänen on allekirjoitettava uusi käyttöoikeus. Tämä saavutetaan generoimalla toinen satunnainen nonce
tälle käyttäjälle ja säilyttämällä sen tietokantaan.
Ja sinä menet! Näin hallitsemme ei-allekirjoittavan salasanattoman kirjautumisvirran.
Todennus on määritelmän mukaan oikeastaan vain todiste tilin omistajuudesta. Jos tunnistat tilisi yksilöllisesti julkisella osoitteella, on salauksen kannalta triviaalia todistaa, että omistat sen.
Estääksemme tapauksen, jossa hakkeri saa käsiinsä yhden tietyn viestin ja allekirjoituksesi (mutta ei todellista yksityistä avainta), pakotamme viestin allekirjoittamaan:
Muutimme sitä jokaisen onnistuneen kirjautumisen jälkeen selityksessämme, mutta myös aikaleimapohjainen mekanismi voitaisiin kuvitella.
Tässä osassa käyn läpi kuusi yllä olevaa vaihetta yksitellen. Näytän joitain koodinpätkiä siitä, miten voimme luoda sisäänkirjautumisvirran tyhjästä tai integroida sen olemassa olevaan käyttöliittymään ilman liikaa vaivaa.
Loin pienen esittelysovelluksen tätä artikkelia varten. Pino, jota käytän, on seuraava:
Yritän käyttää niin vähän kirjastoja kuin pystyn. Toivon, että koodi on riittävän yksinkertainen, jotta voit helposti siirtää sen muihin teknisiin pinoihin.
Koko projekti voidaan nähdä tämä GitHub-arkisto . Demo isännöi tässä .
Kaksi kenttää vaaditaan: publicAddress
ja nonce
. Alustamme nonce
satunnaiseksi suureksi luvuksi. Tämä numero on muutettava jokaisen onnistuneen kirjautumisen jälkeen. Lisäsin myös valinnaisen username
kenttä, jota käyttäjä voi muuttaa.
const User = sequelize.define('User', { nonce: { allowNull: false, type: Sequelize.INTEGER.UNSIGNED, defaultValue: () => Math.floor(Math.random() * 1000000) // Initialize with a random nonce }, publicAddress: { allowNull: false, type: Sequelize.STRING, unique: true, validate: { isLowercase: true } }, username: { type: Sequelize.STRING, unique: true } });
Yksinkertaisuuden vuoksi asetin publicAddress
kenttä pieninä kirjaimina. Tarkempi toteutus lisäisi vahvistusfunktion tarkistamaan, että kaikki täällä olevat osoitteet ovat kelvolliset Ethereum-osoitteet .
Tämä tehdään defaultValue()
toiminto yllä olevassa mallimääritelmässä.
Seuraava askel on lisätä joitain kattilakoodeja takaosaan CRUD-menetelmien käsittelemiseksi User
mallia, jota emme tee täällä.
Siirtyminen käyttöliittymäkoodiin, kun käyttäjä napsauttaa kirjautumispainiketta, handleClick
käsittelijä tekee seuraavaa:
class Login extends Component { handleClick = () => { // --snip-- const publicAddress = web3.eth.coinbase.toLowerCase(); // Check if user with current publicAddress is already present on back end fetch(`${process.env.REACT_APP_BACKEND_URL}/users?publicAddress=${publicAddress}`) .then(response => response.json()) // If yes, retrieve it. If no, create it. .then( users => (users.length ? users[0] : this.handleSignup(publicAddress)) ) // --snip-- }; handleSignup = publicAddress => fetch(`${process.env.REACT_APP_BACKEND_URL}/users`, { body: JSON.stringify({ publicAddress }), headers: { 'Content-Type': 'application/json' }, method: 'POST' }).then(response => response.json()); }
Täältä haemme aktiivisen MetaMask-tilin web3.eth.coinbase
: lla. Sitten tarkistamme, onko tämä publicAddress
on jo läsnä tai ei takana. Joko haemme sen, jos käyttäjä on jo olemassa, tai jos ei, luomme uuden tilin handleSignup
menetelmä.
Siirrytään eteenpäin handleClick
-sivullamme menetelmä. Meillä on nyt hallussamme käyttöliittymän antama käyttäjä (onko se haettu vai uusi). Erityisesti meillä on heidän nonce
ja publicAddress
. Joten olemme valmiita allekirjoittamaan nonce tähän publicAddress
liittyvällä yksityisellä avaimella käyttämällä web3.personal.sign
. Tämä tehdään handleSignMessage
toiminto.
Huomaa, että web3.personal.sign
ottaa merkkijonon heksadesimaalin esityksen ensimmäisenä argumenttinaan. Meidän on muunnettava UTF-8-koodattu merkkijonomme hex-muotoon käyttämällä web3.fromUtf8
Sen lisäksi, että allekirjoitin vain nonce, päätin allekirjoittaa käyttäjäystävällisemmän lauseen, koska se näkyy MetaMask-vahvistusikkunassa: I am signing my once-time nonce: ${nonce}
.
class Login extends Component { handleClick = () => { // --snip-- fetch(`${process.env.REACT_APP_BACKEND_URL}/users?publicAddress=${publicAddress}`) .then(response => response.json()) // If yes, retrieve it. If no, create it. .then( users => (users.length ? users[0] : this.handleSignup(publicAddress)) ) // Popup MetaMask confirmation modal to sign message .then(this.handleSignMessage) // Send signature to back end on the /auth route .then(this.handleAuthenticate) // --snip-- }; handleSignMessage = ({ publicAddress, nonce }) => { return new Promise((resolve, reject) => web3.personal.sign( web3.fromUtf8(`I am signing my one-time nonce: ${nonce}`), publicAddress, (err, signature) => { if (err) return reject(err); return resolve({ publicAddress, signature }); } ) ); }; handleAuthenticate = ({ publicAddress, signature }) => fetch(`${process.env.REACT_APP_BACKEND_URL}/auth`, { body: JSON.stringify({ publicAddress, signature }), headers: { 'Content-Type': 'application/json' }, method: 'POST' }).then(response => response.json()); }
Kun käyttäjä on allekirjoittanut viestin onnistuneesti, siirrymme handleAuthenticate
-sivulle menetelmä. Lähetämme yksinkertaisesti pyynnön /auth
reitti takana, lähettämällä publicAddress
samoin kuin signature
käyttäjän juuri allekirjoittamasta viestistä.
Tämä on hieman monimutkaisempi osa. Taustapää saa pyynnön /auth
reitti, joka sisältää publicAddress
ja a signature
, ja sen on tarkistettava, onko tämä publicAddress
on allekirjoittanut oikean nonce
.
Ensimmäinen vaihe on hakea käyttäjä tietokannasta mainitulla publicAddress
; on vain yksi, koska määritimme publicAddress
ainutlaatuisena kenttänä tietokannassa. Sitten asetamme viestin msg
'Olen allekirjoittamassa…', aivan kuten vaiheen 4 käyttöliittymässä, tämän käyttäjän kanssa.
Seuraava lohko on itse todentaminen. Siellä on jonkin verran salausta. Jos sinusta tuntuu seikkailunhaluiselta, suosittelen lukemaan lisää elliptisen käyrän allekirjoitukset .
Yhteenvetona tästä lohkosta, mitä se tekee, on msg
(sisältää nonce
) ja signature
, ecrecover
funktio tuottaa julkisen osoitteen, jota käytetään allekirjoittamaan msg
. Jos se vastaa publicAddress
pyynnön rungosta, sitten pyynnön tehnyt käyttäjä osoitti onnistuneesti omistavansa publicAddress
Pidämme niitä todennettuina.
User.findOne({ where: { publicAddress } }) // --snip-- .then(user => { const msg = `I am signing my one-time nonce: ${user.nonce}`; // We now are in possession of msg, publicAddress and signature. We // can perform an elliptic curve signature verification with ecrecover const msgBuffer = ethUtil.toBuffer(msg); const msgHash = ethUtil.hashPersonalMessage(msgBuffer); const signatureBuffer = ethUtil.toBuffer(signature); const signatureParams = ethUtil.fromRpcSig(signatureBuffer); const publicKey = ethUtil.ecrecover( msgHash, signatureParams.v, signatureParams.r, signatureParams.s ); const addressBuffer = ethUtil.publicToAddress(publicKey); const address = ethUtil.bufferToHex(addressBuffer); // The signature verification is successful if the address found with // ecrecover matches the initial publicAddress if (address.toLowerCase() === publicAddress.toLowerCase()) { return user; } else { return res .status(401) .send({ error: 'Signature verification failed' }); } })
Onnistuneen todennuksen jälkeen käyttöliittymä luo JWT: n ja lähettää sen takaisin asiakkaalle. Tämä on klassinen todennustapa ja koodi JWT: n integroimiseksi käyttöliittymään löydät reposta .
Viimeinen vaihe on muuttaa ei-turvallisuussyistä. Lisää jostain onnistuneen todennuksen jälkeen tämä koodi:
// --snip-- .then(user => { user.nonce = Math.floor(Math.random() * 1000000); return user.save(); }) // --snip--
Se ei ollut niin vaikeaa, vai mitä? Jälleen kerran, jos haluat nähdä, kuinka koko sovellus on kytketty (JWT-sukupolvi, CRUD-reitit, localStorage jne.), Voit vapaasti katsoa GitHub-repo .
Vaikka estoketjulla voi olla puutteita ja se on vielä lapsenkengissä, en voi korostaa tarpeeksi, miten tämä kirjautumisvirta voitaisiin toteuttaa millä tahansa olemassa olevalla verkkosivustolla tänään . Tässä on luettelo argumenteista, miksi tämä kirjautumisvirta on parempi kuin molemmat sähköpostiosoitteet / salasanat ja sosiaaliset kirjautumistiedot:
Tietysti MetaMask-kirjautumisvirtaa voidaan käyttää hyvin rinnakkain muiden perinteisten kirjautumistapojen kanssa. Jokaisen tilin ja sen hallussa olevan julkisen osoitteen välillä on tehtävä kartoitus.
Mutta tämä kirjautumisvirta ei sovi kaikille:
web3
-yhteensopivaa selainta. Jos yleisösi ei ole kiinnostunut kryptovaluutoista, on pieni mahdollisuus, että he jopa harkitsisivat MetaMaskin asentamista. Äskettäisen salausbuumin myötä toivotaan, että olemme menossa kohti a Web 3.0 Internet .Kuten olemme nähneet, web3
on edellytys tälle kirjautumisvirralle. MetaMask pistää sen työpöydän selaimissa. Mobiiliselaimissa ei kuitenkaan ole laajennuksia, joten tämä sisäänkirjautumisvirta ei toimi valmiina mobiilisafarilla, Chromella tai Firefoxilla. On joitain erillisiä mobiiliselaimia, jotka pistävät web3
—periaatteessa selaimeen kääritty MetaMask. Ne ovat melko varhaisessa vaiheessa tästä kirjoituksesta, mutta jos olet kiinnostunut, tutustu Salaus , Tila ja Toshi . 'Sisäänkirjautuminen MetaMaskilla' toimii näillä mobiiliselaimilla.
Mobiilisovellusten osalta vastaus on kyllä, sisäänkirjautumisvirta toimii, mutta valmistautumista on paljon. Pohjimmiltaan sinun on itse rakennettava yksinkertainen Ethereum-lompakko. Tämä sisältää julkisen osoitteen luomisen, siemensanan palauttamisen ja suojatun yksityisen avaimen tallennuksen sekä web3.personal.sign
ja vahvistusikkuna. Onneksi on olemassa kirjastoja, jotka auttavat sinua. Keskeinen alue, johon on keskityttävä, on tietysti turvallisuus, koska sovelluksessa itsessään on yksityinen avain. Pöytäselaimissa delegoimme tämän tehtävän MetaMaskille.
Joten väittäisin, että lyhyt vastaus on ei, tämä kirjautumisvirta ei toimi tänään matkapuhelimessa. Vaivaa pyritään tähän suuntaan, mutta helppo ratkaisu on edelleen rinnakkainen perinteinen kirjautumistapa matkapuhelinkäyttäjille.
Esitimme tässä artikkelissa yhdellä napsautuksella salatun ja turvallisen kirjautumisvirran, johon ei liity kolmatta osapuolta, nimeltään 'Kirjaudu sisään MetaMaskilla'. Selitimme, kuinka taustapohjaisen satunnaisen ei-digitaalisen allekirjoituksen avulla voidaan todistaa tilin omistajuus ja tarjota siten todennus. Tutkimme myös tämän kirjautumismekanismin kompromisseja perinteisiin sähköposti- / salasana- tai sosiaalisiin kirjautumistunnuksiin verrattuna sekä työpöydällä että mobiililaitteella.
Vaikka tällaisen kirjautumisvirran kohdeyleisö on edelleen pieni, toivon vilpittömästi, että jotkut teistä tuntevat innoitusta tarjota sisäänkirjautumista MetaMaskilla omassa verkkosovelluksessanne rinnakkain perinteisiin kirjautumisvirtoihin - ja haluaisin kuulla siitä jos sinä teet. Jos sinulla on kysyttävää, ota rohkeasti yhteyttä alla oleviin kommentteihin.
Liittyvät: Ultimate ENS ja ĐApp-opetusohjelma