امنیت یکی از مهمترین بخشهای توسعه نرمافزارهای تحت وب است. یک پروژه Laravel ممکن است از نظر امکانات و طراحی کاملاً مناسب باشد، اما اگر احراز هویت، مجوزهای دسترسی، اعتبارسنجی ورودیها و تنظیمات سرور بهدرستی پیادهسازی نشده باشند، در معرض خطر قرار میگیرد.
Laravel ابزارهای امنیتی متعددی در اختیار توسعهدهندگان قرار میدهد؛ از محافظت در برابر حملات CSRF و استفاده از Query Builder گرفته تا سیستم احراز هویت، مجوزهای دسترسی و رمزنگاری اطلاعات.
بااینحال، استفاده از یک فریمورک امن بهتنهایی کافی نیست. امنیت نهایی به نحوه استفاده از امکانات فریمورک، منطق کسبوکار و پیکربندی سرور نیز وابسته است.
در این مقاله، مهمترین روشهای امنسازی پروژه Laravel را با مثالهای کاربردی بررسی میکنیم.
۱. غیرفعال کردن Debug در محیط Production
یکی از اولین اقدامات امنیتی هنگام انتشار پروژه Laravel، غیرفعال کردن نمایش جزئیات خطا برای کاربران است.
در محیط توسعه، نمایش خطاها به برنامهنویس کمک میکند مشکلات را سریعتر پیدا کند. اما در محیط عملیاتی، نمایش Stack Trace، مسیر فایلها، جزئیات تنظیمات یا اطلاعات اتصال میتواند اطلاعات مفیدی در اختیار مهاجم قرار دهد.
در فایل .env محیط عملیاتی، تنظیمات زیر را قرار دهید:
APP_ENV=production
APP_DEBUG=false
پس از تغییر تنظیمات، اگر کش پیکربندی فعال است، آن را مطابق فرایند استقرار پروژه بهروزرسانی کنید:
php artisan config:cache
مطمئن شوید مقدار APP_DEBUG در محیط عملیاتی واقعاً false است و خطاهای داخلی برنامه به کاربر نمایش داده نمیشوند.
نکته: غیرفعال کردن Debug به معنای حذف ثبت خطاها نیست. بهتر است خطاها بهصورت کنترلشده در Log ذخیره شوند تا امکان بررسی و عیبیابی وجود داشته باشد.
۲. محافظت در برابر SQL Injection
SQL Injection زمانی رخ میدهد که ورودی کنترلنشده کاربر بهگونهای وارد یک دستور SQL شود که ساختار یا منطق آن را تغییر دهد.
در Laravel، استفاده از Eloquent و Query Builder با Binding پارامترها، بسیاری از خطرهای متداول این حمله را کاهش میدهد.
برای مثال، روش زیر مناسب است:
$user = DB::table('users')
->where('email', $request->input('email'))
->first();
Laravel مقدار ورودی را بهعنوان پارامتر کوئری ارسال میکند، نه اینکه آن را مستقیماً به متن SQL متصل کند.
اما ساختن کوئری با الحاق رشتههای ورودی کاربر خطرناک است:
// روش ناامن؛ از این الگو استفاده نکنید.
$email = $request->input('email');
$user = DB::select(
"SELECT * FROM users WHERE email = '$email'"
);
در این نمونه، ورودی مستقیماً وارد متن SQL شده است.
آیا استفاده از Eloquent برای جلوگیری از SQL Injection کافی است؟
استفاده صحیح از Eloquent و Query Builder بسیار کمککننده است، اما همه خطرها را برطرف نمیکند. برای مثال، نام ستونها و بخشهایی از SQL مانند جهت مرتبسازی را نمیتوان همیشه بهعنوان پارامتر معمولی Binding کرد.
اگر کاربر امکان انتخاب ستون مرتبسازی را دارد، مقدار را به فهرست مجاز محدود کنید:
$allowedSorts = ['name', 'created_at', 'email'];
$sort = $request->input('sort', 'created_at');
if (! in_array($sort, $allowedSorts, true)) {
$sort = 'created_at';
}
$users = User::query()
->orderBy($sort)
->get();
در نتیجه، بهجای اعتماد به ورودی کاربر، فقط مقادیر مورد تأیید برنامه در کوئری استفاده میشوند.
۳. محافظت در برابر حملات CSRF
CSRF مخفف Cross-Site Request Forgery است. در این نوع حمله، مهاجم تلاش میکند مرورگر کاربر را وادار کند در حالی که کاربر به یک سایت وارد شده است، درخواست ناخواستهای به آن سایت ارسال کند.
Laravel برای فرمهای وب خود مکانیزم محافظت در برابر CSRF دارد.
برای مثال، در یک فرم Blade:
<form method="POST" action="{{ route('profile.update') }}">
@csrf
<input
type="text"
name="name"
value="{{ old('name', auth()->user()->name) }}"
>
<button type="submit">ذخیره</button>
</form>
دستور @csrf یک توکن امنیتی به فرم اضافه میکند که Laravel آن را در درخواست بررسی میکند.
در فرمهایی که با روشهای POST، PUT، PATCH یا DELETE کار میکنند، باید مکانیزم مناسب محافظت از درخواست را رعایت کنید.
نکته مهم: برای رفع خطای CSRF، محافظت امنیتی را بدون بررسی حذف نکنید. اگر یک Webhook یا API خارجی نیاز به استثنا دارد، باید روش احراز اصالت مناسب همان درخواست را طراحی کنید. استثنا کردن مسیرها بدون کنترل جایگزین میتواند ریسک امنیتی ایجاد کند.
۴. اعتبارسنجی ورودی کاربران
هر دادهای که از مرورگر، API، فایل یا سرویس خارجی وارد برنامه میشود، باید بر اساس نیاز همان بخش اعتبارسنجی شود.
برای مثال، هنگام ثبت کاربر:
$request->validate([
'name' => ['required', 'string', 'max:100'],
'email' => ['required', 'email', 'max:255', 'unique:users,email'],
'password' => ['required', 'string', 'min:12', 'confirmed'],
]);
این اعتبارسنجی مواردی مانند خالی نبودن نام، معتبر بودن ساختار ایمیل، یکتا بودن ایمیل و حداقل طول رمز عبور را بررسی میکند.
قواعد دقیق باید با نیازمندیهای پروژه هماهنگ باشند. برای مثال، در سیستمهای حساس ممکن است سیاست رمز عبور، محدودیت تلاش ورود و احراز هویت چندمرحلهای نیز لازم باشد.
آیا اعتبارسنجی بهتنهایی امنیت را تضمین میکند؟
خیر. اعتبارسنجی به کنترل ساختار و محدوده داده کمک میکند، اما جایگزین مجوز دسترسی، Query Binding، رمزنگاری یا خروجیسازی امن نیست.
همچنین اگر از ورودی کاربر برای جستوجو، نمایش HTML یا عملیات فایل استفاده میکنید، باید خطرهای مربوط به همان کاربرد را نیز در نظر بگیرید.
۵. جلوگیری از XSS در خروجیهای Blade
XSS یا Cross-Site Scripting زمانی رخ میدهد که محتوای کنترلنشده بهصورت کد فعال در مرورگر اجرا شود.
در Blade، برای نمایش معمولی متن، از {{ }} استفاده کنید:
<p>{{ $comment->body }}</p>
این روش خروجی را Escape میکند و مانع اجرای بسیاری از کدهای HTML یا JavaScript واردشده از طریق متن میشود.
اما استفاده از {!! !!} خروجی را بدون Escape نمایش میدهد:
{{-- فقط برای محتوای HTML کاملاً مورد اعتماد و پاکسازیشده --}}
{!! $trustedHtml !!}
اگر محتوای HTML را از کاربران دریافت میکنید، صرفاً به این دلیل که آن را در دیتابیس ذخیره کردهاید نباید قابل اعتماد فرض کنید. در چنین مواردی به پاکسازی HTML با یک راهکار معتبر و محدود کردن تگها و ویژگیهای مجاز نیاز دارید.
همچنین در کد JavaScript، URLها و ویژگیهای HTML باید با توجه به زمینه استفاده از داده، خروجیسازی امن انجام شود.
۶. استفاده از Hash برای رمز عبور
رمز عبور کاربران نباید بهصورت متن ساده در پایگاه داده ذخیره شود. برای این کار از سیستم Hash لاراول استفاده کنید.
برای نمونه:
use Illuminate\Support\Facades\Hash;
$hashedPassword = Hash::make($request->input('password'));
برای بررسی رمز عبور نیز از متد مناسب استفاده کنید:
if (Hash::check($plainPassword, $user->password)) {
// رمز عبور صحیح است.
}
Hash با رمزنگاری قابل بازگشت تفاوت دارد. در سیستم ورود، برنامه باید بتواند رمز واردشده را با Hash ذخیرهشده بررسی کند، نه اینکه رمز اصلی را از دیتابیس بازیابی کند.
در پروژههای جدید، از سازوکارهای استاندارد Laravel برای ثبتنام، ورود و تغییر رمز عبور استفاده کنید و از طراحی الگوریتم اختصاصی برای Hash رمز عبور بپرهیزید.
۷. احراز هویت با مجوز دسترسی یکسان نیست
احراز هویت یا Authentication مشخص میکند کاربر چه کسی است.
مجوز دسترسی یا Authorization تعیین میکند کاربر اجازه انجام چه عملیاتی را دارد.
برای مثال، وارد شدن کاربر به سیستم به این معنی نیست که مجاز است اطلاعات همه سفارشها را مشاهده کند.
فرض کنید کاربری سفارش شماره ۱۵ را درخواست میکند. بررسی ورود کاربر بهتنهایی کافی نیست؛ باید مالکیت سفارش یا مجوز دسترسی او نیز بررسی شود.
نمونه ساده:
$order = Order::findOrFail($id);
$this->authorize('view', $order);
در این مثال، Policy مربوط به مدل Order باید تعریف شده باشد تا مشخص کند چه کاربری اجازه مشاهده سفارش را دارد.
استفاده از Policy
برای ایجاد Policy میتوانید از Artisan استفاده کنید:
php artisan make:policy OrderPolicy --model=Order
سپس در Policy، منطق مجوز را تعریف کنید. برای نمونه:
public function view(User $user, Order $order): bool
{
return $user->id === $order->user_id;
}
این کد نمونهای ساده برای سیستمی است که فقط مالک سفارش باید بتواند آن را مشاهده کند. در پروژه واقعی ممکن است مدیران، پشتیبانها یا نقشهای دیگری نیز مجوزهای متفاوتی داشته باشند.
نکته: بررسی مجوز باید در سمت سرور انجام شود. مخفی کردن یک دکمه در رابط کاربری، بهتنهایی مانع ارسال درخواست مستقیم به Endpoint نمیشود.
۸. محافظت از مسیرها با Middleware
Middleware میتواند درخواستهای ورودی را پیش از رسیدن به منطق اصلی برنامه بررسی کند.
برای مثال، مسیرهای مربوط به کاربران واردشده را میتوان پشت Middleware احراز هویت قرار داد:
use App\Http\Controllers\OrderController;
use Illuminate\Support\Facades\Route;
Route::middleware('auth')->group(function () {
Route::get('/orders', [OrderController::class, 'index'])
->name('orders.index');
});
این کد دسترسی به مسیر فهرست سفارشها را به کاربران احراز هویتشده محدود میکند.
اما اگر هر کاربر فقط باید سفارشهای خودش را ببیند، باید مجوزهای مالکیت نیز بررسی شوند. Middleware احراز هویت بهتنهایی این مسئله را حل نمیکند.
برای مدیریت نقشها و مجوزهای پیچیده، میتوانید از Policyها، Gateها یا یک سامانه مدیریت نقش و دسترسی سازگار با معماری پروژه استفاده کنید.
۹. امنسازی فایلهای آپلودی
آپلود فایل یکی از بخشهایی است که در صورت پیادهسازی نادرست میتواند ریسک جدی ایجاد کند.
موارد مهم عبارتاند از:
- اعتبارسنجی نوع و حجم فایل
- استفاده از نام فایل تولیدشده توسط برنامه
- جلوگیری از اجرای فایلهای آپلودشده
- ذخیره فایلهای خصوصی خارج از مسیر عمومی
- محدود کردن دسترسی به فایلها
- جلوگیری از اعتماد به نام یا پسوند ارسالی کاربر
برای نمونه، در یک فرم آپلود تصویر:
$request->validate([
'image' => [
'required',
'file',
'image',
'mimes:jpg,jpeg,png,webp',
'max:2048',
],
]);
در این مثال، حداکثر اندازه فایل ۲۰۴۸ کیلوبایت تعیین شده است.
سپس میتوانید فایل را با نام تولیدشده توسط Storage ذخیره کنید:
$path = $request->file('image')->store('uploads', 'public');
این نمونه فایل را در دیسک public ذخیره میکند؛ بنابراین برای فایلهای عمومی مناسب است. برای اسناد خصوصی، مدارک هویتی یا فایلهایی که فقط مالک آنها باید دسترسی داشته باشد، از دیسک خصوصی استفاده کنید و دانلود را از مسیر کنترلشدهای عبور دهید که مجوز دسترسی را بررسی میکند.
همچنین اعتبارسنجی پسوند بهتنهایی کافی نیست؛ نوع واقعی محتوا، سیاست نگهداری فایل و تنظیمات وبسرور نیز باید متناسب با نیاز بررسی شوند.
۱۰. مدیریت امن Secretها و فایل .env
فایل .env ممکن است حاوی اطلاعات حساس باشد، از جمله:
- رمز عبور پایگاه داده
- کلید برنامه
- کلیدهای API
- اطلاعات اتصال به سرویسهای خارجی
- تنظیمات ایمیل و سرویسهای پرداخت
این فایل نباید در مخزن عمومی Git قرار بگیرد یا از طریق وب در دسترس باشد.
موارد زیر را رعایت کنید:
- فایل
.envواقعی را در مخزن عمومی منتشر نکنید. - فایل
.env.exampleرا بدون اطلاعات محرمانه نگه دارید. - دسترسی فایلهای محیطی را در سرور محدود کنید.
- Secretها را در لاگها یا پیامهای خطا چاپ نکنید.
- در صورت افشای یک کلید، آن را در سرویس مربوطه باطل یا تعویض کنید.
- برای محیط توسعه، آزمایش و تولید از Secretهای جداگانه استفاده کنید.
مهمترین اقدام در پیکربندی وبسرور این است که ریشه عمومی سایت روی پوشه public پروژه Laravel قرار بگیرد، نه پوشه اصلی آن.
۱۱. جلوگیری از افشای اطلاعات در Logها
ثبت خطا برای نگهداری و عیبیابی برنامه ضروری است، اما Logها ممکن است بهصورت ناخواسته اطلاعات حساسی را در خود ذخیره کنند.
برای مثال، ثبت کامل درخواست پرداخت، هدرهای احراز هویت، رمز عبور یا توکنهای دسترسی میتواند اطلاعات محرمانه را در اختیار افراد دارای دسترسی به فایلهای Log قرار دهد.
بهتر است:
- رمز عبور و توکنهای محرمانه را ثبت نکنید.
- اطلاعات حساس را پیش از ثبت در Log حذف یا ماسک کنید.
- دسترسی به فایلهای Log را محدود کنید.
- برای نگهداری و حذف خودکار Logها سیاست مشخصی داشته باشید.
- خطاهای داخلی را بهجای نمایش به کاربران، در محل مناسب ثبت کنید.
در Laravel میتوانید از سیستم Logging برای ثبت پیامهای قابلکنترل استفاده کنید:
use Illuminate\Support\Facades\Log;
Log::warning('Payment provider request failed', [
'order_id' => $order->id,
]);
این نمونه فقط شناسه سفارش را ثبت میکند و از ثبت اطلاعات محرمانه درخواست جلوگیری میکند.
۱۲. محدود کردن درخواستهای ورود و API
محدود کردن تعداد درخواستها یا Rate Limiting میتواند به کاهش سوءاستفاده از برخی Endpointها کمک کند؛ برای مثال، مسیرهای ورود، ارسال کد تأیید، بازیابی رمز عبور یا APIهای پرهزینه.
Laravel امکان تعریف Rate Limiter و استفاده از Middleware مربوط به محدودیت درخواست را فراهم میکند.
نمونهای از استفاده از Middleware آماده:
Route::middleware('throttle:10,1')->group(function () {
Route::post('/login', [AuthController::class, 'login']);
});
این نمونه از یک محدودیت کلی درخواست استفاده میکند. در سامانههای واقعی، بهتر است محدودیتها بر اساس حساسیت Endpoint، کاربر، IP یا شناسه مناسب طراحی شوند.
برای ورود و ارسال OTP، علاوه بر Rate Limiting باید مواردی مانند جلوگیری از حدسزدن رمز، محدود کردن ارسال مکرر پیامک، انقضای کد و جلوگیری از استفاده مجدد از کد تأیید نیز در نظر گرفته شوند.
محدود کردن درخواستها بهتنهایی جایگزین احراز هویت و کنترل مجوز دسترسی نیست.
۱۳. امنسازی APIهای Laravel
اگر Laravel برای یک اپلیکیشن موبایل، پنل جداگانه یا سرویس خارجی API ارائه میکند، باید احراز هویت و مجوز دسترسی API را بهدرستی پیادهسازی کنید.
چند اصل مهم عبارتاند از:
- از سازوکار احراز هویت مناسب معماری API استفاده کنید.
- توکنهای دسترسی را در محل امن نگهداری کنید.
- برای هر Endpoint، مجوز لازم را بررسی کنید.
- از ارسال اطلاعات حساس در URL خودداری کنید.
- ورودیها را اعتبارسنجی کنید.
- برای Endpointهای پرهزینه Rate Limiting تعریف کنید.
- فقط فیلدهای لازم را در پاسخ API برگردانید.
- ارتباطات حساس را از طریق HTTPS برقرار کنید.
برای APIهای مبتنی بر توکن، Laravel Sanctum میتواند در سناریوهای مناسب انتخاب خوبی باشد. بااینحال، استفاده از Sanctum بهتنهایی تضمین نمیکند که تمام Endpointها مجوزهای درستی دارند؛ کنترل مالکیت منابع و مجوز عملیات همچنان ضروری است.
۱۴. بهروزرسانی وابستگیها و پکیجها
وابستگیهای قدیمی ممکن است شامل آسیبپذیریهای امنیتی شناختهشده باشند. بنابراین باید نسخه Laravel، PHP و پکیجهای پروژه را متناسب با نیازمندیها و سیاست پشتیبانی آنها بهروز نگه دارید.
برای مشاهده وابستگیهای نصبشده میتوانید از Composer استفاده کنید:
composer show
برای بررسی تغییرات قابلدسترس نیز:
composer outdated
برای بررسی آسیبپذیریهای شناختهشده در وابستگیهای Composer، در نسخههای سازگار Composer میتوانید از دستور زیر استفاده کنید:
composer audit
پیش از بهروزرسانی در محیط تولید، تغییرات نسخهها را بررسی کنید، تستها را اجرا کنید و از پایگاه داده و فایلهای مهم نسخه پشتیبان تهیه کنید.
از بهروزرسانی کورکورانه تمام پکیجها روی سرور اصلی خودداری کنید؛ تغییرات ناسازگار ممکن است باعث اختلال در برنامه شوند.
۱۵. چکلیست امنیت Laravel پیش از انتشار
قبل از انتشار یا بهروزرسانی پروژه، این موارد را بررسی کنید:
- [ ] مقدار
APP_DEBUGدر محیط تولیدfalseاست. - [ ] فایل
.envاز دسترسی عمومی محافظت شده است. - [ ] مسیر ریشه سایت روی پوشه
publicتنظیم شده است. - [ ] ورودیها در سمت سرور اعتبارسنجی میشوند.
- [ ] کوئریها از Binding امن استفاده میکنند.
- [ ] فرمهای وب محافظت CSRF مناسبی دارند.
- [ ] خروجیهای HTML بهصورت امن Escape میشوند.
- [ ] رمزهای عبور با سازوکار Hash مناسب ذخیره میشوند.
- [ ] مجوز دسترسی به منابع و عملیات حساس بررسی میشود.
- [ ] فایلهای آپلودی محدودیت نوع و اندازه دارند.
- [ ] APIها احراز هویت و Rate Limiting مناسب دارند.
- [ ] اطلاعات محرمانه در Logها ثبت نمیشوند.
- [ ] وابستگیها و پکیجها از نظر آسیبپذیری بررسی شدهاند.
- [ ] HTTPS برای ارتباطات حساس فعال است.
- [ ] نسخه پشتیبان و فرایند بازیابی بررسی شدهاند.
پرسشهای متداول
آیا Laravel بهصورت پیشفرض امن است؟
Laravel امکانات امنیتی مهمی مانند محافظت CSRF، Query Binding و سیستم Hash رمز عبور ارائه میدهد. اما امنیت نهایی به پیادهسازی صحیح برنامه، مدیریت دسترسیها، اعتبارسنجی ورودیها و تنظیمات سرور وابسته است.
مهمترین اشتباه امنیتی در پروژه Laravel چیست؟
یک اشتباه مهم، اعتماد به احراز هویت بدون بررسی مجوز دسترسی است. ممکن است کاربر وارد سیستم شده باشد، اما نباید به سفارشها یا اطلاعات کاربران دیگر دسترسی داشته باشد.
آیا استفاده از Eloquent مانع SQL Injection میشود؟
استفاده صحیح از Eloquent و Query Builder با پارامترهای Binding بسیاری از خطرهای متداول SQL Injection را کاهش میدهد. اما بخشهایی مانند نام ستونها و دستورهای SQL پویا همچنان باید با ورودیهای محدودشده و کنترلشده مدیریت شوند.
آیا غیرفعال کردن APP_DEBUG کافی است؟
خیر. غیرفعال کردن Debug از افشای بخشی از جزئیات خطا جلوگیری میکند، اما جایگزین کنترل دسترسی، محافظت از فایلهای محرمانه، اعتبارسنجی ورودیها و سایر اقدامات امنیتی نیست.
برای امنسازی API لاراول چه باید کرد؟
باید احراز هویت مناسب، کنترل مجوز هر عملیات، اعتبارسنجی ورودیها، Rate Limiting، محافظت از توکنها و ارتباط امن HTTPS را متناسب با معماری API پیادهسازی کنید.
جمعبندی
امنیت Laravel مجموعهای از اقدامات مرتبط با کدنویسی، پیکربندی و مدیریت سرور است. استفاده از قابلیتهای داخلی Laravel میتواند بسیاری از خطرهای رایج را کاهش دهد، اما برای ساخت یک برنامه امن باید همه لایهها را بررسی کرد.
از غیرفعال کردن Debug و محافظت در برابر SQL Injection گرفته تا کنترل مجوزهای دسترسی، مدیریت فایلهای آپلودی و بررسی وابستگیها، هر کدام بخشی از فرایند امنسازی پروژه هستند.
بهترین رویکرد این است که امنیت را از ابتدای توسعه در نظر بگیرید و پیش از هر انتشار، چکلیست امنیتی پروژه را بررسی کنید.





