Lesson 3 / الدرس 3
What the web can reach, and who owns it / ما يستطيع الويب بلوغه، ومن يملكه
Two questions decide most of a server's security, and both have short answers: which directory does a URL map onto, and which user is the code running as. Getting them right is structural — it protects you from mistakes you have not made yet.
سؤالان يقرران معظم أمن الخادم، ولكليهما جواب قصير: أيُّ مجلد يقابله الرابط، وأيُّ مستخدم يعمل الكود بصفته. وضبطهما بنيوي — فهو يحميك من أخطاء لم ترتكبها بعد.
A web server maps URLs onto one directory. Everything inside it is fetchable by anyone who guesses the name; everything outside it cannot be named by a URL at all. That single boundary is the cheapest security you will ever get, and it is set once when the site is configured.
/home/site/
config.php not reachable — no URL maps here
src/ not reachable
views/ not reachable
content/ not reachable
storage/
logs/ not reachable (and must NOT be)
uploads/ not reachable (see chapter 4)
vendor/ not reachable
public_html/ <- the document root. THIS is the web.
index.php the front controller
assets/ css, js, images
bin/deploy.sh exists to maintain it: the repository's public/ goes to public_html/, and everything else goes one level above. The split is not a convention, it is the security model — a mistake in a view cannot expose config.php because no URL reaches it. bin/deploy.sh موجود لصيانته: فـpublic/ في المستودع تذهب إلى public_html/، وكل ما عداها يذهب فوقها بمستوى. والفصل ليس اصطلاحًا بل هو نموذج الأمن — فالخطأ في عرضٍ لا يستطيع كشف config.php لأن لا رابط يبلغه.Whoever the code runs as, is who an attacker becomes
# Who am I, on this server?
$ php -r 'echo get_current_user();'
$ ps aux | grep php-fpm
# Directories: enter and list. Files: read.
$ find /home/site -type d -exec chmod 755 {} +
$ find /home/site -type f -exec chmod 644 {} +
# Only what genuinely has to be written to.
$ chmod 775 /home/site/storage/logs /home/site/storage/uploads
# The one that is only for you.
$ chmod 600 /home/site/config.php
# 777 is not a fix. It is 'anyone on this machine may rewrite this',
# and it is the answer to a permissions error roughly never.
Things that end up in a document root by accident
| What | What it gives away |
|---|---|
| .git/ | Your entire source history, including deleted secrets |
| .env, config.bak, config.php~ | Credentials — editors and editors' backups leave these |
| phpinfo.php | Paths, extensions, versions — a map for choosing an exploit |
| adminer.php, db.php | Direct database access, often left after "just for a minute" |
| error_log, debug.log | Your bugs, with file paths and sometimes user data |
| *.sql, backup.zip | The whole database, downloadable |
.git/ is the one that surprises people: rsync and FTP copy hidden directories, so a deploy that syncs the repository puts it in the document root, and anyone can then reconstruct your full source and every secret you ever committed. This site's deploy script excludes it explicitly.
.git/ هي ما يفاجئ الناس: فـrsync وFTP ينسخان المجلدات المخفية، فالنشر الذي يزامن المستودع يضعها في جذر المستند، ويستطيع أي أحد عندئذ إعادة بناء مصدرك الكامل وكل سرٍّ أودعته يومًا. وبرنامج النشر في هذا الموقع يستثنيها صراحة.your-site.com/.git/config و/config.php و/storage/logs/php.log في متصفح وانظر ما يعود. فـ200 بمحتوى إفشاء حيّ؛ و403 أو 404 هو ما تريد — وهذا يستغرق ثلاثين ثانية على موقع تعتقد أصلًا أنه مضبوط صحيحًا، وذلك بعينه حين يستحق فعله.public/ في مستودعك. وليس ذلك سببًا لوضع كل شيء فيه: بل قسّم النشر، فالتطبيق فوق والأصول بالداخل، وهذا ما يفعله bin/deploy.sh هنا وسبب مزامنته مجلدًا مجلدًا.Check yourself / اختبر نفسك
1. Why must .git/ never be inside the document root?
rsync and FTP copy hidden directories, so a deploy that syncs the repository puts it there without anyone deciding to. Excluding it explicitly is the fix.
2. Why should PHP not be able to write to its own source directory?
Permissions decide what a bug can do. Writable should be a short list you can recall from memory: logs, uploads, and usually nothing else.
3. How do you know your web root boundary is actually configured correctly?
A 200 with content is a live disclosure. It takes thirty seconds and is most worth doing on a site you already believe is configured correctly.
Score / النتيجة: 0 / 3