SSD Nodes Learn 🎉 VPS $5.50/నెల నుండి
మార్గదర్శకాలు Matt Connorద్వారా Matt Connor · అప్‌డేట్ చేయబడింది 2026-08-16

npm supply-chain attacks నుండి సర్వర్‌ను కాపాడుకోవడం ఎలా

npm ప్యాకేజీల ద్వారా మీ Node అప్లికేషన్‌పై జరిగే దాడులను ఎలా అడ్డుకోవాలి? malicious patch releases, typosquats మరియు postinstall scripts నుండి రక్షణ పొందే పద్ధతులను ఇక్కడ చూడండి.

npm supply-chain attack అంటే ఏమిటి మరియు అది మీ సర్వర్‌ను ఎలా ప్రభావితం చేస్తుంది

npm supply-chain attack అనేది మీరు ఇన్‌స్టాల్ చేయడానికి ఎంచుకున్న ప్యాకేజీ ద్వారా మీ సర్వర్‌కు చేరుకుంటుంది. ఇందులో ఎటువంటి open port లేదా exploit దశ ఉండదు. npm (node package manager) కోడ్‌ను ఇన్‌స్టాల్ చేస్తుంది, మరియు కోడ్‌ను ఇన్‌స్టాల్ చేయడం అంటే ఆ కోడ్‌ను రన్ చేయడం అని అర్థం. కాబట్టి, ఒక చిన్న Node అప్లికేషన్ మీరు ఎప్పుడూ చూడని వందలాది ప్యాకేజీలను డౌన్‌లోడ్ చేస్తుంది. వాటిలో ఏ ఒక్కటైనా సరే, గంట వ్యవధిలో కొత్త వెర్షన్‌ను విడుదల చేయగలదు.

మీరు రన్ చేసే ఇన్‌స్టాల్ కమాండ్ సరికొత్త వెర్షన్‌ను అడుగుతుంది కాబట్టి, మీ డిప్లాయ్‌మెంట్ ఒక హానికరమైన (malicious) వెర్షన్‌ను పొందుతుంది. ఆ కోడ్, ఇన్‌స్టాల్ కమాండ్‌ను ఎవరు రన్ చేశారో వారి అధికారాలతో (privileges) రన్ అవుతుంది. కింద పేర్కొన్నవన్నీ ఈ రెండు వాక్యాల నుండే ఉత్పన్నమవుతాయి.

ఒక వ్యక్తి ఒక Node అప్లికేషన్‌ను ఒక VPSలో డిప్లాయ్ చేస్తున్నప్పుడు, ఈ దాడులు జరిగే క్రమాన్ని బట్టి ఇక్కడ వివరించబడ్డాయి. పెద్ద కంపెనీలు అనుసరించే క్రమం ఇది కాదు, ఎందుకంటే పెద్ద కంపెనీలకు అంతర్గత రిజిస్ట్రీ, రివ్యూ టీమ్ మరియు పబ్లిక్ రిజిస్ట్రీ యొక్క మిర్రర్ ఉంటాయి. మీ దగ్గర ఉన్నది కేవలం ఒక డిప్లాయ్ స్క్రిప్ట్ మాత్రమే.

ఆకృతి 1: ఒక మెయింటైనర్ ఖాతా breached అవ్వడం మరియు ప్యాచ్‌ను విడుదల చేయడం

npm registry ఇప్పటికే ఉన్న వెర్షన్ యొక్క కంటెంట్‌ను మార్చడానికి ఎవరినీ అనుమతించదు. ఒక మెయింటైనర్‌ను ఫిషింగ్ ద్వారా మోసం చేసినా లేదా publish token దొంగిలించినా, దాడి చేసే వ్యక్తి 4.18.2 ను తిరిగి రాయలేడు. వారు 4.18.3 ను విడుదల చేస్తారు.

మీ package.json ను చూడండి. "express": "^4.18.2" వంటి లైన్ అంటే 4.18.2 వెర్షన్ అని కాదు. caret గుర్తు "ఈ వెర్షన్ లేదా అంతకంటే ఎక్కువ ఉన్న ఏదైనా 4.x వెర్షన్" అని అర్థం, మరియు ~4.18.2 అంటే "ఏదైనా 4.18.x" అని అర్థం. npm install ఆ range ను అది రన్ అయ్యే సమయంలోనే పరిష్కరిస్తుంది, కాబట్టి ఒకే git commit ను ఒకే మధ్యాహ్నం రెండుసార్లు deploy చేసినప్పుడు, రెండు వేర్వేరు కోడ్ సెట్‌లు ఇన్‌స్టాల్ అవ్వవచ్చు. ఆ వ్యత్యాసమే attack surface. అది తెరుచుకోవడానికి మీ మెషీన్‌లో ఏదీ compromised అవ్వాల్సిన అవసరం లేదు.

హానికరమైన releases సాధారణంగా రిపోర్ట్ చేయబడి తొలగించబడతాయి, కానీ ఆ తొలగింపు ప్రజలు వాటిని ఇన్‌స్టాల్ చేసిన తర్వాతే జరుగుతుంది. ఆ సమయంలో ఎవరైతే deploy చేశారో, వారి డిస్క్‌లో ఆ కోడ్ ఉంటుంది. ప్రతి రన్ సమయంలో ranges ను పరిష్కరించే pipeline, ఎవరూ నిర్ణయించకుండానే, వారానికి అనేకసార్లు ఆ window లోకి ఆటోమేటిక్‌గా ప్రవేశిస్తుంది.

రూపం 2: ఇన్‌స్టాల్ స్క్రిప్ట్ డిప్లాయ్ చేస్తున్న యూజర్ అనుమతులతో రన్ అవుతుంది

ఒక ప్యాకేజీ యొక్క package.json దాని scripts బ్లాక్‌లో preinstall, install, postinstall మరియు prepare లను ప్రకటించగలదు. npm వీటిని ఇన్‌స్టాలేషన్ సమయంలో రన్ చేస్తుంది. ఇవి శాండ్‌బాక్స్ చేయబడవు మరియు వీటిని ఎవరూ సమీక్షించరు. ఇవి ఇన్‌స్టాల్ కమాండ్ టైప్ చేసిన యూజర్ యొక్క హోమ్ డైరెక్టరీలో, ఆ యూజర్ యొక్క నెట్‌వర్క్ యాక్సెస్‌తో మరియు ఆ షెల్ యొక్క పూర్తి ఎన్విరాన్‌మెంట్‌తో రన్ అయ్యే షెల్ కమాండ్లు.

కాబట్టి, ప్యాకేజీ ఏమి చేయగలదు అనేది కాదు, ఆ యూజర్ దేనిని చదవగలడు అనేది అసలైన ప్రశ్న. సాధారణ డిప్లాయ్ బాక్స్‌లో, దీని సమాధానంలో రిజిస్ట్రీ టోకెన్‌ను కలిగి ఉన్న ~/.npmrc, SSH (secure shell) కోసం డిప్లాయ్ కీగా ఉపయోగించే ~/.ssh/id_ed25519, ~/.aws/credentials, ~/.docker/config.json, మరియు షెల్‌లో ఎక్స్‌పోర్ట్ చేయబడిన ప్రతి వేరియబుల్ ఉంటాయి; సాధారణంగా DATABASE_URL ఇక్కడే ఉంటుంది.

ఇలాంటి పేలోడ్‌కు పర్సిస్టెన్స్ లేదా ప్రివిలేజ్ ఎస్కలేషన్ అవసరం లేదు. ఇది కొన్ని ఫైళ్లను చదివి, వాటిని HTTPS ద్వారా ఒక హోస్ట్‌కు పంపి, 0 స్టేటస్‌తో ఎగ్జిట్ అవుతుంది. npm డిఫాల్ట్‌గా ఇన్‌స్టాల్-స్క్రిప్ట్ అవుట్‌పుట్‌ను దాచిపెడుతుంది కాబట్టి, మీకు ఏమీ కనిపించదు. దీన్ని ఆపివేసి, అసలు ఏమి రన్ అవుతుందో గమనించండి:

npm ci --foreground-scripts

foreground-scripts అనేది npm ప్రాసెస్‌తో స్టాండర్డ్ ఇన్‌పుట్, అవుట్‌పుట్ మరియు ఎర్రర్‌లను పంచుకుంటుంది. కాబట్టి, బిల్డ్ స్క్రిప్ట్‌లు ఇన్‌స్టాలేషన్ విజయవంతమైనప్పుడు npm తొలగించే బఫర్‌లోకి కాకుండా, నేరుగా మీ టెర్మినల్‌లోకి ప్రింట్ అవుతాయి.

రూపం 3: typosquats, మరియు మీరు సరిగ్గా టైప్ చేయని పేరు

Typosquat అనేది ఒక ప్రసిద్ధ ప్యాకేజీ పేరుకు దగ్గరగా ఉండే పేరుతో ప్రచురించబడిన ప్యాకేజీ. ఇది తప్పుగా టైప్ చేసిన లేదా కాపీ-పేస్ట్ చేసిన install కమాండ్ కోసం వేచి ఉంటుంది. దీనికి కారణం కమాండ్, కోడ్ కాదు. కాబట్టి, lockfile ఇక్కడ మీకు సహాయపడదు: మీరు ఒకసారి తప్పు పేరును జోడిస్తే, ఆ తర్వాత lockfile దానినే నమ్మకంగా పిన్ చేస్తుంది.

వ్యక్తుల కంటే టీమ్‌లను లక్ష్యంగా చేసుకునే మరొక రకం dependency confusion. మీ అంతర్గత ప్యాకేజీ పేరు billing-utils మరియు అది ఒక private registry లో ఉంటుంది. ఒకవేళ public registry లో billing-utils అనే పేరుతో ఏదీ లేకపోతే, ఎవరైనా దానిని ప్రచురించవచ్చు. npm అనేది unscoped పేర్లను డిఫాల్ట్ public registry లో వెతుకుతుంది, కాబట్టి public కాపీ గెలిచే అవకాశం ఉంది. దీనికి పరిష్కారం మీరు సొంతంగా ఒక scope ను కలిగి ఉండటం మరియు .npmrc లో ఆ scope కోసం registry mapping ను సెట్ చేయడం:

@yourorg:registry=https://npm.yourorg.example/
//npm.yourorg.example/:_authToken=${NPM_TOKEN}

ఇప్పుడు @yourorg/billing-utils ఎల్లప్పుడూ ఆ host నుండే వస్తుంది, ఎందుకంటే డిఫాల్ట్ registry కంటే ముందుగా scope-to-registry mapping ని పరిశీలిస్తారు. Unscoped అంతర్గత పేరుకు ఎటువంటి mapping ఉండదు, కాబట్టి దానికి ఎటువంటి రక్షణ ఉండదు.

ఏదైనా కొత్త dependency ని జోడించే ముందు, దాని download badge ను చూడటం కంటే దానిని క్షుణ్ణంగా పరిశీలించండి:

npm view some-lib repository.url maintainers time.created time.modified

గత నెలలో సృష్టించబడిన ప్యాకేజీ, మరియు మీరు ఏ public repository తోనూ అనుసంధానించలేని ఖాతా ద్వారా ప్రచురించబడిన ప్యాకేజీ, ఆరు సంవత్సరాల చరిత్ర ఉన్న ప్యాకేజీ కంటే భిన్నమైన ప్రమాదాన్ని కలిగి ఉంటుంది. ఏదీ కూడా పూర్తి భద్రతకు నిదర్శనం కాదు. రెండింటినీ తనిఖీ చేయడం సులభం.

రూపం 4: యజమాని నిశ్శబ్దంగా మారిన డిపెండెన్సీ

మెయింటైనర్లు ప్యాకేజీలను ఇతరులకు అప్పగిస్తుంటారు. ఒకరు అలసిపోయినప్పుడు, కొత్త వ్యక్తి సహాయం చేయడానికి ముందుకు వస్తారు, పబ్లిష్ చేసే హక్కులు మారుతాయి, కానీ దానిపై ఆధారపడిన ప్రాజెక్టులకు ఎటువంటి సమాచారం అందదు. ఏదీ రాజీ పడదు (compromise అవ్వదు). మీరు 2021లో ఉంచిన నమ్మకం ఇప్పుడు వేరే వ్యక్తి చేతుల్లో ఉంటుంది.

ఇది అత్యంత నెమ్మదిగా జరిగే మార్పు మరియు గుర్తించడం కష్టతరమైనది, దీనిని నేరుగా సమాధానపరిచే కమాండ్ ఏదీ లేదు. రెండు విషయాలు దీనిని పరిమితం చేస్తాయి. మీరు ఒక ప్యాకేజీని స్వీకరించే ముందు, పైన ఉన్న npm view లైన్‌తో ఎవరు పబ్లిష్ చేయగలరో తనిఖీ చేయండి. ఆపై మీరు నిజంగా ఆధారపడిన ప్యాకేజీ మారినప్పుడు diff ను చదవండి:

npm diff --diff-name-only --diff=some-lib@1.4.2 --diff=some-lib@1.4.3
npm diff --diff=some-lib@1.4.2 --diff=some-lib@1.4.3

మొదటి ఫార్మాట్ కేవలం మారిన ఫైల్ పేర్లను మాత్రమే ప్రింట్ చేస్తుంది, మీరు శ్రద్ధ వహించే ప్యాకేజీని ప్రతిసారీ అప్‌గ్రేడ్ చేసేటప్పుడు ఇది త్వరగా పూర్తవుతుంది. బిల్డ్ స్క్రిప్ట్‌ను మార్చే, ప్యాకేజీ రూట్‌లో ఒక ఫైల్‌ను జోడించే లేదా scripts బ్లాక్‌ను ఎడిట్ చేసే ప్యాచ్ రిలీజ్, మీ సర్వర్‌కు చేరకముందే పూర్తిగా చదవడం మంచిది.

npm ci తో కమిట్ చేసిన lockfile నుండి బిల్డ్ చేయడం

package-lock.json అనేది ట్రీలోని ప్రతి ప్యాకేజీ యొక్క ఖచ్చితమైన వెర్షన్, అది వచ్చిన URL, ప్రతి tarball యొక్క sha512 integrity hash, మరియు ఏ ప్యాకేజీ దానిని కోరిందో రికార్డ్ చేస్తుంది. దీనిని కమిట్ చేయండి. మీరు వాస్తవంగా పరీక్షించినది ఏమిటో చెప్పే ఏకైక ఫైల్ ఇదే.

ఆ తర్వాత, డెవలపర్ ల్యాప్‌టాప్ కాని ఏదైనా మెషీన్‌పై npm install కి బదులుగా, ఎల్లప్పుడూ npm ci తో ఇన్‌స్టాల్ చేయండి:

npm ci --omit=dev --ignore-scripts

npm ci మరియు npm install మధ్య ఉన్న తేడాలు ఇక్కడ చాలా ముఖ్యమైనవి. దీనికి lockfile తప్పనిసరిగా ఉండాలి. ఇది ప్రారంభానికి ముందే ఇప్పటికే ఉన్న node_modules ను తొలగిస్తుంది, కాబట్టి మునుపటి డిప్లాయ్‌మెంట్ నుండి మిగిలిపోయినవి ఇందులో ఉండవు. ఇది ఎప్పుడూ package.json లో లేదా lockfile లో మార్పులు చేయదు, కాబట్టి ఇన్‌స్టాలేషన్ ప్రక్రియ నిశ్శబ్దంగా మిమ్మల్ని కొత్త వెర్షన్‌కు తీసుకెళ్లదు. ఒకవేళ lockfile మరియు package.json మధ్య ఏవైనా విభేదాలు ఉంటే, అది సమస్యను పరిష్కరించడానికి ప్రయత్నించకుండా, ఎర్రర్‌తో ఆగిపోతుంది.

ఆ ఎర్రర్ ఒక ఇబ్బంది కాదు, అది ఒక ఫీచర్. దీని అర్థం డిపెండెన్సీలో మార్పు అనేది ఎవరైనా రివ్యూ చేసిన కమిట్ ద్వారానే రావాలి, అంతే తప్ప రాత్రి 02:00 గంటలకు జరిగే డిప్లాయ్‌మెంట్ యొక్క దుష్ప్రభావంగా రాకూడదు.

ప్రతి fetch సమయంలో integrity hash తనిఖీ చేయబడుతుంది. రికార్డ్ చేసిన hash తో సరిపోలని bytes ఉన్న tarball, అన్‌ప్యాక్ అవ్వడానికి బదులుగా code EINTEGRITY తో ఇన్‌స్టాల్‌ను విఫలం చేస్తుంది. దీని వల్ల మీకు కలిగే ప్రయోజనం ఏమిటో స్పష్టంగా తెలుసుకోండి: lockfile లో పిన్ చేసిన ఫైల్ మీకు అందిందని ఇది నిరూపిస్తుంది, ఇది checksums తో డౌన్‌లోడ్‌లను ధృవీకరించడం మీకు ఇచ్చే అదే హామీని ఇస్తుంది, మరియు ఇది అదే పరిమితులను కలిగి ఉంటుంది. పిన్ చేసిన వెర్షన్ పబ్లిష్ అయినప్పుడు హానికరమైనదా కాదా అనే దాని గురించి ఇది ఏమీ చెప్పదు.

--omit=dev గురించి ఒక ముఖ్యమైన విషయం: ఆ ప్యాకేజీలు ఇప్పటికీ రిజాల్వ్ చేయబడతాయి మరియు lockfile లో రాయబడతాయి. అవి కేవలం డిస్క్‌పై ఉంచబడవు. డిస్క్‌పై తక్కువ ప్యాకేజీలు ఉంటే తక్కువ ఇన్‌స్టాల్ స్క్రిప్ట్‌లు మరియు రన్‌టైమ్‌లో తక్కువ కోడ్ లోడ్ అవుతుంది, కాబట్టి ఇది చేయడం మంచిది. ఇది మీ ట్రీ నుండి డిపెండెన్సీని తొలగించదు.

ఇన్‌స్టాల్ స్క్రిప్ట్‌లను కోడ్‌గా పరిగణించండి మరియు వాటిని ఎలా నిరాకరించాలో తెలుసుకోండి

మీరు ఇన్‌స్టాల్ స్క్రిప్ట్‌లను నిలిపివేయవచ్చు. దీనిని ప్రాజెక్ట్ యొక్క .npmrc లో ఉంచి, లాక్‌ఫైల్‌తో పాటు కమిట్ చేయండి:

ignore-scripts=true
save-exact=true

ignore-scripts=true అనేది డిపెండెన్సీలలో పేర్కొన్న స్క్రిప్ట్‌లను npm రన్ చేయకుండా ఆపుతుంది. save-exact=true ద్వారా npm install some-lib అనేది ^1.4.2 కి బదులుగా 1.4.2 ను package.json లోకి రాస్తుంది, తద్వారా రిజాల్వింగ్ రేంజ్ పొరపాటున మీ మేనిఫెస్టోలోకి రాదు.

ఇది కొన్ని సేవలను విచ్ఛిన్నం చేస్తుంది, కాబట్టి మీరు దీన్ని ఎనేబుల్ చేసే ముందు దాని ప్రభావం ఎలా ఉంటుందో తెలుసుకోవాలి. నేటివ్ యాడ్-ఆన్‌ను కంపైల్ చేసే లేదా ప్రీ-బిల్ట్ బైనరీని డౌన్‌లోడ్ చేసే ప్యాకేజీలు ఆ పనిని ఇన్‌స్టాల్ స్క్రిప్ట్ ద్వారానే చేస్తాయి. స్క్రిప్ట్‌లు ఆపివేసినప్పుడు, ఇన్‌స్టాలేషన్ విజయవంతమవుతుంది కానీ, ఆ తర్వాత రన్‌టైమ్‌లో మాడ్యూల్ దాని బైండింగ్ ఫైల్‌ను లోడ్ చేయలేక విఫలమవుతుంది. దీనికి పరిష్కారం ఒక అలో-లిస్ట్ (allowlist):

npm ci --ignore-scripts
npm rebuild better-sqlite3

npm rebuild <package> ఆ ఒక్క ప్యాకేజీ కోసం బిల్డ్ స్క్రిప్ట్‌లను రన్ చేస్తుంది. మీరు ఎప్పుడూ కలవని వందలాది మంది అపరిచితులకు గుడ్డిగా ఎగ్జిక్యూట్ అనుమతులు ఇచ్చే బదులు, ఇప్పుడు మీరు ప్రతి ప్యాకేజీకి విడివిడిగా నిర్ణయం తీసుకుంటున్నారు.

ప్రస్తుతం ఈ అనుమతి ఎంత విస్తృతంగా ఉందో తెలుసుకోవడానికి, npm ని ఇలా అడగండి:

npm query ":attr(scripts, [postinstall])"

ఇది postinstall స్క్రిప్ట్‌ను కలిగి ఉన్న ఇన్‌స్టాల్ చేయబడిన ట్రీలోని ప్రతి ప్యాకేజీని ప్రింట్ చేస్తుంది. సాధారణ అప్లికేషన్‌లలో ఈ జాబితా ప్రజలు ఊహించిన దానికంటే తక్కువగానే ఉంటుంది, అందుకే అలో-లిస్ట్ పద్ధతిని అమలు చేయడం ఆచరణాత్మకం.

బిల్డ్ ప్రక్రియను మరియు ట్రాఫిక్‌ను అందించే ప్రక్రియను వేరు చేయండి

Deploy యూజర్‌కు node_modules లో వ్రాయాల్సిన అవసరం ఉంటుంది. కానీ HTTP అభ్యర్థనలను స్వీకరించే ప్రాసెస్‌కు ఆ అవసరం లేదు. ఈ రెండూ ఒకే అకౌంట్‌పై నడిస్తే, ఇన్‌స్టాలేషన్ సమయంలో రన్ అయ్యే కోడ్ మీ వినియోగదారులకు సేవలను అందించే కోడ్‌ను మార్చగలదు, అలాగే రన్‌టైమ్‌లో రన్ అయ్యే కోడ్ కూడా దానిని మార్చగలదు.

వీటిని వేరు చేయండి. ఒక యూజర్‌తో బిల్డ్ చేయండి, మరొక యూజర్‌తో సేవలను అందించండి, మరియు సేవలను అందించే అకౌంట్‌కు ఆ డైరెక్టరీని కేవలం చదవడానికి మాత్రమే (read-only) పరిమితం చేయండి:

sudo useradd --system --home-dir /srv/nodeapp --shell /usr/sbin/nologin nodeapp
sudo chown -R deploy:nodeapp /srv/nodeapp
sudo chmod -R o-rwx /srv/nodeapp

తరువాత systemd ద్వారా దీనిని అమలు చేయండి. /etc/systemd/system/nodeapp.service ను వ్రాయండి:

[Unit]
Description=Node application
After=network-online.target

[Service]
User=nodeapp
Group=nodeapp
WorkingDirectory=/srv/nodeapp/current
EnvironmentFile=/etc/nodeapp/env
ExecStart=/usr/bin/node server.js
Restart=on-failure

NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/srv/nodeapp/shared
NoExecPaths=/srv/nodeapp/shared
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

[Install]
WantedBy=multi-user.target

ProtectSystem=strict ఈ సర్వీస్ కోసం మొత్తం ఫైల్ సిస్టమ్‌ను read-onlyగా మారుస్తుంది, అయితే /dev, /proc, /sys మరియు మీరు ReadWritePaths లో పేర్కొన్నవి మినహాయింపుగా ఉంటాయి. కాబట్టి, అప్లికేషన్ node_modules లో వ్రాయడానికి ప్రయత్నిస్తే అది EROFS: read-only file system తో విఫలమవుతుంది, దీనిని మీరు ఒక నిమిషంలో మీ స్వంత లాగ్స్‌లో పరిశీలించవచ్చు. NoExecPaths అనేది వ్రాయదగిన అప్‌లోడ్ డైరెక్టరీని కవర్ చేస్తుంది: సర్వీస్ అక్కడ ఫైళ్లను వ్రాయగలదు కానీ కెర్నల్ వాటిని ఎగ్జిక్యూట్ చేయడానికి అనుమతించదు. ఈ ఆప్షన్ కోసం systemd 249 లేదా అంతకంటే కొత్త వెర్షన్ అవసరం, Ubuntu 24.04 లో 255 వెర్షన్ అందుబాటులో ఉంది.

ఈ యూనిట్ ఫైల్‌లో రెండు చిక్కులు ఉన్నాయి. మొదటిది, MemoryDenyWriteExecute=yes ను జోడించవద్దు. ఇది చాలా systemd హార్డెనింగ్ జాబితాలలో కనిపిస్తుంది, కానీ ఇది Node ప్రారంభం కాకుండా ఆపుతుంది, ఎందుకంటే V8 రన్‌టైమ్‌లో JavaScript ను మెషిన్ కోడ్‌గా కంపైల్ చేస్తుంది మరియు దానికి వ్రాయదగిన (writable) మరియు ఎగ్జిక్యూటబుల్ (executable) పేజీలు అవసరం. రెండవది, command -v node నుండి ExecStart పాత్‌ను తీసుకోండి. ఒకవేళ Node ను వెర్షన్ మేనేజర్‌తో ఇన్‌స్టాల్ చేసి ఉంటే, అది deploy యూజర్ హోమ్ డైరెక్టరీలో ఉంటుంది, అప్పుడు ProtectHome=yes ఆ డైరెక్టరీని సర్వీస్ నుండి దాచిపెడుతుంది, దీనివల్ల యూనిట్ వెంటనే status=203/EXEC తో విఫలమవుతుంది మరియు ఎగ్జిక్యూటబుల్ ఫైల్ దొరకలేదని లాగ్ లైన్ చూపిస్తుంది.

ఫైల్‌ను నమ్మే బదులు ఫలితాన్ని తనిఖీ చేయండి:

sudo systemctl daemon-reload
sudo systemctl enable --now nodeapp
sudo systemd-analyze security nodeapp.service
sudo -u nodeapp touch /srv/nodeapp/current/probe

systemd-analyze security ప్రతి హార్డెనింగ్ సెట్టింగ్‌ను దాని ఎక్స్‌పోజర్‌తో సహా జాబితా చేస్తుంది, కాబట్టి ఏవి ఇంకా డిఫాల్ట్ సెట్టింగ్‌లలో ఉన్నాయో మీరు చూడవచ్చు. nodeapp కు current కింద ఏమీ యాజమాన్యం లేదు కాబట్టి, touch అనేది Permission denied తో విఫలం కావాలి. ఒకవేళ అది విజయవంతమైతే, మీ ఫైల్ ఓనర్‌షిప్ తప్పుగా ఉందని మరియు systemd సెట్టింగ్‌లు దానిని కప్పిపుచ్చుతున్నాయని అర్థం.

EnvironmentFile గురించి ఒక గమనిక: systemd దీనిని User=nodeapp కి మారకముందే root గా చదువుతుంది, కాబట్టి ఆ ఫైల్ 600 మోడ్‌తో root:root గా ఉండవచ్చు. అప్లికేషన్ ఇప్పటికీ వేరియబుల్స్‌ను అందుకుంటుంది. nodeapp గా షెల్ యాక్సెస్ ఉన్న ఎవరైనా వాటిని /proc/<pid>/environ నుండి చదవగలరు, కాబట్టి ఇది రన్ అవుతున్న ప్రాసెస్‌ను కాకుండా, నిల్వ ఉన్న (at rest) రహస్య సమాచారాన్ని మాత్రమే రక్షిస్తుంది.

Deploy credentials ను build environment లో ఉంచవద్దు

Install scripts environment ను వారసత్వంగా పొందుతాయి. ఈ ఒక్క అంశమే మీరు ఎక్కడ build చేయాలో నిర్ణయించాలి.

అత్యంత సురక్షితమైన పద్ధతి ఏమిటంటే, production server కాని చోట build చేసి, పూర్తయిన directory ని అక్కడికి కాపీ చేయడం. అప్పుడు build machine వద్ద కేవలం read-only registry token మాత్రమే ఉంటుంది, మరేమీ ఉండదు. SSH deploy key, cloud access key, database password, లేదా container registry login వంటివి ఏవీ ఉండవు.

npm token create --read-only

Read-only token ప్యాకేజీలను డౌన్‌లోడ్ చేయగలదు కానీ publish చేయలేదు. ఒకవేళ ఇది build environment నుండి దొంగిలించబడినా, నష్టం కేవలం పబ్లిక్ ప్యాకేజీలను డౌన్‌లోడ్ చేసే సామర్థ్యానికి మాత్రమే పరిమితమవుతుంది.

ఒకవేళ మీరు తప్పనిసరిగా server పైనే build చేయాల్సి వస్తే, deploy user గా, ఉద్దేశపూర్వకంగా పరిమితం చేసిన environment తో build చేయండి. Runtime secrets ను /etc/nodeapp/env లో ఉంచండి, వీటిని deploy చదవలేదు. మీరు స్వయంగా హోస్ట్ చేసే build automation కు కూడా ఇదే తర్కం వర్తిస్తుంది: self-hosted GitHub Actions runner టోకెన్లను కలిగి ఉండి, ప్రతి job లోనూ బయటి కోడ్‌ను అమలు చేస్తుంది, ఇది చిన్న deployment లలో అత్యంత విలువైన machine గా మారుతుంది. మీరు రాయకుండా, మీ పూర్తి environment ను పొందే ఏ ప్రోగ్రామ్ అయినా ఇదే వర్గంలోకి వస్తుంది, అందుకే AI agent environment లో secrets లేకుండా చూడటం అనేది మధ్యలో వేరే ప్రోగ్రామ్ ఉన్న ఇదే సమస్య.

మీరు ఆడిట్ చేయలేని వాటిని పిన్ చేయండి లేదా వెండర్ చేయండి

పిన్ చేసిన డిపెండెన్సీ అంటే, కమిట్ చేయకుండా దాని వెర్షన్ మారదు. కమిట్ చేసిన lockfile ఇప్పటికే మొత్తం ట్రీ కోసం ఆ పనిని చేస్తుంది. అయితే రెండు సందర్భాల్లో అదనపు జాగ్రత్తలు అవసరం.

మొదటిది ట్రాన్సిటివ్ డిపెండెన్సీలు. మీ డిపెండెన్సీలు వేటిపై ఆధారపడతాయో మీరు నియంత్రించలేరు. overrides లోని package.json ట్రీలో ఎక్కడైనా ఒక వెర్షన్‌ను బలవంతంగా సెట్ చేస్తుంది:

{
  "overrides": {
    "some-transitive-lib": "1.4.2"
  }
}

దీనిని జోడించిన తర్వాత ఒక్కసారి npm install రన్ చేయండి, తద్వారా lockfile ఫలితాన్ని నమోదు చేస్తుంది, ఆపై రెండు ఫైళ్లను కమిట్ చేయండి.

రెండవ సందర్భం, మీరు ఆడిట్ చేయలేని మరియు వదిలించుకోలేని ప్యాకేజీ. దానిని వెండర్ చేయండి. npm pack రిజిస్ట్రీ అందించే ఖచ్చితమైన tarball ను డౌన్‌లోడ్ చేస్తుంది, మరియు file: డిపెండెన్సీ మీ కాపీ నుండి ఇన్‌స్టాల్ అవుతుంది:

npm pack some-lib@1.4.2
mkdir -p vendor && mv some-lib-1.4.2.tgz vendor/
{
  "dependencies": {
    "some-lib": "file:vendor/some-lib-1.4.2.tgz"
  }
}

ఇప్పుడు ఆ tarball మీ రిపోజిటరీలోనే ఉంటుంది మరియు మీ అనుమతి లేకుండా మారదు. దీని అప్‌డేట్‌ల బాధ్యత కూడా మీదే అవుతుంది, కాబట్టి దీనిని మీరు వదిలించుకోలేని చిన్న పాత ప్యాకేజీల కోసం మాత్రమే వాడండి, మీ వెబ్ ఫ్రేమ్‌వర్క్ కోసం కాదు.

అదనంగా, ఎటువంటి ఖర్చు లేని కూలింగ్-ఆఫ్ పీరియడ్ కూడా ఉంది:

npm install --before=2026-08-01

before ఆప్షన్ ఆ తేదీన లేదా అంతకు ముందు ప్రచురించబడిన వెర్షన్లను మాత్రమే ఉపయోగించి ట్రీని పునర్నిర్మిస్తుంది. మీరు డిపెండెన్సీలను రిఫ్రెష్ చేసేటప్పుడు దీనిని ఒకటి లేదా రెండు వారాల వెనక్కి సెట్ చేయండి. దీనివల్ల ఒక చెడు రిలీజ్ లైవ్‌లో ఉండి, ఇంకా రిపోర్ట్ అవ్వని సమయంలో మీరు దానికి దూరంగా ఉండవచ్చు. ఇది ఒక మొరటు పద్ధతి, ఎందుకంటే ఇది నిజమైన సెక్యూరిటీ ఫిక్స్‌లను కూడా ఆపివేస్తుంది. దీనిని రేంజ్‌లను పరిష్కరించడానికి వాడండి, ఏమేమి మారాయో చదవండి, ఆపై lockfile ను కమిట్ చేయండి.

నేను ఏ వెర్షన్‌ను విడుదల చేశానో నాకు ఎలా తెలుస్తుంది?

git లోని lockfile దేనిని ఇన్‌స్టాల్ చేయాలో చెబుతుంది. డిస్క్ దేనిని ఇన్‌స్టాల్ చేశామో చెబుతుంది. రెండవది మాత్రమే వాస్తవమైన సాక్ష్యం.

npm ls some-lib
node -e "console.log(require('./node_modules/some-lib/package.json').version)"

npm ls అనేది node_modules ను చదువుతుంది, కాబట్టి ఇది lockfile ఉద్దేశించిన దానికంటే భౌతికంగా ఏది ఉందో దానిని నివేదిస్తుంది. node -e లైన్ ఇన్‌స్టాల్ చేయబడిన మానిఫెస్ట్‌ను పాత్ ద్వారా చదువుతుంది. ఇది exports ఫీల్డ్ సబ్‌పాత్ ఇంపోర్ట్‌లను నిరోధించే ప్యాకేజీలకు కూడా పనిచేస్తుంది మరియు ఎటువంటి ట్రీ డ్రాయింగ్ లేకుండా ఒక వెర్షన్‌ను ప్రింట్ చేస్తుంది.

పోలికలో మిగిలిన సగం కోసం, git ని చదవండి:

git log --oneline -- package-lock.json
git show <commit>:package-lock.json | grep -A3 '"node_modules/some-lib"'

కమిట్‌ను deploy లేఅవుట్‌లో ఉంచడం ద్వారా రెండింటి మధ్య శాశ్వత అనుసంధానాన్ని ఏర్పరచండి. /srv/nodeapp/releases/<short commit sha> లోకి విడుదల చేయండి మరియు symlink తో /srv/nodeapp/current ని దాని వైపు మళ్లించండి. "ప్రస్తుతం ఏమి రన్ అవుతోంది" అనే ప్రశ్నకు సమాధానం readlink /srv/nodeapp/current అవుతుంది, మరియు ఇది డిప్లాయ్ చేసిన వ్యక్తి కాకుండా వేరే ఎవరికైనా 03:00 గంటలకు అందుబాటులో ఉంటుంది.

చివరగా, రిజిస్ట్రీ దేనిని ధృవీకరిస్తుందో తనిఖీ చేయండి:

npm audit signatures

ఇది మీ ఇన్‌స్టాల్ చేయబడిన ట్రీలోని ప్యాకేజీలపై రిజిస్ట్రీ సంతకాలను ధృవీకరిస్తుంది, మరియు ప్యాకేజీలకు ఉన్న provenance attestations ను కూడా తనిఖీ చేస్తుంది. Provenance అనేది పబ్లిష్ చేయబడిన tarball ను దానిని తయారు చేసిన పబ్లిక్ continuous integration (CI) బిల్డ్‌తో అనుసంధానిస్తుంది. కాబట్టి, ధృవీకరించబడిన attestation అంటే మీరు కోడ్‌ను తెలియని ల్యాప్‌టాప్‌కు కాకుండా, ఒక కమిట్‌కు తిరిగి ట్రేస్ చేయగలరని అర్థం. కవరేజ్ అన్నింటికీ ఉండదు, కాబట్టి attestation లేకపోతే దానిని "సమాచారం లేదు" అని అర్థం చేసుకోండి, "చెడు ప్యాకేజీ" అని కాదు.

ఒక తప్పు విడుదల (bad release) మీ సర్వర్‌కు చేరినప్పుడు ఏమి చేయాలి

ఏది రన్ అయింది మరియు ఏ యూజర్ ద్వారా రన్ అయింది అనే అంశాల నుంచి బయటకు వచ్చి విశ్లేషించండి.

ఇన్‌స్టాలేషన్ సమయంలో కోడ్ రన్ అయితే, బిల్డ్ యూజర్ చదవగలిగే ప్రతిదీ రాజీ పడిందని భావించండి. రిజిస్ట్రీ టోకెన్, ఆ హోమ్ డైరెక్టరీలోని SSH keys, క్లౌడ్ క్రెడెన్షియల్స్ మరియు ఆ షెల్‌లో ఎక్స్‌పోర్ట్ అయిన ప్రతి రహస్య సమాచారాన్ని (secret) మార్చండి (rotate). ఒక ఫైల్ చదవబడలేదని మీరు నిరూపించలేరు కాబట్టి, మార్పు చేయడమే ఏకైక సరైన పరిష్కారం.

లాక్-డౌన్ చేయబడిన సర్వీస్ అకౌంట్ కింద రన్‌టైమ్‌లో కోడ్ రన్ అయితే, అది చేరుకోగల పరిధి చాలా తక్కువ: అప్లికేషన్ యొక్క సొంత environment variables మరియు దాని నెట్‌వర్క్ యాక్సెస్ ద్వారా దేనిని చేరుకోగలదో అది మాత్రమే. VPSలో unprivileged యూజర్లుగా సర్వీసులను రన్ చేయడం వెనుక ఉన్న ప్రధాన ఉద్దేశ్యం ఇదే. ఇది రాజీ పడటాన్ని (compromise) అడ్డుకోదు. కానీ, ఆ రాజీ సర్వర్‌లో ఎంతవరకు ప్రభావం చూపుతుందో మరియు రీస్టార్ట్ తర్వాత కూడా అది కొనసాగుతుందో లేదో నిర్ణయిస్తుంది.

ఆ తర్వాత క్లీన్ చేయడానికి బదులుగా మళ్లీ బిల్డ్ చేయండి. node_modules ను తొలగించండి, package.json లో ప్రభావితమైన ప్యాకేజీని తప్పు వెర్షన్ కంటే తక్కువకు పిన్ చేయండి, లాక్‌ఫైల్‌ను అప్‌డేట్ చేయడానికి ఒకసారి npm install రన్ చేయండి, దానిని కమిట్ చేయండి మరియు npm ci తో డిప్లాయ్ చేయండి. ఉన్న ఫైల్ సిస్టమ్ ట్రీని అక్కడికక్కడే రిపేర్ చేయవద్దు. ఇన్‌స్టాల్ స్క్రిప్ట్ దేనిని తాకిందో మీరు పూర్తిగా గుర్తించలేరు.

అలాగే ఆ సమయాన్ని (window) నోట్ చేసుకోండి: ఆ వెర్షన్‌ను పొందే అవకాశం ఉన్న మొదటి డిప్లాయ్ మరియు దానిని తొలగించిన డిప్లాయ్. ఆ పరిధి మీ సొంత లాగ్స్‌లో దేనిని చదవాలో మీకు చెబుతుంది, మరియు మీ రిలీజ్‌లకు కమిట్స్ పేరు పెట్టినప్పుడు మాత్రమే దీనికి సమాధానం దొరుకుతుంది.

వీటిలో ఏదీ పరిష్కరించలేని సమస్యలు

ఒక lockfile ఉన్నంత మాత్రాన dependency సురక్షితం కాదు. ఇది మీరు ఒక dependencyని అంగీకరించిన క్షణాన్ని, deploymentలో అనుకోకుండా జరిగే పరిణామంలా కాకుండా, తేదీతో కూడిన మరియు సమీక్షించబడిన నిర్ణయంగా మారుస్తుంది. పైన పేర్కొన్న ప్రతి పద్ధతి ఇదే మార్పును చేస్తుంది: అంటే ప్రమాదవశాత్తు జరిగే వాటిని ఒక ఎంపికగా మారుస్తుంది.

npm audit ఇక్కడ రక్షణ కల్పించదు. ఇది మీ dependency treeని ఇప్పటికే నివేదించబడిన vulnerabilities డేటాబేస్‌తో పోల్చి చూస్తుంది, కాబట్టి ఇది ఇప్పటికే ప్రచురించబడిన మరియు గుర్తించబడిన సమస్యలను మాత్రమే కనుగొంటుంది. ఒక supply-chain attack దాని ఉపయోగకరమైన జీవితకాలం మొత్తం అజ్ఞాతంగానే ఉంటుంది. పాత తెలిసిన బగ్‌ల కోసం npm audit రన్ చేయండి, కానీ నాలుగు గంటల క్రితం విడుదలైన ఒక release గురించి దీని నుండి ఎటువంటి సమాచారం ఆశించవద్దు.

ఈ గైడ్‌లోని ఏ సాధనం కంటే కూడా మీ dependencyల సంఖ్యను తగ్గించుకోవడం ఎక్కువ సహాయపడుతుంది, కానీ ఎవరూ చెప్పని సలహాలలో ఇది అత్యంత అప్రజాదరణ పొందినది. మీరు జోడించని ప్రతి package, మీ తరపున ఫిషింగ్‌కు గురికాకుండా ఉండే ఒక ప్రచురణకర్తను మరియు మీ deploy userగా ఎప్పటికీ రన్ అవ్వని ఒక install scriptని తగ్గిస్తుంది.

ఇవేవీ కేవలం npmకి మాత్రమే పరిమితం కాదు. ఇదే నాలుగు రకాల పద్ధతులు PyPI, RubyGems, container images మరియు మీ distribution యొక్క package managerకి కూడా వర్తిస్తాయి. npmలో ఇవి ఎక్కువగా కనిపిస్తాయి, ఎందుకంటే అక్కడ dependency trees చాలా లోతుగా ఉంటాయి మరియు install scripts డిఫాల్ట్‌గా రన్ అవుతాయి. చుట్టూ ఉన్న యంత్రంలో ఎంత భాగాన్ని మీరు రక్షించుకోవాలి అనేది అది ఎక్కడ రన్ అవుతోంది అనే దానిపై ఆధారపడి ఉంటుంది, ఇది VPS హోస్టింగ్ సురక్షితమేనా అనే విస్తృత ప్రశ్నలో ఒక భాగం.

FAQ

npm ci నన్ను compromised npm package నుంచి రక్షిస్తుందా?

మీకు తెలియకుండానే వెర్షన్ మారకుండా ఇది మిమ్మల్ని రక్షిస్తుంది. npm ci, package-lock.json లో రికార్డ్ చేసిన దానినే ఖచ్చితంగా ఇన్‌స్టాల్ చేస్తుంది. ప్రతి tarball ను దాని sha512 integrity hash తో సరిచూస్తుంది. ఒకవేళ package.json మరియు lockfile మధ్య తేడాలు ఉంటే, వాటిని సరిచేయడానికి ప్రయత్నించకుండా, error తో ఆగిపోతుంది. అయితే, పిన్ చేసిన వెర్షన్ సురక్షితమేనా అనే దాని గురించి ఇది ఏమీ చెప్పదు. ఒకవేళ మీరు హానికరమైన వెర్షన్‌ను పిన్ చేసిన lockfile ను commit చేస్తే, npm ci ప్రతిసారీ మీ సర్వర్లలో ఆ వెర్షన్‌నే విశ్వసనీయంగా ఇన్‌స్టాల్ చేస్తుంది.

నేను అన్నింటికీ ignore-scripts=true సెట్ చేయాలా?

ముందుగా దీన్ని సెట్ చేసి, ఆపై allowlist ను ఉపయోగించండి. ప్రాజెక్ట్ యొక్క .npmrc లో ignore-scripts=true సెట్ చేయడం వల్ల dependency install scripts రన్ అవ్వవు. ఇది ఒక చెడు ప్యాకేజీ నుంచి మీ deploy user యొక్క credentials కు ఉన్న అత్యంత వేగవంతమైన మార్గాన్ని తొలగిస్తుంది. native addon ను compile చేసే లేదా prebuilt binary ని డౌన్‌లోడ్ చేసే ప్యాకేజీలకు నిజంగానే scripts అవసరం. scripts ఆపివేసినప్పుడు, అవి ఇన్‌స్టాల్ సమయంలో కాకుండా, రన్‌టైమ్ సమయంలో missing binding file తో విఫలమవుతాయి. npm ci --ignore-scripts రన్ చేయండి, ఆపై మీరు నమ్మదగినవిగా భావించే కొన్ని ప్యాకేజీల కోసం npm rebuild <package> వాడండి. నిజానికి ఎన్ని ప్యాకేజీలు ఉన్నాయో npm query ":attr(scripts, [postinstall])" చూపిస్తుంది.

నా సర్వర్‌లో ఒక ప్యాకేజీ ఏ వెర్షన్ ఇన్‌స్టాల్ అయిందో నేను ఎలా తెలుసుకోవాలి?

lockfile ను కాకుండా, డిస్క్‌ను చూడండి. node_modules లో ఏముందో npm ls <package> నివేదిస్తుంది, మరియు node -e "console.log(require('./node_modules/<package>/package.json').version)" కేవలం వెర్షన్ స్ట్రింగ్‌ను మాత్రమే ప్రింట్ చేస్తుంది. git లోని lockfile వేరే ప్రశ్నకు సమాధానం ఇస్తుంది, అంటే ఏమి ఇన్‌స్టాల్ అవ్వాలి అనేది అది చెబుతుంది. ఆ రెండింటినీ పోల్చి చూడటమే అసలైన ఉద్దేశ్యం. git commit పేరుతో ఉన్న డైరెక్టరీలో డిప్లాయ్ చేయడం వల్ల, నెలల తర్వాత అవసరమైనప్పుడు కూడా ఈ రెండు సమాధానాలు అందుబాటులో ఉంటాయి.

npm audit సప్లై-చైన్ దాడులను గుర్తిస్తుందా?

లేదు. npm audit మీ ట్రీని నివేదించబడిన vulnerabilities డేటాబేస్‌తో పోల్చుతుంది, కాబట్టి ఇది ఇప్పటికే ప్రచురించబడిన మరియు identifier పొందిన సమస్యలను మాత్రమే గుర్తిస్తుంది. ఒక హానికరమైన release ఇన్‌స్టాల్ చేయడం వల్ల నష్టం జరిగే గంటలు లేదా రోజుల్లో, అది నివేదించబడదు. npm audit signatures మరింత ఉపయోగకరమైన కమాండ్: ఇది మీ ఇన్‌స్టాల్ చేసిన ట్రీ అంతటా registry signatures ను ధృవీకరిస్తుంది మరియు పబ్లిషర్ అందించిన provenance attestations ను తనిఖీ చేస్తుంది. దీని ద్వారా ఒక tarball తెలియని మెషీన్ నుంచి కాకుండా, పబ్లిక్ బిల్డ్ నుంచి వచ్చిందని తెలుస్తుంది.

ఇన్‌స్టాల్ సమయంలోనే దాడి జరిగితే, అప్లికేషన్‌ను unprivileged user గా రన్ చేయడం ఎందుకు ముఖ్యం?

ఎందుకంటే ఈ రెండు వైఫల్యాలకు వేర్వేరు పరిధి ఉంటుంది మరియు మీరు రెండింటి నుంచీ రక్షణ పొందాలి. ఇన్‌స్టాల్ సమయంలో రన్ అయ్యే కోడ్ deploy user గా పనిచేస్తుంది, కాబట్టి అది ఆ యూజర్ యొక్క SSH keys, registry tokens మరియు cloud credentials ను చదవగలదు. రన్‌టైమ్ కోడ్ service account గా రన్ అవుతుంది. User=nodeapp, ProtectSystem=strict మరియు డిస్క్‌పై చదవగలిగే credentials ఏవీ లేకపోవడం వల్ల, దాని పరిధి అప్లికేషన్ యొక్క environment మరియు దాని డేటాబేస్‌కే పరిమితమవుతుంది. ఈ ఖాతాలను వేరు చేయడం వల్ల, ట్రాఫిక్‌ను సర్వ్ చేసే ప్రాసెస్ node_modules ను తిరిగి రాయలేదు. కాబట్టి, రన్‌టైమ్ compromise అనేది శాశ్వతం కాకుండా, తదుపరి రీస్టార్ట్‌తో తొలగిపోతుంది.