নিরাপত্তা
আমাদের নিরাপত্তা মডেল এক বাক্যে: সার্ভারে আক্রমণ করার মতো কিছু নেই। নিচের সবকিছু আপনার DevTools থেকে যাচাইযোগ্য।
আর্কিটেকচার
জেনারেটরটি একটি স্ট্যাটিক সিঙ্গেল-পেজ অ্যাপ্লিকেশন যা Cloudflare Pages থেকে পরিবেশন করা হয়: কোনো ব্যবহারকারী অ্যাকাউন্ট নেই, কোনো প্রমাণীকরণ নেই এবং জেনারেশন ফ্লোর কোথাও কোনো ব্যাকএন্ড কোড পাথ নেই। প্রতিটি QR তৈরি, এনকোডিং, স্ক্যানিং এবং রেন্ডারিং অপারেশন সম্পূর্ণভাবে আপনার ব্রাউজারের মধ্যে চলে। একটি ছোট সার্ভারলেস এন্ডপয়েন্ট এর পাশে আছে এবং সেটি লুকানো না রেখে এখানে তালিকাভুক্ত করা হলো: /api/contact (কন্টাক্ট ফর্ম, যা আপনার জমা দেওয়া তথ্য Cloudflare D1-এ সংরক্ষণ করে এবং আমাদের ইমেইল করে)। QR কোড তৈরি করার সময় এটি কল হয় না; URL সেফটি চেকার একটি পৃথক পণ্য যা check.qr.abundera.ai-এ আছে। QR কোড নিরাপদ কিনা পরীক্ষা করুন
হুমকির মডেল
যেহেতু জেনারেটর কোনো ব্যবহারকারীর ডেটা সংগ্রহ, সঞ্চয় বা প্রেরণ করে না (উপরের দুটি এন্ডপয়েন্ট শুধু আপনি স্পষ্টভাবে পাঠানো তথ্যই পরিচালনা করে), তাই সবচেয়ে সাধারণ ওয়েব-অ্যাপ হুমকি, ক্রেডেনশিয়াল চুরি, ডেটাবেস লঙ্ঘন, সেশন হাইজ্যাকিং, সার্ভার-সাইড ইনজেকশন, এটিতে প্রযোজ্য নয়। অবশিষ্ট আক্রমণের পৃষ্ঠ হলো আমাদের অরিজিন থেকে পরিবেশিত স্ট্যাটিক অ্যাসেট বান্ডেল (HTML, CSS, JavaScript)। আমরা ধরে নিয়ে ডিজাইন করি:
- অরিজিন আপোস: একজন আক্রমণকারী আমাদের বান্ডেলকৃত অ্যাসেটের একটি ক্ষতিকর দিয়ে প্রতিস্থাপন করে। নিচের CSP বিস্ফোরণের ব্যাসার্ধ সীমাবদ্ধ করে; ক্যাশ-বাস্টার টোকেনগুলি পরিচিত-ভালো সংস্করণে রোলব্যাক সহজ করে।
- ব্যবহারকারী-সরবরাহকৃত ইনপুট: QR পেলোড, vCard নাম, WiFi পাসওয়ার্ড, ব্যাচ CSV সারি, স্ক্যান করা ছবির বিষয়বস্তু। প্রতিটি ইনপুট পাথকে অবিশ্বস্ত হিসেবে বিবেচনা করা হয় যখন এটি DOM-এ ফিরে রেন্ডার করে।
- ব্যবহারকারী-সরবরাহকৃত ছবি: vCard ফটো URL এবং লোগো আপলোড। ছবিগুলি একটি ক্যানভাসে রেন্ডার করা হয়, কখনো DOM-এ কাঁচা মার্কআপ হিসেবে এম্বেড করা হয় না।
- তৃতীয়-পক্ষের ব্রাউজার এক্সটেনশন: স্কোপের বাইরে। যদি আপনার ব্রাউজারের কোনো এক্সটেনশনের প্রতিটি পেজ পরিবর্তন করার অনুমতি থাকে, তাহলে এটি আমাদেরটিও পরিবর্তন করতে পারে। পেজটি অপরিবর্তিতভাবে লোড হলে আমাদের গ্যারান্টি প্রযোজ্য।
কন্টেন্ট সিকিউরিটি পলিসি, ডিরেক্টিভ অনুযায়ী
নিচের পলিসিটি এই পেজ বিল্ড হওয়ার সময় ডিপ্লয় করা _headers ফাইল থেকে পড়া হয়, তাই এটি এজ যা পাঠায় তা থেকে সরে যেতে পারে না। যেকোনো অনুরোধের রেসপন্স হেডারে এটি যাচাই করুন।
Content-Security-Policy:
default-src 'self';
script-src 'self' https://abundera.ai 'wasm-unsafe-eval' https://challenges.cloudflare.com;
worker-src 'self' blob:;
style-src 'self' 'unsafe-inline' https://abundera.ai;
font-src 'self';
img-src 'self' data: blob: https:;
connect-src 'self' https: https://challenges.cloudflare.com;
frame-src 'self' https://challenges.cloudflare.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self'প্রতিটি ডিরেক্টিভ কী করতে দেয় এবং কোথায় আপোস করে:
default-src 'self', শক্ত ভিত্তি। আমরা যা স্পষ্টভাবে শিথিল করি না তা একই-অরিজিনে থাকে।script-src 'self' https://abundera.ai 'wasm-unsafe-eval' https://challenges.cloudflare.com, কোনো ইনলাইন<script>নয়, কোনোeval()নয়।abundera.aiআমাদের নিজস্ব প্যারেন্ট ডোমেইন এবং একটি শেয়ার্ড স্ক্রিপ্ট পরিবেশন করে, ভাষা সিলেক্টর।challenges.cloudflare.comহলো Turnstile উইজেট, যা শুধুমাত্র /contact/-এ ব্যবহৃত হয়।'wasm-unsafe-eval'আমাদের QR এনকোডার লাইব্রেরির WebAssembly কম্পাইলেশন পাথের জন্য প্রয়োজন; এটি ঐতিহ্যগতeval()অনুমতি দেয় না। আমাদের নিজস্ব প্রি-ডিপ্লয় চেক প্রতিটি HTML পেজে ইনলাইন স্ক্রিপ্ট স্ক্যান করে এবং বিল্ড ব্যর্থ করে।style-src 'self' 'unsafe-inline', একটি বাস্তব ছাড়। আমাদের QR প্রিভিউ ইনলাইনে পিক্সেল-স্তরের রঙ গণনা করে (পৃথক মডিউলে স্টাইল অ্যাট্রিবিউট)। হ্যাশ-ভিত্তিক অনুমতি তালিকা কাজ করত কিন্তু ডিপ্লয় ছাড়া যেকোনো স্টাইল আপডেটে ব্যর্থ হত। ট্রেডঅফ: আমরা সামান্য দুর্বল স্টাইল পলিসি গ্রহণ করি; স্টাইলিং যেকোনোভাবে ডেটা বের করতে পারে না (CSS-এর কোনোconnect-srcনাগাল নেই)।img-src 'self' data: blob: https:, ইনলাইন QR রেন্ডারের জন্যdata:, এক্সপোর্ট ডাউনলোড URL-এর জন্যblob:, ব্যবহারকারী-সরবরাহকৃত vCard ফটো এবং অ্যাভাটার URL-এর জন্যhttps:। ব্যবহারকারী-সরবরাহকৃত URL কখনো এক্সিকিউট হয় না, শুধু রেন্ডার হয়। মনে রাখবেন এই ডিরেক্টিভটি একটি আউটবাউন্ড চ্যানেলও: পেজে চলমান যেকোনো স্ক্রিপ্ট যেকোনো HTTPS হোস্ট থেকে একটি ছবি অনুরোধ করতে পারে এবং URL-এ ডেটা রাখতে পারে। আমরা এটি মেনে নিই কারণ ফিচারটির জন্য এটি দরকার, এবং পলিসিটিকে অভেদ্য না বলে আমরা এখানে তা স্পষ্টভাবে বলছি।connect-src 'self' https: https://challenges.cloudflare.com, সবচেয়ে মনোযোগ দিয়ে পড়ার মতো একটি।https:একটি স্কিম সোর্স: এটিfetch(), XMLHttpRequest, TLS-এর ওপর WebSocket, EventSource এবংsendBeacon()-কে যেকোনো HTTPS অরিজিনে পৌঁছাতে দেয়, শুধু আপনার টাইপ করা অরিজিনে নয়। এটি সেখানে আছে যাতে vCard ফটো ফিল্ড এবং URL সেফটি চেক আপনার পেস্ট করা একটি ঠিকানা ফেচ করতে পারে। এটি একটি ক্ষতিকর স্ক্রিপ্ট দ্বারা এক্সফিল্ট্রেশন প্রতিরোধ করে না; স্ক্রিপ্ট একবার আমাদের হিসেবে চলতে শুরু করলে কোনো CSP ডিরেক্টিভই তা করে না। যা এক্সফিল্ট্রেশন প্রতিরোধ করে তা হলো আমাদের পাঠানো কোড এমন কোনো অনুরোধ করে না, যা আপনি Network ট্যাবে দেখতে পারেন।frame-src 'self' https://challenges.cloudflare.com, শুধুমাত্র Turnstile উইজেট ফ্রেম করা যেতে পারে।frame-ancestors 'none', অন্য কোনো সাইট আমাদের এম্বেড করতে পারবে না। ক্লিকজ্যাকিং প্রতিরোধ করে।base-uri 'self', একটি ক্ষতিকর ইনজেক্টেড<base>ট্যাগ আক্রমণকারীর অরিজিনে আপেক্ষিক URL পুনঃনির্দেশ করতে পারবে না।form-action 'self', যেকোনো ইনজেক্টেড ফর্ম শুধুমাত্র আমাদের অরিজিনে পোস্ট করতে পারে। কন্টাক্ট ফর্মই একমাত্র ফর্ম যা কোথাও সাবমিট হয়।
CSP যা করতে পারে না
CSP ব্রাউজার কোথা থেকে কোড লোড করবে তা সীমাবদ্ধ করে। লোড হওয়া কোড কী করে তা এটি যাচাই করে না। যদি আমাদের অরিজিন কখনো আপোস হয়, যা হুমকির মডেলের প্রথম আইটেম, তাহলে আক্রমণকারীর স্ক্রিপ্ট আমাদের কোডের মতো একই অনুমতি নিয়ে চলবে, উপরের connect-src এবং img-src অনুমতিগুলোসহ। এর বিরুদ্ধে আমাদের প্রতিরক্ষা CSP-এর উজানে থাকে: ডিপ্লয়গুলো স্কোপড টোকেনসহ একটি Cloudflare অ্যাকাউন্টের মধ্য দিয়ে বের হয়, অ্যাসেট ফাইলনেম কন্টেন্ট-হ্যাশড তাই একটি প্রতিস্থাপিত ফাইল তাকে রেফার করা প্রতিটি URL বদলে দেয়, এবং সার্ভিস ওয়ার্কার শুধুমাত্র একই-অরিজিনের GET রেসপন্স ক্যাশ করে। ম্যানিফেস্টো সাইটটিকে যেভাবে শিপ করা হয়েছে সেভাবে বর্ণনা করে। এটি এমন দাবি নয় যে কোনো ওয়েব পেজ কখনো কোথাও ডেটা পাঠাতে পারবে না, এবং আমরা চাই আপনি আমাদের এই সংকীর্ণ, যাচাইযোগ্য বিবৃতির ভিত্তিতে বিচার করুন।
/bio/* (ব্যবহারকারী-সরবরাহকৃত অ্যাভাটারের জন্য শিথিল img-src) এবং /embed/* (ইচ্ছাকৃত এম্বেডিংয়ের জন্য শিথিল frame-ancestors)-এ ভিন্ন CSP পলিসি প্রযোজ্য। উভয়ই site/_headers-এ ডকুমেন্ট করা হয়েছে।
ট্রান্সপোর্ট + ফ্রেমিং হেডার
- HSTS:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload, ১ বছর, সব সাবডোমেইন, HSTS প্রিলোড তালিকার যোগ্য। HTTP-তে ডাউনগ্রেড সম্মত ব্রাউজার দ্বারা প্রত্যাখ্যাত। - X-Frame-Options: DENY, CSP
frame-ancestors-এর সাথে অপ্রয়োজনীয়, পুরানো ব্রাউজার কভারেজের জন্য রাখা হয়েছে। - X-Content-Type-Options: nosniff, MIME কনফিউশন আক্রমণ প্রতিরোধ করে।
- Referrer-Policy: strict-origin-when-cross-origin, আউটবাউন্ড লিঙ্ক ক্লিক অরিজিন প্রকাশ করে কিন্তু পাথ নয়।
- Permissions-Policy:
camera=(self), microphone=(), geolocation=(), ক্যামেরা শুধুমাত্র আমাদের নিজস্ব স্ক্যানারের জন্য অনুমতি; মাইক্রোফোন এবং লোকেশন এম্বেড করা হলেও স্পষ্টভাবে অস্বীকার।
সার্ভিস ওয়ার্কার
আমাদের সার্ভিস ওয়ার্কার (site/sw.js) শুধুমাত্র একই-অরিজিনের অ্যাসেট ক্যাশ করে। fetch হ্যান্ডলার স্পষ্টভাবে ক্রস-অরিজিন অনুরোধ এবং non-GET পদ্ধতি প্রত্যাখ্যান করে, আপনি /sw.js-এ লজিক পড়তে পারেন (সোর্সটি অনুসরণযোগ্য থাকার মতো যথেষ্ট আনমিনিফাইড অবস্থায় শিপ হয়)। ক্যাশ রাইট event.waitUntil()-এ মোড়ানো তাই এগুলি নেভিগেশনের মাঝে বাদ পড়তে পারে না।
ইনপুট স্যানিটাইজেশন
ব্যবহারকারীর ইনপুট গ্রহণকারী প্রতিটি রেন্ডারিং পাথ এটিকে অবিশ্বস্ত টেক্সট হিসেবে বিবেচনা করে:
- QR পেলোড প্রিভিউ
textContentব্যবহার করে,innerHTMLনয়। - শেয়ার টার্গেট (ক্লিপবোর্ড,
navigator.share()) ব্যবহারকারীর টেক্সট স্ট্রিং হিসেবে পাস করে, কখনো মার্কআপ হিসেবে নয়। - SVG এক্সপোর্ট আমাদের এনকোডার লাইব্রেরি থেকে তৈরি; ব্যবহারকারীর বিষয়বস্তু
<image>xlink:href-এ base64-এনকোড করা, SVG উপাদান হিসেবে ইনজেক্ট করা নয়। - প্রিন্ট প্রিভিউ blob URL ব্যবহার করে,
document.write()নয়। - localStorage পার্সিং
try/catch-এ মোড়ানো, একটি দূষিত এন্ট্রি একটি নতুন খালি ডিফল্ট দেয়, কখনো এমন ব্যতিক্রম নয় যা একটি লাইভ কোড পাথে আনওয়াইন্ড করতে পারে। - "লিঙ্ক খুলুন" বোতাম হিসেবে দেখানো ব্যবহারকারী-সরবরাহকৃত URL
http(s)://-এ সীমাবদ্ধ,javascript:এবংdata:স্কিম প্রত্যাখ্যাত।
ক্রস-অরিজিন ইমেজ ফেচিং
যখন একজন ব্যবহারকারী vCard ফটো বা লোগো হিসেবে একটি https: URL পেস্ট করেন, ব্রাউজার CORS এবং আমাদের CSP-এর img-src অনুমতি তালিকা সাপেক্ষে এটি ফেচ করে। ছবিটি একটি ক্যানভাসে রেন্ডার হয়। এটি কখনো লাইভ DOM হয় না, কখনো কোড হিসেবে চলে না এবং কখনো আমাদের অরিজিনে পৌঁছায় না, ফেচটি হলো ব্রাউজার → রিমোট ইমেজ, এবং ফলাফলটি ক্লায়েন্ট-সাইডে পেইন্ট করা হয়। একটি রিমোট ইমেজ URL নিয়ন্ত্রণকারী আক্রমণকারী ট্র্যাক করতে পারে যে URL লোড হয়েছিল (তাদের নিজের সার্ভারে একটি লগ লাইন) কিন্তু আমাদের পেজ থেকে কিছু বের করতে পারে না।
সাবরিসোর্স ইন্টিগ্রিটি (SRI)
আমরা যে সমস্ত JavaScript এবং CSS পাঠাই তা একই-অরিজিনের। আমরা তৃতীয়-পক্ষের স্ক্রিপ্ট বা স্টাইলশিট লোড করি না, তাই SRI হ্যাশ প্রযোজ্য নয়। যদি আমরা কখনো তৃতীয়-পক্ষের অ্যাসেট লোড করি, আমরা এটিতে একটি SRI integrity অ্যাট্রিবিউট পাঠাব এবং এই পেজে হ্যাশ-আপডেট প্রক্রিয়া ডকুমেন্ট করব।
একটি দুর্বলতা রিপোর্ট করা
আপনি যদি Abundera QR-এ একটি নিরাপত্তা সমস্যা আবিষ্কার করেন, আমাদের কোডে, আমাদের ডিপ্লয়মেন্টে, বা আমরা যে ডিপেন্ডেন্সি পাঠাই তাতে, অনুগ্রহ করে এটি ব্যক্তিগতভাবে security@abundera.ai-এ রিপোর্ট করুন। আমরা ৭২ ঘণ্টার মধ্যে ট্রিয়াজ করার লক্ষ্য রাখি। আপনি আমাদের /.well-known/security.txt ফাইলে যোগাযোগের বিবরণের মাধ্যমেও আমাদের সাথে যোগাযোগ করতে পারেন।
কোনো বাগ বাউন্টি নেই (এখনো)
আমরা বর্তমানে পেইড বাউন্টি অফার করি না, কিন্তু প্রতিটি নিশ্চিত বৈধ রিপোর্ট চেঞ্জলগে ক্রেডিট এবং আমাদের প্রকাশ্য ধন্যবাদ পায়।
উপরের যেকোনোটি যাচাই করুন
এই পেজের প্রতিটি দাবি আমাদের বিশ্বাস না করেই আপনার ব্রাউজারের DevTools থেকে যাচাইযোগ্য:
- CSP: DevTools → Network →
/→ Headers।Content-Security-Policyরেসপন্স হেডার পড়ুন। - HSTS + নিরাপত্তা হেডার: একই জায়গায়, সমস্ত
Strict-Transport-Security,X-Frame-Optionsইত্যাদি দৃশ্যমান। - কোনো আউটবাউন্ড কল নেই: DevTools → Network → Fetch/XHR। একটি QR তৈরি করুন। কাউন্ট শূন্যে থাকে দেখুন।
- সার্ভিস ওয়ার্কার স্কোপ: DevTools → Application → Service Workers। স্ক্রিপ্ট সোর্স এবং ক্যাশড অ্যাসেট তালিকা যাচাই করুন।
- কোনো কুকি নেই: DevTools → Application → Cookies। খালি।
- সম্পূর্ণ ওয়াকথ্রু: ম্যানিফেস্টোর ভেরিফিকেশন বিভাগ।
যোগাযোগ
নিরাপত্তা প্রকাশ: security@abundera.ai