أمان تطبيقات TypeScript: أهم 10 ثغرات أمنية للمبتدئين
\n\nTypeScript هي طبقة فوق JavaScript تضيف الكتابة الثابتة، لكنها لا تحمي من الثغرات الأمنية الكلاسيكية للويب. غالبًا ما يعتمد المطورون المبتدئون على صرامة الأنواع، متناسين الأمان على مستوى المنطق والبيانات. في هذه المقالة، سنستعرض أكثر 10 ثغرات أمنية شيوعًا في تطبيقات TypeScript مع أمثلة على الكود وطرق الحماية.
\n\n1. XSS (Cross-Site Scripting) عبر dangerouslySetInnerHTML
\nواحدة من أكثر المشكلات شيوعًا هي إدراج HTML الخاص بالمستخدم دون تنقية. في TypeScript، يحدث هذا غالبًا عند العمل مع React أو Angular.
\n\n// ❌ كود ضعيف
function UserComment({ comment }: { comment: string }) {
return <div dangerouslySetInnerHTML={{ __html: comment }} />;
}
// ✅ الخيار الآمن
import DOMPurify from 'dompurify';
function SafeComment({ comment }: { comment: string }) {
const sanitized = DOMPurify.sanitize(comment);
return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
}\n\n2. حقن SQL عبر استعلامات نصية
\nTypeScript لا يحمي من حقن SQL إذا كنت تستخدم نصوصًا خام. استخدم دائمًا الاستعلامات ذات المعاملات.
\n\n// ❌ خطير
const query = `SELECT * FROM users WHERE email = '${userEmail}'`;
// ✅ آمن (مثال مع Prisma)
const user = await prisma.user.findUnique({
where: { email: userEmail }
});\n\n3. تخزين غير آمن للأسرار في الكود
\nيجب ألا تظهر مفاتيح API والرموز وكلمات المرور في الكود المصدري. يتم ترجمة TypeScript إلى JavaScript، وتبقى جميع النصوص قابلة للقراءة.
\n\n// ❌ لا تفعل هذا أبدًا
const API_KEY = 'sk-1234567890abcdef';
// ✅ استخدم متغيرات البيئة
const API_KEY = process.env.API_KEY;
if (!API_KEY) throw new Error('API_KEY is missing');\n\n4. حقن NoSQL (MongoDB)
\nعند العمل مع MongoDB عبر Mongoose أو برنامج التشغيل، يمكن أن تمرر عن طريق الخطأ كائن استعلام يتلاعب بالمنطق.
\n\n// ❌ كود ضعيف
app.post('/login', async (req, res) => {
const user = await User.findOne({
email: req.body.email,
password: req.body.password
});
});
// ✅ الخيار الآمن
app.post('/login', async (req: Request, res: Response) => {
const { email, password } = req.body;
if (typeof email !== 'string' || typeof password !== 'string') {
return res.status(400).send('Invalid input');
}
const user = await User.findOne({ email, password });
});\n\n5. CSRF (Cross-Site Request Forgery)
\nإذا كان تطبيقك يستخدم مصادقة ملفات تعريف الارتباط، يمكن للمهاجم تنفيذ إجراءات نيابة عن المستخدم.
\n\n// ❌ عدم وجود حماية
app.post('/transfer', (req, res) => {
// تنفيذ التحويل دون التحقق من المصدر
});
// ✅ الحماية عبر رمز CSRF (مثال مع csurf)
import csrf from 'csurf';
const csrfProtection = csrf({ cookie: true });
app.post('/transfer', csrfProtection, (req, res) => {
// تنفيذ آمن
});\n\n6. تلوث النموذج الأولي (Prototype Pollution)
\nعند دمج الكائنات دون تحقق، يمكن استبدال خصائص النموذج الأولي، مما يؤدي إلى ثغرات أمنية.
\n\n// ❌ خطير
function merge(target: any, source: any) {
for (const key in source) {
target[key] = source[key];
}
}
// ✅ آمن
function safeMerge(target: Record<string, any>, source: Record<string, any>) {
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}\n\n7. تسرب المعلومات عبر الأخطاء
\nيجب ألا تظهر تتبعات المكدس وتفاصيل قاعدة البيانات للمستخدم. قد يخدع TypeScript اليقظة بسبب الأنواع الصارمة.
\n\n// ❌ سيء
app.use((err, req, res, next) => {
res.status(500).json({ error: err.m