الأمان والأداء
معالجة الأخطاء والكشف عن المعلومات
معالجة الأخطاء والكشف عن المعلومات
تمنع معالجة الأخطاء الصحيحة تسرب المعلومات الحساسة مع الحفاظ على تجربة مستخدم جيدة وقدرات تصحيح الأخطاء.
صفحات الأخطاء المخصصة
إنشاء صفحات أخطاء سهلة الاستخدام لا تكشف عن معلومات النظام:
<!-- resources/views/errors/500.blade.php -->
<!DOCTYPE html>
<html>
<head>
<title>خطأ في الخادم</title>
</head>
<body>
<h1>500 - خطأ داخلي في الخادم</h1>
<p>حدث خطأ ما. يرجى المحاولة مرة أخرى لاحقاً.</p>
<!-- لا آثار مكدس أو مسارات ملفات أو تفاصيل نظام -->
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>خطأ في الخادم</title>
</head>
<body>
<h1>500 - خطأ داخلي في الخادم</h1>
<p>حدث خطأ ما. يرجى المحاولة مرة أخرى لاحقاً.</p>
<!-- لا آثار مكدس أو مسارات ملفات أو تفاصيل نظام -->
</body>
</html>
لا تعرض أبداً: آثار المكدس، مسارات الملفات، أخطاء قاعدة البيانات، أرقام الإصدارات، أو تفاصيل البيئة في الإنتاج.
تكوين تسجيل الأخطاء
تكوين Laravel لتسجيل الأخطاء بشكل آمن:
// config/logging.php
'channels' => [
'production' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => 'error',
'days' => 14,
'permission' => 0640, // تقييد أذونات الملف
],
];
'channels' => [
'production' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => 'error',
'days' => 14,
'permission' => 0640, // تقييد أذونات الملف
],
];
وضع التصحيح في .env
تكوين البيئة الحرج:
# .env (الإنتاج)
APP_ENV=production
APP_DEBUG=false
LOG_LEVEL=error
# .env (التطوير)
APP_ENV=local
APP_DEBUG=true
LOG_LEVEL=debug
APP_ENV=production
APP_DEBUG=false
LOG_LEVEL=error
# .env (التطوير)
APP_ENV=local
APP_DEBUG=true
LOG_LEVEL=debug
مخاطر أمنية: APP_DEBUG=true في الإنتاج يكشف: آثار المكدس، متغيرات البيئة، قيم التكوين، مسارات الملفات، واستعلامات قاعدة البيانات.
معالج الاستثناءات المخصص
التحكم في استجابات الأخطاء في الإنتاج:
// app/Exceptions/Handler.php
public function render($request, Throwable $e)
{
if (app()->environment('production')) {
// تسجيل تفاصيل الخطأ الكاملة
Log::error($e->getMessage(), [
'exception' => get_class($e),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString(),
]);
// إرجاع خطأ عام للمستخدم
return response()->view('errors.500', [], 500);
}
return parent::render($request, $e);
}
public function render($request, Throwable $e)
{
if (app()->environment('production')) {
// تسجيل تفاصيل الخطأ الكاملة
Log::error($e->getMessage(), [
'exception' => get_class($e),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString(),
]);
// إرجاع خطأ عام للمستخدم
return response()->view('errors.500', [], 500);
}
return parent::render($request, $e);
}
منع تسرب المعلومات
تسريبات المعلومات الشائعة:
- آثار المكدس التي تكشف بنية الملفات
- رسائل خطأ قاعدة البيانات التي تظهر أسماء الجداول/الأعمدة
- إصدار الإطار في رؤوس HTTP
- التعليقات في كود مصدر HTML
- رسائل الخطأ التي تكشف وجود المستخدم
رسائل خطأ آمنة
أمثلة على رسائل الخطأ الآمنة مقابل غير الآمنة:
// ❌ سيء: يكشف وجود المستخدم
return 'البريد الإلكتروني موجود بالفعل في قاعدة البيانات';
// ✅ جيد: رسالة عامة
return 'فشل التسجيل. يرجى المحاولة مرة أخرى.';
// ❌ سيء: يكشف مسار الملف
throw new Exception('الملف غير موجود: /var/www/uploads/secret.pdf');
// ✅ جيد: رسالة عامة
throw new Exception('الملف غير موجود');
return 'البريد الإلكتروني موجود بالفعل في قاعدة البيانات';
// ✅ جيد: رسالة عامة
return 'فشل التسجيل. يرجى المحاولة مرة أخرى.';
// ❌ سيء: يكشف مسار الملف
throw new Exception('الملف غير موجود: /var/www/uploads/secret.pdf');
// ✅ جيد: رسالة عامة
throw new Exception('الملف غير موجود');
حدود الأخطاء في الواجهة الأمامية
مثال على حد الخطأ في React:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// تسجيل في خدمة تتبع الأخطاء
logErrorToService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h2>حدث خطأ ما.</h2>;
}
return this.props.children;
}
}
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// تسجيل في خدمة تتبع الأخطاء
logErrorToService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h2>حدث خطأ ما.</h2>;
}
return this.props.children;
}
}
رؤوس الأمان
إخفاء معلومات الخادم:
// app/Http/Middleware/SecurityHeaders.php
public function handle($request, Closure $next)
{
$response = $next($request);
// إزالة توقيع الخادم
$response->headers->remove('X-Powered-By');
$response->headers->set('Server', 'WebServer');
return $response;
}
public function handle($request, Closure $next)
{
$response = $next($request);
// إزالة توقيع الخادم
$response->headers->remove('X-Powered-By');
$response->headers->set('Server', 'WebServer');
return $response;
}
أفضل الممارسات: تنفيذ معالجة مركزية للأخطاء، استخدام التسجيل المنظم، مراقبة معدلات الأخطاء، وعدم الكشف أبداً عن التفاصيل الداخلية للمستخدمين النهائيين.
تمرين: راجع تطبيقك بحثاً عن نقاط ضعف الكشف عن المعلومات. تحقق من صفحات الأخطاء واستجابات API وملفات السجل. اضبط APP_DEBUG=false واختبر جميع سيناريوهات الأخطاء.