وصفات الوكيل العكسي وعقد ردّ النداء
كل وكيل عكسي يحتاج القطعتين نفسيهما: فحص مُخوِّل يسأل Caputchin إن كان طلب يحمل تصريحًا صالحًا، وردّ نداء على أصلك يحوّل تصريحًا محلولًا إلى كوكي cpt_gate. شرح nginx يبيّن الشكل من طرف إلى طرف؛ وهذه الصفحة تعطي الوكلاء الآخرين، وعقد ردّ النداء بالضبط، ومثال Authelia كاملًا. استبدِل YOUR_SITE_KEY بمفتاحك العامّ في كل موضع.
نقاط الوصول هي نفسها في كل مكان:
- المُخوِّل:
GET https://verify.caputchin.com/v1/gate/authz?site=YOUR_SITE_KEY، مع تمرير ترويسةCookieالخاصّة بالزائر.204تعني اسمح، و401تعني تحدٍّ. - التحدّي: أعِد توجيه المتصفّح إلى
https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return=<الرابط الأصلي>.
Traefik
استخدِم وسيطة forwardAuth للمُخوِّل. يمرّر Traefik ترويسة Cookie الواردة افتراضيًّا. عند 401 من الوسيطة، أعِد توجيه المتصفّح إلى التحدّي (وسيطة صفحة خطأ موجّهة إلى مسار صغير يُصدِر 302، أو عالِج 401 عند حافّتك).
http:
middlewares:
cpt-gate:
forwardAuth:
address: "https://verify.caputchin.com/v1/gate/authz?site=YOUR_SITE_KEY"
# The 401 from forwardAuth is your signal to send the browser to:
# https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return=<original-url>
routers:
portal:
rule: "Host(`auth.example.com`)"
middlewares: ["cpt-gate"]
service: your-appCaddy
استخدِم forward_auth للمُخوِّل وhandle_errors لتحويل 401 إلى إعادة توجيه. هذه نقطة بداية؛ اضبط صياغة التوجيهات لإصدار Caddy عندك.
auth.example.com {
forward_auth https://verify.caputchin.com {
uri /v1/gate/authz?site=YOUR_SITE_KEY
copy_headers Cookie
}
handle_errors {
@challenge expression {http.error.status_code} == 401
redir @challenge https://verify.caputchin.com/v1/gate/challenge?site=YOUR_SITE_KEY&return={scheme}://{host}{uri} 302
}
reverse_proxy your-app:8080
}ردّ النداء
تنتهي صفحة التحدّي المُستضافة بإرسال ذاتي لنموذج POST إلى https://<أصلك>/__cpt/callback بحقلين في الجسم: cpt_gate (التصريح) وto (إلى أين يُرسَل الزائر). أضِف هذا المسار الواحد إلى أصلك (أو ككتلة location مخصّصة على الوكيل). يجب أن:
- يقرأ
cpt_gateوtoمن جسم POST، لا من الرابط أبدًا (تصريح في رابط يتسرّب إلى السجلّات والمُحيلين). - يؤكّد أن
toعلى أصلك أنت، ويرفض ما عداه، كي لا يُحوَّل ردّ النداء إلى إعادة توجيه مفتوحة. - يضبط الكوكي بالسمات أدناه.
- يعيد التوجيه (
303) إلىto.
// Any tiny handler on your origin works. Express shown; ~15 lines.
app.post("/__cpt/callback", express.urlencoded({ extended: false }), (req, res) => {
const pass = String(req.body.cpt_gate || "");
const to = String(req.body.to || "/");
const target = new URL(to, `https://${req.headers.host}`);
if (target.host !== req.headers.host) return res.status(400).end(); // same-origin only
res.setHeader(
"Set-Cookie",
`cpt_gate=${pass}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=1800`
);
res.redirect(303, target.pathname + target.search);
});سمات الكوكي هي نموذج الأمان كلّه. ولأن التصريح غير مربوط بجهاز، فإن HttpOnly (يحجب سرقة السكربت)، وSecure (HTTPS فقط)، وSameSite=Lax، وMax-Age قصير (طابِقه مع مدّة السماح TTL) هي ما يحميه. وأيضًا: لا تسجّل قيمة cpt_gate في سجلّات وصولك، وأبقِ Referrer-Policy: no-referrer على ردّ النداء كي لا يركب التصريح أبدًا في ترويسة مُحيل.
مثال محلول: Authelia
بوّابة تسجيل الدخول في Authelia تطبيق أحادي الصفحة مُصرَّف بلا مكان لإدراج الأداة وبلا خطّاف إضافة، فالبوّابة هي طريقة حمايته. Authelia تجلس أصلًا خلف وكيل عكسي (هكذا يعمل ForwardAuth الخاصّ بها)، وذلك الوكيل هو موضع البوّابة. وAuthelia نفسها تُترَك دون أي تعديل بتاتًا.
ضَع البوّابة على vhost البوّابة (مثلًا auth.example.com):
- أغلِق ببوّابة HTML البوّابة ونقطة وصول تسجيل الدخول بالعامل الأول (
/api/firstfactor). - استثنِ نقطة وصول verify الخاصّة بـ ForwardAuth في Authelia (
/api/verify)، التي يناديها الوكيل لكل طلب upstream محمي. إغلاقها ببوّابة سيكسر كل تطبيق محمي خلف Authelia. - استثنِ فحوص السلامة والأصول الساكنة التي تحتاجها صفحة التحدّي نفسها.
- أضِف مسار
/__cpt/callbackكما أعلاه.
تُبقي البوّابة البوتات بعيدة عن البوّابة؛ ويظلّ Regulation المدمج في Authelia (حدّ المحاولات والحظر) يسقّف محاولات بيانات الاعتماد لمن يمرّ، فتتراكم الطبقتان. تحمي البوّابة البوّابة التفاعلية فقط (واجهة تسجيل الدخول والموافقة)؛ ولا تُغلق، ولا ينبغي أن تُغلق، نقاط وصول الرموز غير التفاعلية.
انظر أيضًا
- أعدّ بوّابة الوكيل: شرح nginx والطرح بوضع المعاينة أولًا.
- نظرة عامة: الفكرة وكوكي السماح.
- الإحصاءات: أكّد التوصيل بمراقبة التحدّي مقابل المرور المباشر.