ஒரு வரியிலான குறியீடு (code) உங்கள் முழு அணுகல் கட்டுப்பாட்டு மாதிரியையும் (access control model) சிதைத்துவிடக்கூடும். கோரிக்கை உடலை (request body) நேரடியாக ஒரு தரவுத்தளப் புதுப்பிப்பில் (database update) பயன்படுத்துவது, உங்கள் ஸ்கீமாவை (schema) மாற்றி எழுதுவதற்கு ஒரு பேனாவை வாடிக்கையாளரிடம் ஒப்படைப்பதற்குச் சமம். அதுதான் Mass Assignment. இது ஏதோ ஒரு விசித்திரமான பிழை அல்லது அரிதான நிகழ்வு அல்ல. ஒரு API, ஒரு தரவுப் தொகுப்பை (payload) அதன் சொந்தப் புதுப்பிப்புக் கொள்கையாகக் கருதும் போதெல்லாம் தோன்றும் ஒரு வடிவமைப்புத் தோல்வி இது.

await db.users.update(req.params.id, { ...req.body });

இது பார்ப்பதற்குத் தூய்மையாகத் தெரியும். தட்டச்சு நேரத்தைச் சேமிக்கும். ஆனால், சாவிகளை (keys) வாடிக்கையாளர் தான் கட்டுப்படுத்துகிறார். ஒரு சாதாரண சுயவிவரப் புதுப்பிப்பில் கூட, ஒரு தாக்குதல் நடத்துபவர் (attacker) "role": "admin", "accountId": "someone_else", அல்லது "credit": 99999" போன்றவற்றைச் சேர்க்க முடியும். உங்கள் சரிபார்ப்பு அடுக்கு (validation layer) அந்த மதிப்புகள் சரங்களா (strings) அல்லது எண்களா என்று சரிபார்த்து, அவை சரியாக இருப்பதாகச் சொல்லலாம். இருப்பினும், செல்லுபடித்தன்மை (Validity) என்பது அங்கீகாரம் (Authorization) அல்ல. ஒரு பயனர் அந்தப் பதிவின் உரிமையாளராக இருக்கலாம். ஆனால், அதனுள் இருக்கும் ஒவ்வொரு புலத்தையும் (field) திருத்துவதற்கு அவருக்கு உரிமை உண்டு என்று அர்த்தமல்ல.

Mass Assignment உண்மையில் எப்படி இருக்கும்

ஆபத்து வசதிகளுக்குள் ஒளிந்துள்ளது. Frameworks மற்றும் ORMs மூலம் JSON சாவிகளை நேரடியாக தரவுத்தளத் தூண்களுடன் (database columns) இணைப்பது மிகவும் எளிது. நீங்கள் இதைச் செய்யும்போது, எதை மாற்ற வேண்டும் என்பதைப் பொறுத்தவரை தரவுத்தளத்தை வாடிக்கையாளரை நம்பச் சொல்கிறீர்கள், எப்படி மாற்ற வேண்டும் என்பதை மட்டுமல்ல.

தங்கள் சுயவிவரத்தைப் புதுப்பிக்கும் ஒரு பயனர் displayName மற்றும் bio ஆகியவற்றிற்குச் சரியான தரவை அனுப்பலாம், ஆனால் அதனுடன் role அல்லது balance ஆகியவற்றையும் சேர்த்து அனுப்பக்கூடும். உங்கள் கன்ட்ரோலர் (controller) அந்தப் பொருளை அப்படியே முன்னோக்கி அனுப்பினால், தரவுத்தளம் அனைத்தையும் எழுதிவிடும். சரிபார்ப்பு (Validation) தவறான வடிவமைப்பு கொண்ட மதிப்புகளைப் பிடிக்கும். ஆனால் தீய நோக்கத்துடன் சேர்க்கப்பட்ட சாவிகளை (malicious keys) அது அரிதாகவே பிடிக்கும். "இந்த பயனர் தனது சுயவிவரத்தைப் புதுப்பிக்க அனுமதிக்கப்படுகிறார்" என்று சொல்லும் வணிக விதி, அந்த வரிசையில் உள்ள ஒவ்வொரு தூணிற்கும் ஒரு பொதுவான அனுமதியாக மாறிவிடுகிறது.

இதற்கான தீர்வு கூடுதல் சரிபார்ப்பு அல்ல. அது கடுமையான கட்டமைப்பு (stricter architecture).

மூன்று கட்டங்கள்

ஒரு பாதுகாப்பான மாற்றம் (mutation), சேமிப்பகத்தைத் தொடங்குவதற்கு முன் மூன்று தனித்தனிச் சோதனைகளைக் கடக்க வேண்டும்.

அனுமதிக்கப்பட்ட புலங்கள் (Allowlist)

நீங்கள் எந்தச் சாவிகளைப் பார்ப்பீர்கள் என்பதைத் தீர்மானிப்பதன் மூலம் தொடங்குங்கள். ஒரு புலம் அனுமதிக்கப்பட்ட பட்டியலில் (allowlist) இல்லையென்றால், கோரிக்கையை நிராகரிக்கவும் அல்லது அந்தச் சாவியை நீக்கவும். இது இயல்பான அணுகுமுறையை மாற்றுகிறது: புதிய தரவுத்தளத் தூண்கள் ஒரு டெவலப்பர் அவற்றை வெளிப்படையாக அறிவிக்கும் வரை எழுத முடியாதவையாக (non-writable) இருக்கும். ஸ்கீமாக்கள் காலப்போக்கில் வளரும். ஒரு குழு உறுப்பினர் stripeCustomerId, departmentBudget, அல்லது isVerified போன்ற புதிய புலங்களைச் சேர்க்கலாம். ஒரு அனுமதிக்கப்பட்ட பட்டியல் இருந்தால், அந்தப் புதிய தூண்கள் வாடிக்கையாளர் எழுதும் தரவிலிருந்து தானாகவே பாதுகாக்கப்படும். அது இல்லையென்றால், ஒவ்வொரு புதிய தூணும் தற்செயலாக ஒரு API பரப்பளவாக (API surface) மாறிவிடும்.

செல்லுபடியாகும் மதிப்புகள்

எந்தப் புலங்கள் அனுமதிக்கப்படுகின்றன என்பதைத் தெரிந்து கொண்டவுடன், அந்த மதிப்புகள் அர்த்தமுள்ளவையா என்று சரிபார்க்கவும். Timezone சரம் உண்மையில் அங்கீகரிக்கப்பட்ட Timezone தானா? மின்னஞ்சல் மின்னஞ்சல் வடிவில் உள்ளதா? எண் ஒரு நியாயமான வரம்பிற்குள் உள்ளதா? இது ஒரு அடிப்படைத் தூய்மைப் பணி. இது உங்கள் அமைப்பிற்குள் குப்பைகள் நுழைவதைத் தடுக்கிறது, ஆனால் துஷ்பிரயோகத்தைத் தடுக்காது. தவறான நபர் ஒரு "admin" என்ற சரத்தை role புலத்தில் அனுப்பினால், அது முற்றிலும் செல்லுபடியாகும் சரமாக இருந்தாலும் ஆபத்தானதுதான்.

அங்கீகரிக்கப்பட்ட மாற்றங்கள் (Authorized Transitions)

இது பெரும்பாலான குழுக்கள் தவிர்க்கும் ஒரு கட்டம், ஆனால் உண்மையான பாதுகாப்பு இதில்தான் உள்ளது. ஒரு நுணுக்கமான கேள்வியைக் கேளுங்கள்: இந்த குறிப்பிட்ட நபர் (actor), இந்த குறிப்பிட்ட பதிவில் உள்ள இந்த குறிப்பிட்ட புலத்தை மாற்ற அனுமதி பெற்றிருக்கிறாரா? "பயனர் ஒரு அட்மினா?" என்று கேட்காதீர்கள். "பயனருக்கு write:users அதிகாரம் உள்ளதா?" என்றும் கேட்காதீர்கள். மாறாக, "இந்த பயனர் தனது சொந்த displayName-ஐ மாற்ற அனுமதிக்கப்படுகிறாரா, ஆனால் அவரது accountId-ஐ மாற்ற முடியாதுவா?" என்று கேளுங்கள். புலத்திற்கு இடையிலான அங்கீகாரம் (Per-field authorization), "Editor" அல்லது "User" போன்ற ஒரு பரந்த அனுமதியை, வரிசையில் உள்ள ஒவ்வொரு பண்பிற்கும் ஒரு மாஸ்டர் சாவியாக மாறுவதிலிருந்து தடுக்கிறது.

Patch Function-ஐ உருவாக்குதல்

இந்த மூன்று கட்டங்களையும் ஒரு ஒற்றை குழாயாக (pipeline) இணைக்கவும். ஒரு patch கோரிக்கை வரும்போது, அதை வரிசைப்படி இந்த நிலைகளைக் கடந்து செல்லச் செய்யுங்கள்.

முதலில், உங்கள் அனுமதிக்கப்பட்ட பட்டியலுடன் (allowlist) உள்ளீட்டைச் சரிபார்க்கவும். இந்த endpoint-க்கு role என்பது அனுமதிக்கப்பட்ட புலமாக இல்லையென்றால், அங்கேயே நிறுத்திவிடுங்கள். நீங்கள் ஒருபோதும் பெறக்கூடாத ஒரு மதிப்பைச் சரிபார்க்கவோ அல்லது அங்கீகரிக்கவோ எந்தத் தேவையுமில்லை.

இரண்டாவதாக, அனுமதிக்கப்பட்ட மதிப்புகளைச் சரிபார்க்கவும். வகைகள் (types), வடிவங்கள் (formats) மற்றும் வணிக விதிகளைச் சரிபார்க்கவும். ஒரு இருப்பிடப் புலம் (location field) உண்மையான timezone-ஐக் குறிக்கும் ஒரு சரமாக இருக்க வேண்டும். ஒரு avatar URL ஒரு குறிப்பிட்ட நீளத்திற்குள் இருக்கும் சரியான URI ஆக இருக்க வேண்டும்.

மூன்றாவதாக, செயலை அங்கீகரிக்கவும். அந்த நபர் அந்தப் பதிவின் உரிமையாளரா அல்லது அந்தப் புலத்திற்குத் தேவையான துல்லியமான அனுமதியைக் கொண்டுள்ளாரா என்பதைச் சரிபார்க்கவும். தனிப்பட்ட தரவுகளுக்கு உரிமையாளர் (ownership) என்பது ஒரு நல்ல இயல்பான விதியாகும், ஆனால் சில புலங்களுக்கு இன்னும் கூடுதல் கட்டங்கள் தேவைப்படலாம். ஒரு பயனர் தனது சுயவிவரத்தின் உரிமையாளராக இருக்கலாம், ஆனால் taxRegion-ஐ ஒரு பில்லிங் அட்மின் (billing admin) மட்டுமே தொடர வேண்டும்.

நான்காவதாக, தரவை இயல்பாக்குங்கள் (normalize). வெற்று இடங்களை (whitespace) நீக்கவும், மீண்டும் மீண்டும் வரும் இடைவெளிகளைக் குறைக்கவும், மின்னஞ்சல்களைச் சிறிய எழுத்துக்களாக (lowercase) மாற்றவும் அல்லது கட்டுப்பாட்டு எழுத்துக்களை (control characters) நீக்கவும். இதைச் சரிபார்ப்பிற்குப் பிறகு ஆனால் சேமிப்பதற்கு முன் செய்யுங்கள், அப்போதுதான் அங்கீகாரம் சரிபார்க்கும் போது நீங்கள் அழுக்கடைந்த சரங்களை (dirty strings) ஒப்பிட வேண்டியிருக்காது.

உள்ளீடு (input) ஏதேனும் ஒரு சோதனையில் (gate) தோல்வியடைந்தால், முழு மாற்றத்தையும் (mutation) நிராகரிக்கவும். பாதுகாப்பான புலங்களை (safe fields) மட்டும் பகுதிப்பயன்பாடு செய்துவிட்டு, தவறானவற்றை அமைதியாகத் தவிர்த்துவிடாதீர்கள். ஒரு கலவையான பதில் (mixed response), கிளையண்டுகள் தங்களுக்குத் தெரிந்த அனைத்து சாவிகளையும் (keys) முயற்சி செய்து பார்ப்பதற்கும், எது வேலை செய்கிறது என்று பார்ப்பதற்கும் தூண்டுகோலாக அமையும். வெளிப்படையாகத் தோல்வியைக் காட்டவும் (Fail explicitly).

உண்மையில் முக்கியமான விளிம்பு நிலைச் சூழல்கள் (Edge Cases)

Mass assignment பாதுகாப்புகள், யூனிட் டெஸ்ட்கள் (unit tests) பெரும்பாலும் கவனிக்கத் தவறும் நுணுக்கங்களிலேயே தங்கியுள்ளன.

நகல் JSON சாவிகள் (Duplicate JSON keys). தாக்குதல் நடத்துபவர்கள் {"role": "user", "role": "admin"} போன்ற பேலோட்களை (payloads) அனுப்பலாம். உங்கள் HTTP பார்ஸர் (parser) மற்றும் கட்டமைப்பைப் (framework) பொறுத்து, உங்கள் அப்ளிகேஷன் கோட் அந்த ஆப்ஜெக்ட்டைப் பார்ப்பதற்கு முன்பே இரண்டாவது மதிப்பு முதல் மதிப்பை மாற்றியமைக்கக்கூடும். இந்தச் செயல்பாட்டை பார்ஸர் மட்டத்திலேயே சோதிக்கவும். உங்கள் கட்டமைப்பானது கடைசி சாவியை அமைதியாக ஏற்றுக்கொண்டால், உங்கள் அனுமதிக்கப்பட்ட பட்டியல் (allowlist) "user" என்பதைப் பார்த்துக் கொண்டிருக்கும் அதே வேளையில், தரவுத்தளம் (database) "admin" என்பதைப் பெறக்கூடும்.

நெஸ்டட் ஆப்ஜெக்ட்கள், nulls மற்றும் அரேக்கள் (arrays). பேலோட் தட்டையாக (flat) இருக்கும் என்று assumptions வைத்துக்கொள்ளாதீர்கள். ஒரு கிளையண்ட் கட்டுப்பாட்டுப் புலத்தை (restricted field) { "profile": { "role": "admin" } } போன்ற ஒரு நெஸ்டட் ஆப்ஜெக்ட்டிற்குள் மறைத்து அனுப்பலாம். உங்கள் ஸ்கீமா (schema) நெஸ்டட் முறையில் இருந்தால், உங்கள் அனுமதிக்கப்பட்ட பட்டியலும் (allowlist) அவ்வாறே செயல்பட வேண்டும். அதேபோல், null-ஐ நீங்கள் எவ்வாறு கையாளுகிறீர்கள் என்பதைத் தீர்மானிக்கவும். அது "இந்த புலத்தைப் புறக்கணிக்கவும்" என்பதைக் குறிக்கிறதா அல்லது "இந்த புலத்தை நீக்கவும்" என்பதைக் குறிக்கிறதா? மேலும், ஒரு அரே (array) எதிர்பார்க்கப்படும்போது, உங்கள் சரிபார்ப்பி (validator) எதிர்பாராத கட்டமைப்புகளை நிராகரிக்கிறதா அல்லது ஒரு தனி ஆப்ஜெக்ட்டை அரேவாக மாற்றி அனுமதித்துவிடுகிறதா?

யூனிகோட் இயல்பாக்கம் (Unicode normalization). இரண்டு சரங்கள் (strings) மனிதர்களுக்கு ஒரே மாதிரியாகத் தோன்றினாலும், அவை வெவ்வேறு பைட் வரிசைகளாக (byte sequences) இருக்கலாம். ஒரு பயனர் ஒரு ஒருங்கிணைந்த é அல்லது பிரிக்கப்பட்ட e மற்றும் சேர்க்கப்பட்ட குறியீட்டை (combining accent) அனுப்பலாம். உங்கள் அங்கீகாரச் சரிபார்ப்பு (authorization check) ஒருமுறை இயல்பாக்கம் செய்து, ஆனால் உங்கள் சேமிப்பு அடுக்கு (storage layer) வேறு விதமாக இயல்பாக்கம் செய்தால், நீங்கள் முரண்பட்ட தரவைப் பெறலாம் அல்லது மிக மோசமாக, பயனர் பெயர் மோதல் (username collision) உங்கள் தர்க்கத்தைத் தாண்டிச் செல்லும் ஒரு பாதுகாப்பு மீறலுக்கு (bypass) வழிவகுக்கலாம். ஆரம்பத்திலேயே இயல்பாக்கம் செய்யவும், அதைத் தொடர்ச்சியாகச் செய்யவும்.

ரேஸ் கண்டிஷன்கள் (Race conditions). அங்கீகார முடிவுகள் என்பவை நிலையானவை அல்ல. அவை ஒரு குறிப்பிட்ட நேரத்தில் நிகழ்கின்றன. இரண்டு கோரிக்கைகள் (requests) ஒரே பதிவைப் படிக்கலாம், இரண்டும் அந்தப் பயனர் எழுத அனுமதிக்கப்பட்டுள்ளார் என்பதைக் காணலாம், மற்றும் இரண்டும் புதுப்பிப்புகளை (updates) வழங்கலாம். அதற்கு இடையில், நிலை (state) அல்லது பயனரின் அனுமதிகள் மாறியிருக்கலாம். எப்போதும் ஒரு பதிப்பு எண் (version number) அல்லது ஸ்டேட் மெஷின் (state machine) மதிப்பைக் கொண்ட நிபந்தனையுடன் தரவுத்தளப் புதுப்பிப்புகளைச் செய்யவும். UPDATE users SET ... WHERE id = ? AND version = 5 போன்ற ஒன்றைப் பயன்படுத்தவும். நீங்கள் படித்ததிலிருந்து அந்த வரிசை (row) மாறியிருந்தால், எழுதும் செயல் தோல்வியடையும். மீண்டும் முயற்சிப்பதன் மூலமோ அல்லது நிராகரிப்பதன் மூலமோ அந்தத் தோல்வியைக் கையாளவும். இது காலாவதியான அங்கீகாரச் சரிபார்ப்புகள் உங்கள் தரவைச் சிதைப்பதைத் தடுக்கும்.

முக்கியமானவற்றைத் கண்காணிக்கவும்

உங்களால் பார்க்க முடியாத ஒன்றைப் பாதுகாக்க முடியாது. உங்கள் தணிக்கை பதிவை (audit logging) வெறும் செயலைச் சுற்றி மட்டும் அல்லாமல், முடிவைச் சுற்றியும் கட்டமைக்கவும்.

பயனர் ஐடி (actor ID) மற்றும் இலக்கு ஐடியை (target ID) பதிவு செய்யவும். ஏற்றுக்கொள்ளப்பட்ட துல்லியமான புலப் பெயர்களையும் (field names) நிராகரிக்கப்பட்டவற்றையும் பதிவு செய்யவும். முடிவெடுத்த கொள்கை பதிப்பைப் (policy version) மற்றும் இறுதி முடிவையும் பதிவு செய்யவும். ஒரு பயனர் தனது சுயவிவரப் புதுப்பிப்பில் (profile update) திடீரென role நிராகரிக்கப்படுவதைக் கண்டால், அதை நீங்கள் உடனடியாகத் தெரிந்துகொள்ள வேண்டும்.

பேரர் டோக்கன்களை (bearer tokens) ஒருபோதும் பதிவு செய்யாதீர்கள். முழு கோரிக்கை உடல்களையும் (request bodies) உங்கள் பதிவுகளில் கொட்டாதீர்கள். ஒரு தணிக்கைப் பாதை (audit trail) துஷ்பிரயோகத்தை விசாரிக்க உங்களுக்கு உதவ வேண்டுமே தவிர, கடவுச்சொற்கள் (credentials) மற்றும் தனிப்பட்ட தரவுகளின் களஞ்சியமாக மாறிவிடக்கூடாது.

உங்களுக்குத் தேவையான ஒரே விதி

ஒரு கோரிக்கை உடல் (request body) தரவை முன்மொழிகிறது. அது ஒருபோதும் தனது சொந்த அதிகாரத்தை வரையறுப்பதில்லை. கிளையண்ட் எதைக் கேட்டாலும் கேட்கலாம். உங்கள் சர்வர் தான், ஒவ்வொரு புலமாகவும் மற்றும் ஒவ்வொரு வரிசையாகவும், நிரந்தரச் சேமிப்பில் (permanent storage) எதை அனுமதிக்கலாம் என்று தீர்மானிக்கிறது. அந்தப் பிரிவினையை மனதில் கொண்டு உங்கள் பேட்ச்களை (patches) உருவாக்கவும், அப்போது mass assignment என்பது உங்கள் அங்கீகார அடுக்கை (authorization layer) எட்டுவதற்கு முன்பே நீங்கள் நிறுத்திவிடும் ஒரு பிரச்சனையாக மாறிவிடும்.