حماية API GraphQL الخاص بك من نقاط الضعف

مرحبا يا هبر! أقدم لكم ترجمة المقال حماية واجهة برمجة تطبيقات GraphQL الخاصة بك من نقاط الضعف الأمنية .


أصبح GraphQL اختيارًا للمطورين الذين يحتاجون إلى إنشاء واجهة برمجة تطبيقات لتطبيق عميلهم. ولكن ، مثل كل التقنيات الجديدة ، تخضع GraphQL لبعض المخاطر الأمنية الكامنة. بغض النظر عما إذا كنت بصدد إنشاء مشروع تابع لجهة خارجية أو تطبيق مؤسسي واسع النطاق ، فأنت بحاجة إلى التأكد من حماية نفسك من هذه التهديدات.


صورة


على الرغم من أن التهديدات المدرجة في هذا المنشور خاصة بـ GraphQL ، فإن تطبيقك سوف يقدم مجموعة جديدة من التهديدات التي ستحتاج إلى معالجتها. من المهم أيضًا أن تفهم التهديدات التي تتعرض لها أي تطبيقات تعمل على الشبكة.


التهديد: استعلامات كبيرة ، متداخلة بعمق تكون مكلفة لحسابها


الحل : الحد من عمق التعشيش


ترتبط القوة التي يوفرها GraphQL ببعض تهديدات الأمان الجديدة. الأكثر شيوعًا هي الاستعلامات المتداخلة بعمق ، والتي تؤدي إلى حسابات باهظة الثمن و JSON ضخمة ، والتي يمكن أن تؤثر سلبًا على الشبكة وعرض النطاق الترددي الخاص بها.


تتمثل الطريقة الصحيحة لحماية API الخاص بك من هذا النوع من الهجوم في الحد من عمق الطلبات بحيث يتم حظر الطلبات العميقة الضارة حتى يتم حساب النتيجة.


يوفر GraphQL Depth Limit واجهة بسيطة للحد من عمق الاستعلام.


import depthLimit from 'graphql-depth-limit' import express from 'express' import graphqlHTTP from 'express-graphql' import schema from './schema' const app = express() app.use('/graphql', graphqlHTTP((req, res) => ({ schema, validationRules: [ depthLimit(10) ] }))) 

التهديد: القوة الغاشمة طلبات الطفرة الضعيفة


الحل : الحد من عدد الطلبات


يُعد البحث عن عمليات تسجيل الدخول وكلمات المرور أقدم خدعة في تاريخ القرصنة. في العقد الماضي ، حدثت العديد من عمليات تسرب البيانات على الإنترنت ، حيث تم مؤخرًا العثور على قاعدة بيانات تحتوي على 772،904،991 بريدًا إلكترونيًا فريدًا و 21،222،975 كلمة مرور فريدة . للتحقق مما إذا كانت المعلومات المتعلقة ببريدك وكلمة مرورك قد تسربت ، قام Troy Hunt حتى بإنشاء موقع " I I Pwned" ، والذي استخدم ، من بين آخرين ، قاعدة البيانات هذه.


لحسن الحظ ، لديك طريقة سهلة لجعل البحث صعبًا ومكلفًا حقًا للمهاجمين ، مما يجعلك هدفًا أقل جاذبية لهم.


يسمح لك المكون الإضافي لـ GraphQL Rate Limit بتحديد قيود على استفساراتك بثلاث طرق مختلفة: استخدام توجيهات مخصصة لـ graphql-shield أو استخدام الدالة لتحديد العدد الأساسي للاستعلامات.


سيتيح لك هذا المكون الإضافي تعيين إطار زمني وحد أقصى لعدد طلباته. سيساعدك تعيين نافذة زمنية كبيرة للطلبات شديدة الضعف ، مثل تسجيل الدخول ، ونوافذ صغيرة لطلبات أقل عرضة للخطر ، على الحفاظ على تجربة ممتعة للمستخدمين العاديين وستصبح كابوسًا للمهاجمين.


قم بإنشاء توجيه للحد من عدد الطلبات:


هنا سوف تحتاج إلى معرف فريد لكل طلب. يمكنك استخدام عنوان IP الخاص بالمستخدم أو معرف آخر ، وهو فريد لكل مستخدم ويتوافق مع كل طلب.


 const rateLimitDirective = createRateLimitDirective({ identifyContext: (context) => { return context.id }, }) 

إضافة توجيه إلى المخطط الخاص بك:


 import { createRateLimitDirective } from 'graphql-rate-limit' export const schema = { typeDefs, resolvers, schemaDirectives: { rateLimit: rateLimitDirective, }, } export default schema 

أخيرًا ، أضف توجيهًا إلى استعلامك المحتمل:


 #        60  Login(input: LoginInput!): User @rateLimit( window: "60s" max: 10 message: "You are doing that too often. Please wait 60 seconds before trying again." ) 

التهديد: السماح للمستخدم بالتأثير على البيانات الخاصة بالمستخدم


الحل : خذ هذه البيانات من جلسة المستخدم حيثما كان ذلك ممكنًا


من السهل افتراض أنه إذا كنت ترغب في السماح للمستخدم بتحديث أحد الموارد ، فمن الجدير السماح للمستخدم بتحديد المورد الذي يريد تحديثه. ولكن ماذا لو حصل المستخدم على معرف مورد لا ينبغي له حقًا الوصول إليه؟


افترض أن لدينا طلب طفرة updateUser يسمح للمستخدم بتحديث ملفه الشخصي.


 mutation UpdateUser($input: {"id": "test123" , "email": "test@example.com"}) { UpdateUser(input: $input) { id firstName lastName } } 

إذا لم تكن هناك حماية من جانب الخادم ، فيمكن للمهاجم ، الذي لديه قائمة من المعرفات ، تحديث عنوان البريد الإلكتروني لأي مستخدم. الحل الواضح هنا هو إضافة فحص للتأكد من مطابقة معرف المستخدم الحالي للمعرف في حقول الإدخال.


لا تفعل هذا:


 function updateUser({ id, email }) { return User.findOneAndUpdate({ _id: id }, { email }) .catch(error => { throw error; }); } 

تتمثل الطريقة الأقل وضوحًا ولكن الصحيحة لحل هذه المشكلة في منع استخدام المعرف كمدخلات واستخدام معرف المستخدم من كائن السياق.


افعل هذا:


 function updateUser({ email }, context) { return User.findOneAndUpdate({ _id: context.user._id }, { email }) .catch(error => { throw error; }); } 

ربما هذا مثال تافه إلى حد ما ، ولكن تنفيذ مثل هذه الإجراءات لكل من الكائنات التي يتفاعل معها المستخدم مباشرة يمكن أن يحميك من العديد من الأخطاء الخطرة.


تحقيق العديد من الاستعلامات باهظة الثمن في وقت واحد


الحل : حد تكلفة الاستعلام


من خلال تعيين سعر لكل طلب والإشارة إلى الحد الأقصى لسعر كل طلب ، يمكننا حماية أنفسنا من المتسللين الذين قد يحاولون تلبية الكثير من الطلبات باهظة الثمن في نفس الوقت.


يعد المكون الإضافي لتحليل تكلفة GraphQL طريقة سهلة لتحديد تكلفة الاستعلامات والحد الأقصى للتكلفة.


تحديد التكلفة القصوى:


 app.use( '/graphql', graphqlExpress(req => { return { schema, rootValue: null, validationRules: [ costAnalysis({ variables: req.body.variables, maximumCost: 1000, }), ], } }) ) 

حدد تكلفة كل طلب:


 Query: { Article: { multipliers: ['limit'], useMultipliers: true, complexity: 3, }, } 

التهديد: الكشف عن تفاصيل تنفيذ GraphQL


الحل : تعطيل الاستبطان في رمز "القتال"


GraphQL هي أداة تطوير مفيدة للغاية. إنها قوية جدًا لدرجة أنها توثق نظامك وطلباتك واشتراكاتك. يمكن أن تكون هذه المعلومات منجمًا ذهبيًا للمهاجمين الذين يرغبون في العثور على ثغرات أمنية في تطبيقك.


سيمنع المكون الإضافي GraphQL Display Introspection المخطط الخاص بك من التسرب إلى الجمهور. فقط استيراد البرنامج المساعد وتطبيقه على قواعد التحقق من الصحة.


 import express from 'express'; import bodyParser from 'body-parser'; import { graphqlExpress } from 'graphql-server-express'; + import NoIntrospection from 'graphql-disable-introspection'; const myGraphQLSchema = // ...    ! const PORT = 3000; var app = express(); app.use('/graphql', bodyParser.json(), graphqlExpress({ schema: myGraphQLSchema, validationRules: [NoIntrospection] })); app.listen(PORT); 

Source: https://habr.com/ru/post/ar481840/


All Articles