Lesson 11 / الدرس 11
Six headers and a certificate / ست ترويسات وشهادة
A short block of headers, written once, closes several whole classes of attack. It is the best return on effort available anywhere in this course — and almost every small site ships without it because nothing visibly breaks when it is missing.
كتلة قصيرة من الترويسات، تُكتب مرة، تغلق أصنافًا كاملة من الهجمات. وهي أفضل عائد على جهد متاح في هذه الدورة كلها — ومع ذلك يُشحن كل موقع صغير تقريبًا بدونها لأن شيئًا لا ينكسر ظاهريًا حين تغيب.
HTTPS is free and automatic now, so the remaining question is not whether to use it but whether anything is still reachable without it. A site that answers on both schemes has a plain-text version of itself available to anyone on the network, and a session cookie sent once over that version is a session someone else can use.
The block, and what each line prevents
<?php
// This site's src/bootstrap.php, shortened. Sent on every response.
header(
"Content-Security-Policy: default-src 'self'; "
. "script-src 'self' 'nonce-" . csp_nonce() . "'; "
. "img-src 'self' data:; object-src 'none'; "
. "form-action 'self'; frame-ancestors 'none'"
);
header('X-Frame-Options: DENY');
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: strict-origin-when-cross-origin');
// Only over HTTPS. Sent on a plain-HTTP response it is ignored, and on
// a local http host it would pin a scheme the dev site does not serve.
if (is_https()) {
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
}
| Header | What it stops |
|---|---|
| Content-Security-Policy | Injected script running — a second wall behind escaping, for the hole you missed |
| Strict-Transport-Security | The browser ever using plain HTTP again, including on the first click of a typed address |
| frame-ancestors / X-Frame-Options | Your site being loaded invisibly inside someone else's and clicked through |
| X-Content-Type-Options: nosniff | An uploaded file being guessed into a type it was not served as |
| Referrer-Policy | Full URLs — which can hold ids and tokens — leaking to every site you link to |
| form-action | An injected form posting your visitor's data to somebody else's server |
The CSP row is worth reading twice. It does not replace escaping — it is what catches the one place you forgot to escape, which on a site of any size there eventually is. Defences that assume you got everything right are not defences.
A policy that fits the site you have
A strict CSP is a real constraint, and it is worth knowing that before you write the application rather than after. Inline <script> blocks, onclick attributes, eval, and scripts loaded from a CDN all stop working under script-src 'self'. On this site that is why every animation is CSS rather than JavaScript, and why nothing loads from a CDN — the policy came first and the design followed it.
<script> الداخلية، وسمات onclick، وeval، والبرامج المحمّلة من شبكة توزيع، كلها تكفّ عن العمل تحت script-src 'self'. وفي هذا الموقع لهذا كانت كل حركة CSS لا JavaScript، ولهذا لا يُحمَّل شيء من شبكة توزيع — فالسياسة جاءت أولًا وتبعها التصميم.Strict-Transport-Security غير قابلة للعكس على المدى الذي تريده. فحالما يراها متصفح، يرفض ذلك المتصفح HTTP الصريح لنطاقك سنةً، وincludeSubDomains تمدّ ذلك إلى كل نطاق فرعي — بما فيها ما ليس له شهادة بعد. فابدأ بـmax-age قصيرة، وتأكد أن كل نطاق فرعي يُقدَّم عبر HTTPS، ثم ارفعها بعد ذلك فقط؛ فالخطأ في هذا يُخرج موقعًا من الويب لزوار سبق أن زاروه.Check yourself / اختبر نفسك
1. What does a Content-Security-Policy protect against that escaping does not?
Defences that assume you got everything right are not defences. The policy costs a header and catches the case your discipline did not.
2. Why start with a short max-age on Strict-Transport-Security?
Getting it wrong takes the site off the web for people who have already visited, and there is no way to reach their browsers to undo it. Confirm every subdomain first.
3. Why does a strict CSP need to be decided before the application is built?
It can be added later, but doing so means rewriting whatever it breaks. This site has CSS animations and no CDN because the policy came first.
Score / النتيجة: 0 / 3