میان افزار net/http/middleware
سرآیندهای رایج امنیت، کش و CORS و ثبت درخواستها، در یک صدا زدن.
واردسازی شبکه.اچ تی تی پی.میان افزار
پنج تابع کمکی کوچک برای گردانندههای اچ تی تی پی: اجازه به همه برای CORS، امن برای سرآیندهای امنیتی پایه، بدون کش و کش برای کش، و ثبت رخداد برای یک سطر به ازای هر درخواست. هر کدام مثل خود گرداننده شناسهی زمینه را میگیرد و فقط سرآیند پاسخ میگذارد (یا چاپ میکند)، پس آنها را در سطرهای اول گرداننده صدا میزنید.
سلام زنجیرهی میانافزار ندارد و نمیشود گرداننده را از بیرون پوشاند. میانافزار یک تابع معمولی است که با شناسهی زمینه صدا زده میشود و سرآیندهایی که میگذارد همراه هر چیزی که گرداننده پس از آن مینویسد فرستاده میشوند. اینطور ترتیب کار در خود گرداننده پیداست. برای ورود کاربر نشست و برای بررسی ورودی اعتبارسنجی را ببینید.
پیش از تکیه بر این تابعها بدانید:
اجازه به همهروشPATCHرا فهرست نمیکند. برای همهی مبدأها روشهای GET، POST، PUT، DELETE و OPTIONS را با سرآیندهایContent-TypeوAuthorizationمجاز میکند. مرورگر PATCH از مبدأ دیگر را رد میکند و*با کوکی کار نمیکند؛ برای اینها قاعدهی خودتان را بنویسید (بخش آخر).امنحداقل است.nosniff،X-Frame-Options: DENYوX-XSS-Protectionرا میگذارد که مرورگرهای امروزی نادیدهاش میگیرند.Content-Security-PolicyوStrict-Transport-Securityنمیگذارد.- آخرین فراخوانی برنده است. سرآیندی که دو بار با یک نام گذاشته شود مقدار آخر را نگه میدارد، پس
بدون کشو پس از آنکشفقطmax-ageرا باقی میگذارد. ثبت رخدادپیش از اجرای گرداننده باسرچاپچاپ میکند، پس وضعیت را نشان نمیدهد؛اچ تی تی پی.فعال سازی گزارش دسترسیروی سرور وضعیت را هم ثبت میکند.
CORS برای API که از مرورگر صدا زده میشود
صفحهای از یک مبدأ دیگر فقط وقتی میتواند API شما را صدا بزند که پاسخ اجازه دهد. برای هر چیزی جز یک GET ساده، مرورگر اول یک درخواست OPTIONS میفرستد که به آن پیشپرواز میگویند و سرآیندهای Access-Control-Allow-* پاسخ را بررسی میکند. یک مسیر OPTIONS ثبت کنید که اجازه به همه را صدا بزند و با ۲۰۴ و بدون بدنه پاسخ دهد، و در گردانندهی اصلی هم اجازه به همه را صدا بزنید.
واردسازی شبکه.اچ تی تی پی
واردسازی شبکه.اچ تی تی پی.میان افزار
واردسازی شبکه.مسیریاب
تابع پیش پرواز(ز: صحیح۶۴):
میان افزار.اجازه به همه(ز)
اچ تی تی پی.تنظیم وضعیت(ز، ۲۰۴)
اچ تی تی پی.متن(ز، "")
پایان
تابع یادداشتها(ز: صحیح۶۴):
میان افزار.اجازه به همه(ز)
میان افزار.بدون کش(ز)
اچ تی تی پی.جیسون(ز، `[{"id":1,"text":"نان بخر"}]`)
پایان
تابع ریشه:
ناپایا م := مسیریاب.مسیریاب جدید()
مسیریاب.گزینه ها(م، "/api/notes"، پیش پرواز)
مسیریاب.دریافت(م، "/api/notes"، یادداشتها)
ناپایا س := اچ تی تی پی.سرور جدید(۱۹۷۸۵)
اچ تی تی پی.استفاده(س، م)
_ := اچ تی تی پی.اجرا در پس زمینه(س)
نشانی := "http://127.0.0.1:19785/api/notes"
ناپایا سر := اچ تی تی پی.سرصفحه جدید()
سر.درج("Origin"، "https://app.example.com")
سر.درج("Access-Control-Request-Method"، "GET")
پ := اچ تی تی پی.گزینه ها با(نشانی، سر)
سرچاپ "پیش پرواز:"، اچ تی تی پی.وضعیت(پ)
هر نام در ["access-control-allow-origin"، "access-control-allow-methods"، "access-control-allow-headers"]:
سرچاپ " " + نام + ": " + اچ تی تی پی.دریافت سرصفحه(پ، نام)
پایان
د := اچ تی تی پی.دریافت با(نشانی، سر)
سرچاپ "دریافت:"، اچ تی تی پی.وضعیت(د)، اچ تی تی پی.بدنه(د)
سرچاپ " cache-control: " + اچ تی تی پی.دریافت سرصفحه(د، "cache-control")
سرچاپ " pragma: " + اچ تی تی پی.دریافت سرصفحه(د، "pragma")
پایاناجازه به همه به همهی مبدأها، روشهای GET، POST، PUT، DELETE و OPTIONS (نه PATCH) و سرآیندهای Content-Type و Authorization اجازه میدهد. این برای یک API عمومی و فقطخواندنی مناسب است. APIای که کوکی یا سرآیندهای دیگر به کار میبرد قاعدهی خودش را لازم دارد، همانطور که بخش آخر نشان میدهد.
یک تابع کمکی برای هر نوع پاسخ
به جای تکرار همان صدا زدنها در ابتدای هر گرداننده، آنها را برای هر نوع پاسخ در یک تابع جمع کنید: صفحههای خصوصی که نباید کش شوند و نباید در قاب دیده شوند، و پروندههای عمومی که مرورگر میتواند نگه دارد. امن سرآیندهای nosniff، X-Frame-Options: DENY و سرآیند XSS را میگذارد؛ بدون کش کش کردن را ممنوع میکند؛ کش آن را برای چند ثانیهی دادهشده مجاز میکند.
واردسازی شبکه.اچ تی تی پی
واردسازی شبکه.اچ تی تی پی.میان افزار
واردسازی شبکه.مسیریاب
تابع سرآیند صفحه(ز: صحیح۶۴):
میان افزار.امن(ز)
میان افزار.بدون کش(ز)
پایان
تابع سرآیند فایل(ز: صحیح۶۴، ثانیه: صحیح):
میان افزار.کش(ز، ثانیه)
پایان
تابع حساب(ز: صحیح۶۴):
سرآیند صفحه(ز)
اچ تی تی پی.اچ تی ام ال(ز، "<h1>حساب شما</h1>")
پایان
تابع نشان(ز: صحیح۶۴):
سرآیند فایل(ز، ۸۶۴۰۰)
اچ تی تی پی.متن(ز، "logo bytes")
پایان
تابع اخبار(ز: صحیح۶۴):
سرآیند فایل(ز، ۶۰)
اچ تی تی پی.جیسون(ز، `["نسخه 0.5.5"]`)
پایان
تابع ریشه:
ناپایا م := مسیریاب.مسیریاب جدید()
مسیریاب.دریافت(م، "/account"، حساب)
مسیریاب.دریافت(م، "/logo.svg"، نشان)
مسیریاب.دریافت(م، "/news.json"، اخبار)
ناپایا س := اچ تی تی پی.سرور جدید(۱۹۷۸۶)
اچ تی تی پی.استفاده(س، م)
_ := اچ تی تی پی.اجرا در پس زمینه(س)
پایه := "http://127.0.0.1:19786"
هر مسیر در ["/account"، "/logo.svg"، "/news.json"]:
پ := اچ تی تی پی.دریافت(پایه + مسیر)
سرچاپ مسیر + " cache-control=" + اچ تی تی پی.دریافت سرصفحه(پ، "cache-control") + " frame=" + اچ تی تی پی.دریافت سرصفحه(پ، "x-frame-options")
پایان
پایانثبت رخداد برای هر درخواست یک خط با روش و مسیر چاپ میکند که هنگام توسعه کمک میکند. در محیط واقعی، اچ تی تی پی.فعال سازی گزارش دسترسی روی سرور هر درخواست را با وضعیتش ثبت میکند، بی آنکه در هر گرداننده چیزی صدا بزنید.
سرآیندهای سختگیرانهتر برای صفحههای خصوصی
برای صفحهی فاکتور یا حساب کاربری، سرآیندهایی را که امن نمیگذارد خودتان اضافه کنید: یک Content-Security-Policy که فقط اجازهی بارگیری از مبدأ خود صفحه را میدهد، Strict-Transport-Security تا مرورگر روی HTTPS بماند (فقط وقتی سایت روی HTTPS است بفرستید) و یک Referrer-Policy. مسیر دوم قاعدهی «آخرین فراخوانی برنده است» را نشان میدهد: بدون کش و سپس کش را صدا میزند و پاسخ فقط یک Cache-Control با مقدار دوم دارد.
واردسازی شبکه.اچ تی تی پی
واردسازی شبکه.اچ تی تی پی.میان افزار
واردسازی شبکه.مسیریاب
تابع سختگیرانه(ز: صحیح۶۴):
میان افزار.امن(ز)
اچ تی تی پی.تنظیم سرصفحه(ز، "Content-Security-Policy"، "default-src 'self'")
اچ تی تی پی.تنظیم سرصفحه(ز، "Strict-Transport-Security"، "max-age=31536000")
اچ تی تی پی.تنظیم سرصفحه(ز، "Referrer-Policy"، "same-origin")
پایان
تابع فاکتور(ز: صحیح۶۴):
سختگیرانه(ز)
میان افزار.بدون کش(ز)
اچ تی تی پی.اچ تی ام ال(ز، "<h1>فاکتور ۱۰۴۲</h1>")
پایان
تابع گزارش(ز: صحیح۶۴):
میان افزار.بدون کش(ز)
میان افزار.کش(ز، ۳۰۰)
اچ تی تی پی.متن(ز، "گزارش ماهانه")
پایان
تابع ریشه:
ناپایا م := مسیریاب.مسیریاب جدید()
مسیریاب.دریافت(م، "/invoice"، فاکتور)
مسیریاب.دریافت(م، "/report"، گزارش)
ناپایا س := اچ تی تی پی.سرور جدید(۱۸۶۴۲)
اچ تی تی پی.تنظیم میزبان(س، "127.0.0.1")
اچ تی تی پی.استفاده(س، م)
اگر وارونه اچ تی تی پی.اجرا در پس زمینه(س):
سرچاپ "درگاه ۱۸۶۴۲ گرفته است"
برگشت ۱
پایان
الف := اچ تی تی پی.دریافت("http://127.0.0.1:18642/invoice")
هر نام در ["x-frame-options"، "content-security-policy"، "strict-transport-security"، "referrer-policy"]:
سرچاپ نام + ": " + اچ تی تی پی.دریافت سرصفحه(الف، نام)
پایان
ب := اچ تی تی پی.دریافت("http://127.0.0.1:18642/report")
سرچاپ "سطرهای cache-control در /report:"، اچ تی تی پی.مقادیر سرصفحه(ب، "cache-control")
برگشت ۰
پایانسیاست default-src 'self' اسکریپت درونخطی <script> و ویژگی style را هم میبندد، پس پیش از روشن کردنش صفحههایتان را با آن بیازمایید.
نوشتن میانافزار خودتان
وقتی سرآیندهای آماده مناسب نیستند، تابعی با همان شکل بنویسید. تابعی که فقط سرآیند اضافه میکند چیزی برنمیگرداند. تابعی که ممکن است درخواست را متوقف کند منطقی برمیگرداند: خودش پاسخ خطا را مینویسد و نادرست برمیگرداند، و گرداننده همانجا برمیگردد. این نمونه فقط به یک مبدأ مورد اعتماد اجازه میدهد و فقط بدنهی جیسون میپذیرد.
واردسازی شبکه.اچ تی تی پی
واردسازی شبکه.اچ تی تی پی.میان افزار
واردسازی شبکه.مسیریاب
تابع اجازه به مبدا(ز: صحیح۶۴، مبدا: رشته):
اگر اچ تی تی پی.سرصفحه(ز، "Origin") برابر مبدا:
اچ تی تی پی.تنظیم سرصفحه(ز، "Access-Control-Allow-Origin"، مبدا)
اچ تی تی پی.تنظیم سرصفحه(ز، "Vary"، "Origin")
پایان
پایان
تابع جیسون لازم(ز: صحیح۶۴): منطقی:
اگر اچ تی تی پی.سرصفحه(ز، "Content-Type").شروع با("application/json"):
برگشت درست
پایان
اچ تی تی پی.تنظیم وضعیت(ز، ۴۱۵)
اچ تی تی پی.جیسون(ز، `{"error":"جیسون بفرستید"}`)
برگشت نادرست
پایان
تابع ثبت سفارش(ز: صحیح۶۴):
میان افزار.امن(ز)
اجازه به مبدا(ز، "https://shop.example.com")
اگر وارونه جیسون لازم(ز): برگشت پایان
اچ تی تی پی.تنظیم وضعیت(ز، ۲۰۱)
اچ تی تی پی.جیسون(ز، اچ تی تی پی.بدنه(ز))
پایان
تابع ریشه:
ناپایا م := مسیریاب.مسیریاب جدید()
مسیریاب.ارسال(م، "/orders"، ثبت سفارش)
ناپایا س := اچ تی تی پی.سرور جدید(۱۹۷۸۷)
اچ تی تی پی.استفاده(س، م)
_ := اچ تی تی پی.اجرا در پس زمینه(س)
نشانی := "http://127.0.0.1:19787/orders"
ناپایا سرآیند مجاز := اچ تی تی پی.سرصفحه جدید()
سرآیند مجاز.درج("Origin"، "https://shop.example.com")
سرآیند مجاز.درج("Content-Type"، "application/json")
پ := اچ تی تی پی.ارسال با(نشانی، `{"item":"چای"}`، سرآیند مجاز)
سرچاپ اچ تی تی پی.وضعیت(پ)، اچ تی تی پی.بدنه(پ)، "[" + اچ تی تی پی.دریافت سرصفحه(پ، "access-control-allow-origin") + "]"
ناپایا بیگانه := اچ تی تی پی.سرصفحه جدید()
بیگانه.درج("Origin"، "https://evil.example")
بیگانه.درج("Content-Type"، "text/plain")
ب := اچ تی تی پی.ارسال با(نشانی، "item=tea"، بیگانه)
سرچاپ اچ تی تی پی.وضعیت(ب)، اچ تی تی پی.بدنه(ب)، "[" + اچ تی تی پی.دریافت سرصفحه(ب، "access-control-allow-origin") + "]"
پایانهر جا پاسخ به سرآیند Origin بستگی دارد، Vary: Origin را هم بفرستید تا کش مشترک پاسخ یک مبدأ را به مبدأ دیگری ندهد.
کدام تابع برای کدام کار
| کار | تابع |
|---|---|
| صفحههای هر مبدأیی بتوانند API را صدا بزنند | اجازه به همه |
| محافظت پایه برای صفحههای HTML | امن |
| صفحههای دارای دادهی خصوصی | بدون کش |
| تصویر، سبک و اسکریپتی که کم تغییر میکند | کش با شمار ثانیه |
| دیدن درخواستها هنگام توسعه | ثبت رخداد |
تابعها
ثبت رخداد Log
تابع ثبت رخداد(ctx: صحیح۶۴)[HTTP]، روش و مسیر درخواست را در خروجی استاندارد چاپ میکند؛ وضعیت را نه، چون پیش از پاسخ گرداننده اجرا میشود.واردسازی شبکه.اچ تی تی پی
واردسازی شبکه.اچ تی تی پی.میان افزار
واردسازی شبکه.مسیریاب
تابع خانه(ز: صحیح۶۴):
میان افزار.ثبت رخداد(ز)
میان افزار.اجازه به همه(ز)
میان افزار.امن(ز)
میان افزار.بدون کش(ز)
اچ تی تی پی.متن(ز، "سلام")
پایان
تابع عکس(ز: صحیح۶۴):
میان افزار.کش(ز، ۳۶۰۰)
اچ تی تی پی.متن(ز، "png")
پایان
تابع ریشه:
ناپایا م := مسیریاب.مسیریاب جدید()
مسیریاب.دریافت(م، "/"، خانه)
مسیریاب.دریافت(م، "/logo.png"، عکس)
ناپایا س := اچ تی تی پی.سرور جدید(۱۹۶۰۴)
اچ تی تی پی.استفاده(س، م)
_ := اچ تی تی پی.اجرا در پس زمینه(س)
پ := اچ تی تی پی.دریافت("http://127.0.0.1:19604/")
هر نام در ["access-control-allow-origin"، "x-content-type-options"، "x-frame-options"، "cache-control"]:
سرچاپ نام + ": " + اچ تی تی پی.دریافت سرصفحه(پ، نام)
پایان
سرچاپ اچ تی تی پی.دریافت سرصفحه(اچ تی تی پی.دریافت("http://127.0.0.1:19604/logo.png")، "cache-control")
پایاناجازه به همه AllowAll
تابع اجازه به همه(ctx: صحیح۶۴)Access-Control-Allow-Origin: *، روشهای GET، POST، PUT، DELETE و OPTIONS و سرآیندهای Content-Type و Authorization. PATCH در فهرست نیست.نمونهی این مورد همراه با موارد بالاتر آمده است: net-http-middleware-Headers.salam
امن Secure
تابع امن(ctx: صحیح۶۴)X-Content-Type-Options: nosniff، X-Frame-Options: DENY و X-XSS-Protection: 1; mode=block را میگذارد. CSP و HSTS ندارد.نمونهی این مورد همراه با موارد بالاتر آمده است: net-http-middleware-Headers.salam
بدون کش NoCache
تابع بدون کش(ctx: صحیح۶۴)Cache-Control: no-store, no-cache, must-revalidate و Pragma: no-cache.نمونهی این مورد همراه با موارد بالاتر آمده است: net-http-middleware-Headers.salam
کش Cache
تابع کش(ctx: صحیح۶۴، seconds: صحیح)Cache-Control: max-age= را با این تعداد ثانیه میگذارد و جای Cache-Control قبلی را میگیرد.نمونهی این مورد همراه با موارد بالاتر آمده است: net-http-middleware-Headers.salam