Aðgangsstýrðar vefþjónustur

Hvernig á að vinna með vefþjónustur sem krefjast aðgangslykils: geyma lykla utan Git, lesa þá úr umhverfisbreytum og frysta niðurstöður sem má endurbyggja síðar.

Lyklar fara aldrei í Git

Margar þjónustur krefjast aðgangslykils (e. API key eða token). Lykill er lykilorð: sá sem hefur hann getur gert allt sem þú mátt gera, í þínu nafni.

MikilvægtÞetta eru algengustu alvarlegu mistökin
# ALDREI SVONA
svar <- request("https://api.example.is/gogn") |>
  req_headers(Authorization = "Bearer LYKILLINN-MINN") |>
  req_perform()

Lykillinn er nú í kóðanum. Committirðu skránni er hann í Git-sögunni — og hann er þar áfram þótt þú eyðir línunni síðar, því sagan geymir allar útgáfur. Geymslur eru vaktaðar af sjálfvirkum skanna og lyklar sem lenda í opnum geymslum eru misnotaðir á mínútum.

Rétta leiðin er að geyma lykilinn í umhverfisbreytu utan geymslunnar. Í R er það .Renviron:

# ~/.Renviron  — eða .Renviron í rót verkefnisins
GITHUB_TOKEN=<lykillinn-thinn-hingad>
AthugasemdStaðgengill, ekki alvöru lykill

Raunverulegur GitHub-lykill byrjar á ghp_ og er 40 stafir. Slíkur strengur er hér vísvitandi ekki notaður, jafnvel sem dæmi: leyndarmálaskannar leita að því sniði og myndu flagga skjölunina. Notaðu sama hátt í þínum eigin dæmum og README-skrám.

Endurræstu R og lestu hann með Sys.getenv():

token <- Sys.getenv("GITHUB_TOKEN")

svar <- request("https://api.github.com/user/repos") |>
  req_auth_bearer_token(token) |>
  req_perform()

Kóðinn ber engan lykil og má fara á GitHub. Sé .Renviron í verkefnismöppunni verður hún að vera í .gitignore:

# .gitignore
.Renviron
.env

ÁbendingHafi lykill lekið

Ekki reyna að fjarlægja hann úr sögunni fyrst. Afturkallaðu hann strax hjá þjónustunni og búðu til nýjan — það gerir gamla lykilinn gagnslausan á augabragði. Að hreinsa Git-söguna er seinna verk og skiptir minna máli.

Sjá einnig öryggi á GitHub.

Dæmi: TMDB

TMDB (The Movie Database) er gott dæmi um þjónustu sem krefst lykils. Lykillinn er ókeypis fyrir persónuleg verkefni — þú sækir um hann, staðfestir að notkunin sé ekki í viðskiptaskyni, og færð hann samstundis.

Sæktu lykilinn á developer.themoviedb.org og settu hann í .Renviron (R) eða .env (Python) — aldrei í kóðann.

library(httr2)

myndir <- request("https://api.themoviedb.org/3/search/movie") |>
  req_url_query(query = "Sódóma Reykjavík") |>
  req_auth_bearer_token(Sys.getenv("TMDB_TOKEN")) |>
  req_perform() |>
  resp_body_json(simplifyVector = TRUE)

myndir$results |>
  dplyr::select(title, release_date, vote_average)
Mikilvægt.Renviron er lesin við ræsingu

Tvennt sem eru líklegir villuvaldar:

R les .Renviron aðeins þegar hún ræsist. Bætirðu lykli við skrána meðan R er opin gerist ekkert — þú verður að endurræsa (í RStudio: Session → Restart R).

Skráin verður að vera í þeirri möppu sem R ræsist úr. Sé .Renviron í rót verkefnisins finnur R hana aðeins ef R ræsist þar — sem er sjálfgefið þegar unnið er í RStudio-verkefni. Viltu að lykillinn gildi alls staðar seturðu hann í ~/.Renviron í heimamöppunni þinni.

Athugaðu að hann hafi lesist áður en þú sendir beiðni:

nzchar(Sys.getenv("TMDB_TOKEN"))   # TRUE ef lykillinn er kominn inn
[1] FALSE

Skráin þarf líka að enda á línuskilum — annars sleppir R síðustu línunni þegjandi.

import os
import requests
import pandas as pd

svar = requests.get(
    "https://api.themoviedb.org/3/search/movie",
    params={"query": "Sódóma Reykjavík"},
    headers={"Authorization": "Bearer " + os.environ["TMDB_TOKEN"]},
    timeout=30,
)
svar.raise_for_status()

pd.json_normalize(svar.json()["results"])[["title", "release_date", "vote_average"]]

Í Python les python-dotenv skrána .env inn í os.environ:

pip install python-dotenv
from dotenv import load_dotenv
load_dotenv()          # les .env úr vinnumöppunni

Þegar lykilinn vantar

Þetta er fyrsta sem gerist hjá öllum, og málin tvö bregðast gjörólíkt við:

Sys.getenv("TMDB_TOKEN")
VarúðÞessi bútur má aldrei keyra

Hann prentar lykilinn. Væri hann keyrður á vél þar sem lykillinn er til staðar færi hann inn í úttak skjalsins — og það er í opinni geymslu. eval: false er hér öryggisráðstöfun, ekki þægindi.

Sama gildir um þinn eigin kóða: það sem búturinn prentar endar í skjalinu.

[1] ""

Sys.getenv() skilar tómum streng — engin villa, engin viðvörun. Beiðnin fer af stað með hausinn Authorization: Bearer og þjónustan svarar:

401 Invalid API key: You must be granted a valid key.

Villan bendir á lykilinn, en ekki á að hann hafi aldrei verið lesinn. Þess vegna borgar sig að athuga sjálf/ur:

token <- Sys.getenv("TMDB_TOKEN", unset = NA)
stopifnot(!is.na(token), nzchar(token))
import os
os.environ["TMDB_TOKEN"]
KeyError: 'TMDB_TOKEN'

Python stöðvar strax og segir nákvæmlega hvað vantar — engin beiðni fer af stað. Það er betri hegðun.

Í gagnvirkri lotu (REPL) lítur þetta þó verr út en það er. Fyrsta línan fellur, svar verður þar með aldrei til, og hver einasta lína á eftir fellur líka:

>>> svar = requests.get(..., headers={"Authorization": "Bearer " + os.environ["TMDB_TOKEN"]})
KeyError: 'TMDB_TOKEN'

>>> svar.raise_for_status()
NameError: name 'svar' is not defined

>>> pd.json_normalize(svar.json()["results"])
NameError: name 'svar' is not defined

Þrjár villur, eitt vandamál. Lestu alltaf fyrstu villuna — hinar eru bergmál af henni. NameError hér er ekki sjálfstæð villa heldur afleiðing þess að fyrsta skrefið tókst aldrei.

Viltu mýkri villuboð:

token = os.environ.get("TMDB_TOKEN")
if not token:
    raise SystemExit("TMDB_TOKEN vantar — settu hann í .env og keyrðu load_dotenv().")
MikilvægtÞögult tóm gildi er verra en villa

R-hegðunin er dæmi um nákvæmlega það sem varað er við annars staðar í þessum kafla: kóðinn heldur áfram með tómt gildi og villan kemur fram löngu síðar, á stað sem bendir í ranga átt. Athugaðu því alltaf að lykillinn hafi lesist áður en þú sendir beiðnina.

AthugasemdEf niðurstöður eru birtar úr lykilstýrðri þjónustu

Byggingarþjónninn hjá GitHub á ekki að fá kennaralykil eða nemendalykil. Ef þú vilt birta niðurstöður úr þjónustu eins og TMDB er örugga mynstrið að keyra sóknina á eigin vél, vista strípuð gögn í skrá og láta skýrsluna lesa þá skrá.

Þá fer lykillinn aldrei úr vélinni sem sótti gögnin. Það sem fer í geymsluna er kóðinn sem skýrir hvernig gögnin voru sótt og lítil gagnaskrá með því sem greiningin þarf — ekki umhverfisbreytan sjálf.

AðvörunSkilmálarnir eru hluti af samningnum

Þegar þú sækir um TMDB-lykil samþykkirðu að nota hann ekki í viðskiptaskyni. Það er raunveruleg kvöð, ekki formsatriði: lykillinn er afturkallaður sé hún brotin. Sama gildir um flestar þjónustur sem gefa ókeypis aðgang — lestu skilmálana áður en þú byggir verkefni á þeim.

TMDB krefst þess líka að getið sé heimildar þegar gögnin eru birt.

Aðgreindu lykla og gefðu lágmarksréttindi

Þegar þú býrð til lykil er oft hægt að velja hvað hann má og hve lengi hann gildir. Hér á eftir er farið yfir hvers vegna það skiptir máli og hvernig best er að gera það.

Hvers vegna lágmarksréttindi?

Veldu alltaf minnstu réttindi sem duga. Þetta kallast meginreglan um lágmarksréttindi (e. principle of least privilege). Gott er að hugsa um áhættuna af lykli sem tvo þætti sem margfaldast saman:

ÁbendingÁhætta lykils

áhætta ≈ líkur á að lykillinn leki × tjónið sem hægt er að valda með honum

Fyrri þættinum ræður þú aldrei alveg. Lykill getur lent í Git-sögu, skjáskoti, spjallskilaboðum eða úttaki skjals, eins og sýnt er hér að ofan. Seinni þættinum ræður þú hins vegar alveg, og það gerirðu á þeirri stundu sem þú býrð lykilinn til. Lesaðgangur að opnum gögnum sem lekur er óþægilegur. Lykill sem má eyða gögnum, skrifa í geymslur eða stofna til kostnaðar getur valdið raunverulegu tjóni.

Einn lykill, einn tilgangur

Aðgreining þýðir að nota ekki sama lykilinn alls staðar. Búðu frekar til sérstakan lykil fyrir hvern tilgang:

  • Hvern liðsmann. Hver og einn í hópnum sækir sinn eigin lykil og geymir hann í sinni eigin .Renviron eða .env. Lyklum er ekki deilt í spjalli eða tölvupósti.
  • Hvert verkefni. Lykillinn fyrir hópverkefnið á ekki að vera sá sami og þú notar í eigin tilraunir eða önnur námskeið.
  • Hvert umhverfi. Ef sjálfvirk keyrsla þarf lykil fær hún sinn eigin, ekki lykilinn af fartölvunni þinni.

Þetta borgar sig þegar eitthvað fer úrskeiðis:

  1. Þú getur afturkallað einn lykil án þess að brjóta allt hitt. Leki lykill eins liðsmanns þarf aðeins að skipta þeim lykli út. Aðrir í hópnum halda áfram að vinna.
  2. Þú sérð hvaðan notkunin kemur. Margar þjónustur sýna notkun og takmörk (e. rate limit) eftir lyklum. Hagi einn lykill sér undarlega veistu strax hvar á að leita.
  3. Hver lykill fær aðeins þau réttindi sem hlutverk hans krefst. Aðgreining gerir lágmarksréttindi mögulegar. Lykill sem á að þjóna öllu þarf að mega allt.

Gefðu lyklunum lýsandi nöfn þegar þjónustan leyfir, til dæmis idn302g-hopverkefni-lestur, svo auðvelt sé að sjá síðar hvaða lykil á að afturkalla.

Dæmi: fínstilltur GitHub-lykill

GitHub býður upp á fine-grained personal access tokens (undir Settings → Developer settings). Þar velurðu hvaða geymslur lykillinn nær til, hvaða réttindi hann hefur og hvenær hann rennur út:

Stilling Of víðtækt Lágmarksréttindi
Repository access All repositories Aðeins sú geymsla sem verkefnið þarf
Permissions Read and write á allt Aðeins það sem þarf, t.d. Contents: Read-only
Expiration No expiration Út önnina eða skemur

Leki lykill úr hægri dálkinum gefur hann aðeins lesaðgang að einni geymslu í takmarkaðan tíma. Leki lykill úr vinstri dálkinum getur sá sem finnur hann breytt eða eytt öllum geymslunum þínum þar til þú tekur eftir því.

Gildistími

Lykill án gildistíma er virkur þar til einhver man eftir að afturkalla hann, og það gleymist. Hópverkefnið klárast, önnin líður, en lykillinn liggur enn í gamalli .Renviron eða í Git-sögu einhvers staðar. Með gildistíma verður gleymdur lykill sjálfkrafa skaðlaus. Þegar hann rennur út býrðu einfaldlega til nýjan og setur hann í stað þess gamla.

Bjóði þjónustan ekki upp á gildistíma, eins og á við um suma ókeypis lykla, skaltu afturkalla lykilinn þegar verkefninu lýkur.

Lekur lykill þrátt fyrir allt gildir það sama og áður: afturkallaðu hann strax (sjá Hafi lykill lekið ofar á síðunni). Aðgreining og lágmarksréttindi breyta því ekki, en þau tryggja að tjónið sé lítið og að viðbrögðin séu einföld.

Gátlisti

Áður en þú notar nýjan lykil: