Kokeneelle kehittäjälle tämä teksti ei ehkä ole lainkaan yllättävä, mutta mielestäni monissa Railsin CORS-asetuksista lukemissani artikkeleissa sanottiin jotain sellaista kuin: käytä rack-corsia, salli minkä tahansa isännän käyttää API:ta ja (valinnaisesti): sinun pitäisi harkita jotain muuta (kuin minkä tahansa isännän sallimista) tuotannossa.
Ehdotettu koodi oli aina lähellä alla olevaa:
config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins ''
resource '', headers: :any, methods: :any
end
end
ja valitettavasti näissä teksteissä tuskin selitettiin meille, mitä tuotannossa pitäisi oikeastaan tehdä.
Olen melko hyvä kopioimaan ja liittämään (Joskus vitsailen, että yritykset voisivat palkata Stack Overflow'n copy-pasterin.), sikäli kuin "kopioi" ja "liitä" välillä on "mieti ja säädä" -hetki. Haluaisin siis hieman tarkentaa, mitä teemme täällä ja miten se toimii tosielämässä.
Toivottavasti et pahastu siitä, että aloitan lyhyellä johdannolla kunnian teoriaan ja siirryn sitten Rails-esimerkkeihin.
Johdanto
Aloitetaan alusta. Selittääkseni asiat paremmin olen jakanut johdannon kolmeen osaan. Ensimmäisessä osassa hahmotellaan, mikä on alkuperä - keskeinen termi sille, mistä tässä keskustelemme. Toinen osa käsittelee SOP:ia, vain lyhyt kuvaus. Ja viimeisessä osassa puhutaan CORS
itse.
Mikä on alkuperä?
MDN:n verkkodokumenttien mukaan:
- Verkkosisällön alkuperä määritellään URL-osoitteen protokollan (scheme), isännän (domain) ja portin perusteella. Kahdella objektilla on sama alkuperä vain, jos järjestelmä, isäntä ja portti ovat kaikki samat (lähde)
Eikö se vaikuta aika selvältä? Analysoidaanpa varmuuden vuoksi kaksi esimerkkiä MDN:stä.
http://example.com/app1/index.html
, http://example.com/app2/index.html
Edellä olevat 2 ovat samaa alkuperää, koska:
- niiden järjestelmät (http) ovat samat,
- niiden verkkotunnukset (example.com) ovat samat,
- niiden portit (implisiittiset) ovat samat.
http://www.example.com
, http://myapp.example.com
Näillä kahdella on erilainen alkuperä, koska verkkotunnukset (www.example.com
, myapp.example.com
) ovat erilaisia.
Toivottavasti se on tarpeeksi selvää. Jos ei, katso lisää esimerkkejä MDN:n verkkodokumenteista.
Mikä on SOP?
MDN Web Docs sanoo (lähde):
- Saman alkuperän käytäntö on tärkeä turvamekanismi, joka rajoittaa sitä, miten yhdestä alkuperästä ladattu asiakirja tai komentosarja voi olla vuorovaikutuksessa toisen alkuperän resurssin kanssa. Se auttaa eristämään mahdollisesti haitalliset asiakirjat ja vähentää mahdollisia hyökkäysväyliä.
- Cross-origin-kirjoitukset ovat yleensä sallittuja. Esimerkkejä ovat linkit, uudelleenohjaukset ja lomakkeiden lähettäminen.
- Cross-origin upottaminen on yleensä sallittua.
- Alkuperän rajat ylittävä lukeminen ei yleensä ole sallittua, mutta lukuoikeudet vuotavat usein sulauttamalla.
Käytä CORS
sallia cross-origin access
Kuten huomaat, SOP:n määritelmissä on paljon tietoa alkuperän rajat ylittävästä käyttäytymisestä. Se ei haittaa. Meidän pitäisi nyt vain tietää, että samalla alkuperällä on enemmän oikeuksia ja voimme löysätä ristikkäisalkuperää koskevia sääntöjä käyttämällä CORS:ää. Ja tässä tulee seuraava osio.
Mikä on CORS?
MDN:n sanojen perusteella:
- CORS (Cross-Origin Resource Sharing) on HTTP-otsikkoon perustuva mekanismi, jonka avulla palvelin voi ilmoittaa minkä tahansa muun alkuperän (verkkotunnus, järjestelmä tai portti) kuin omansa, josta selaimen pitäisi sallia resurssien lataaminen. CORS perustuu myös mekanismiin, jonka avulla selaimet tekevät "preflight"-pyynnön palvelimelle, joka isännöi ristikkäistä alkuperää olevaa resurssia, tarkistaakseen, että palvelin sallii varsinaisen pyynnön. Tässä preflight-pyynnössä selain lähettää otsikot, jotka osoittavat HTTP-menetelmän ja otsikot, joita käytetään varsinaisessa pyynnössä. (lähde).
Se ei silti riitä. Mitä ei sanottu siellä nimenomaisesti on, että tärkein otsikko käytettäessä CORS
on Access-Control-Allow-Origin
:
- The
Access-Control-Allow-Origin
vastausotsikko osoittaa, voidaanko vastaus jakaa tietyn alkuperän koodin kanssa (lähde).
No, sen pitäisi olla siinä. Todellisessa elämässä, kun konfiguroit CORS
, konfiguroimme tyypillisesti ACAO
otsikko ensin.
Todellinen elämä
Siinä kaikki, kun on kyse määritelmistä. Palataanpa takaisin Railsiin ja tosielämän esimerkkeihin.
Kuinka määrittää CORS Railsissa?
Käytämme ehdottomasti rack-corsia (kuten meille kerrottiin). Palautetaan mieleen ensimmäinen pätkä, joka on useimmiten esitetty muissa artikkeleissa:
config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins ''
resource '', headers: :any, methods: :any
end
end
Vaihtoehtojen määrä on valtava tai jopa ääretön, mutta tarkastellaanpa näitä kahta:
- rakennamme API:n, jota kolmannen osapuolen selainohjelmat voivat käyttää,
- meillä on tyypillinen frontend/backend-erottelu ja haluamme antaa luotettavien asiakkaidemme käyttää API:ta.
Kolmannen osapuolen asiakkaiden käyttämä API
Jos edessäsi on ensimmäinen vaihtoehto, voit luultavasti valita vaihtoehdon alkuperä
'*' - haluat, että muut rakentavat asiakkaan API:si päälle, etkä tiedä, keitä he ovat, eikö niin?
Tyypillinen frontend/backend-erottelu
Jos kehität jälkimmäistä, et luultavasti halua kaikkien tekevän ristikkäisiä pyyntöjä API:si. Haluat pikemminkin:
- sallia tuotantoasiakkaiden käyttää tuotannon API:ta,
- sama koskee lavastusta,
- sama koskee localhostia,
- saatat haluta sallia FE:n tarkistussovellusten pääsyn stagingiin.
Käytämme edelleen hammaskorsuja (kuten meitä kehotettiin) - mutta omalla tavallamme.
Käytetään 2 ENV-muuttujaa: ALLOWED_ORIGINS
kirjaimellisia alkuperämäärityksiä varten (tähti tai varsinainen URL-osoite) ja SALLITUT_ALKUPERÄ_REGEXPIT
kuvioita varten.
config/initializers/cors.rb
frozenstringliteral: true
toregexp = ->(string) { Regexp.new(string) }
hosts = [
*ENV.fetch('ALLOWEDORIGINS').split(','),
*ENV.fetch('ALLOWEDORIGINREGEXPS').split(';').map(&to_regexp)
]
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins(*hosts)
resurssi '*',
methods: %i[get post put patch delete options head],
headers: :any
end
end
Mitä täällä tapahtuu?
- Kuten näet, jaamme ENV-muuttujiin määritellyt arvot eri erottimilla. Tämä johtuu siitä, että puolipiste on epätodennäköisempi URL-osoitteen määrittelymallissa.
- Literaaliarvot ovat valmiita käytettäväksi, mutta meidän on kartoitettava mallit todellisiksi Regexp-olioiksi.
- Sitten yhdistämme kaiken yhteen ja annamme näiden isäntien käyttää mitä tahansa resurssia, jonka API käyttää valkoisen listan menetelmiä.
Tämän pitäisi antaa sinulle tarpeeksi joustavuutta määrittää oikeat arvot kehitys-, staging- ja tuotantoympäristöissäsi.
Päätelmät
Tiivistetään kaikki edellä mainitut asiat pääkohdittain:
- käyttää ENV-muuttujia konfigurointiin
CORS
,
- käyttää säännöllisiä lausekkeita, jotta eri alkuperät voivat käyttää staging APIa (esim. tarkistussovelluksia varten),
- laita aina "mieti ja säädä" "kopioi" ja "liitä" väliin.
Siinä kaikki. Hyvää päivänjatkoa! 🙂
Lue lisää:
Miksi sinun pitäisi (luultavasti) käyttää Typescriptiä?
10 mainitsemisen arvoista NYC-startupia vuonna 2021