सर्वर की सुरक्षा
Signal Lab सर्वर उस मशीन से असली ट्रैफ़िक भेजता है जिस पर वह चलता है: OSC, UDP, HTTP, MQTT, स्टॉर्म, स्कैन, ब्रॉडकास्ट। जो भी इसका उपयोग कर सकता है, वह उस मशीन से यह सब कर सकता है, इसलिए सर्वर डिफ़ॉल्ट रूप से बंद रहता है और केवल टोकन से खुलता है।
WARNING
एक्सेस टोकन को मशीन के नेटवर्क के पासवर्ड की तरह सँभालें। जिसके पास यह है, वह सर्वर से हर उस चीज़ पर ट्रैफ़िक भेज सकता है जहाँ तक सर्वर पहुँचता है।
एक नज़र में
- टोकन नहीं, तो केवल यही मशीन। टोकन के बिना सर्वर लूपबैक पर सुनता है और केवल लूपबैक होस्ट नामों को जवाब देता है। किसी दूसरे पते पर यह शुरू होने से इनकार कर देता है।
- बाकी सबके लिए टोकन। ब्राउज़र एक बार साइन इन करते हैं और एक सेशन कुकी पाते हैं; स्क्रिप्ट हर रिक्वेस्ट के साथ टोकन भेजती हैं।
- केवल उसके अपने पेज। कुछ बदलने वाली रिक्वेस्ट और इवेंट का WebSocket सर्वर के अपने ओरिजिन से ही आने चाहिए; कमांड केवल JSON लेती हैं।
- केवल उसके अपने नाम। जिस होस्ट नाम का सर्वर जवाब नहीं देता, वह अस्वीकार किया जाता है, जिससे DNS rebinding रुकता है।
- सीक्रेट भीतर रहते हैं। केवल पढ़ने योग्य, एनवायरनमेंट या फ़ाइलों से, कभी लौटाए नहीं जाते, जहाँ भी दिख सकते हों वहाँ छिपाए जाते हैं।
- अपने काम से आगे कुछ नहीं। यह होस्ट का फ़ायरवॉल कभी नहीं बदलता, अपने डेटा फ़ोल्डर से बाहर की कोई फ़ाइल नहीं देता, और इसे किसी विशेषाधिकार की ज़रूरत नहीं।
टोकन के बिना: केवल यही मशीन
टोकन के बिना शुरू होने पर सर्वर 127.0.0.1:1430 पर सुनता है और साइन इन नहीं माँगता: यह इस मशीन के सामने बैठे व्यक्ति का टूल है। ताकि इस मशीन के किसी भी ब्राउज़र का कोई वेब पेज 127.0.0.1 पर रिज़ॉल्व होने वाले किसी नाम (DNS rebinding) के ज़रिए इस तक न पहुँच सके, यह केवल उन रिक्वेस्ट का जवाब देता है जिनका Host एक लूपबैक नाम है — localhost, .localhost से समाप्त होने वाला नाम, 127.x.x.x या [::1] — या ऐसा नाम जिसकी आप --allowed-host से अनुमति देते हैं।
टोकन के बिना किसी दूसरे पते पर सुनने को कहा जाए, तो यह शुरू नहीं होता: यह कारण बताता है और कोड 2 के साथ बाहर निकल जाता है।
टोकन
टोकन में कम से कम 24 अक्षर होते हैं, बिना स्पेस या लाइन ब्रेक के। signal-lab-server token 64 हेक्साडेसिमल अक्षरों का एक रैंडम टोकन छापता है, और --generate-token (इमेज में चालू) पहली बार शुरू होने पर एक टोकन बनाता है, उसे डेटा फ़ोल्डर में ऐसे रखता है कि केवल सर्वर का अपना उपयोगकर्ता उसे पढ़ सके, और उसे एक बार छापता है। टोकन देने के सभी तरीकों के लिए देखें एक्सेस टोकन।
टोकन की तुलना में उतना ही समय लगता है, अंतर चाहे जहाँ हो, और ग़लत टोकन पर एक सेकंड की प्रतीक्षा और लॉग में एक चेतावनी होती है — अनुमान लगाना धीमा है और निशान छोड़ता है।
ब्राउज़र: सेशन
जो ब्राउज़र साइन इन नहीं है, उसे साइन-इन पेज पर भेजा जाता है। उसका टोकन एक बार सेशन से बदला जाता है, जो एक कुकी में रहता है, जो:
HttpOnlyहै — किसी पेज की कोई स्क्रिप्ट उसे नहीं पढ़ सकती;SameSite=Strictहै — किसी दूसरी साइट का पेज ब्राउज़र से उसे नहीं भिजवा सकता;- 7 दिन तक वैध है;
--secure-cookieके साथSecureहै, ताकि वह केवल HTTPS पर जाए (HTTPS प्रॉक्सी के पीछे इसे सेट करें)।
सेशन सर्वर की मेमोरी में रहते हैं: रीस्टार्ट से सभी साइन आउट हो जाते हैं, और साइन आउट करें किसी एक को तुरंत समाप्त कर देता है। अधिकतम 1024 सेशन रखे जाते हैं; सबसे पुराना सबसे पहले हटता है।
स्क्रिप्ट: bearer टोकन
स्क्रिप्ट, signallab --server और CI हर रिक्वेस्ट के साथ टोकन भेजते हैं:
Authorization: Bearer <token>हर एंडपॉइंट को टोकन या सेशन चाहिए, सिवाय GET /api/health (सर्वर जवाब देता है या नहीं, उसका संस्करण, वह टोकन माँगता है या नहीं) और साइन-इन पेज के। बिना टोकन या सेशन के API रिक्वेस्ट को त्रुटि auth.required के साथ 401 मिलता है; किसी पेज को साइन-इन पेज मिलता है।
होस्ट नाम
| सर्वर कैसे शुरू हुआ | किन होस्ट नामों को जवाब देता है |
|---|---|
| टोकन के बिना | लूपबैक नाम, और --allowed-host के नाम |
टोकन के साथ, --allowed-host के बिना | कोई भी नाम |
टोकन और --allowed-host के साथ | लूपबैक नाम, और --allowed-host के नाम |
--allowed-host (SIGNALLAB_ALLOWED_HOSTS) कॉमा से अलग किए गए नाम लेता है, जिनकी तुलना पोर्ट के बिना और अक्षरों के छोटे-बड़े होने को अनदेखा करके होती है:
signal-lab-server --listen 0.0.0.0:1430 --token-file token.txt --allowed-host lab-pc.example.com,192.0.2.10किसी भी दूसरे Host को त्रुटि auth.host के साथ 403 मिलता है। जिस सर्वर तक ज्ञात नामों से पहुँचा जाता है, उस पर इसे सेट करें, ताकि किसी दूसरी साइट का पेज अपने किसी नाम के ज़रिए उस तक न पहुँच सके।
ओरिजिन और कंटेंट टाइप
- कुछ बदलने वाली हर रिक्वेस्ट (
GETऔरHEADके अलावा कुछ भी), और इवेंट का WebSocket, या तो बिनाOriginके होने चाहिए, या सर्वर के अपने ओरिजिन के साथ — वही होस्ट और पोर्ट जो उसकेHostमें है। किसी दूसरी साइट के पेज को, याOrigin: nullभेजने वाले पेज को,auth.originके साथ403मिलता है। स्क्रिप्ट औरcurlकोईOriginनहीं भेजते और इनसे प्रभावित नहीं होते। - कमांड केवल
Content-Type: application/jsonलेती हैं (वरनाcommand.json_requiredके साथ415), इसलिए किसी दूसरी साइट का फ़ॉर्म कमांड नहीं भेज सकता। - सर्वर किसी भी cross-origin (CORS) रिक्वेस्ट का जवाब नहीं देता।
रिस्पॉन्स हेडर
हर रिस्पॉन्स में होते हैं:
| हेडर | मान |
|---|---|
Content-Security-Policy | default-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'self' |
X-Content-Type-Options | nosniff |
X-Frame-Options | DENY |
Referrer-Policy | same-origin |
Cache-Control | API और साइन-इन पेज के लिए no-store |
इंटरफ़ेस केवल वही लोड करता है जो सर्वर देता है, केवल सर्वर से बात करता है, और किसी दूसरे पेज के फ़्रेम में नहीं खोला जा सकता।
फ़ाइलें और आकार
- डाउनलोड (
GET /api/files?path=…) केवल डेटा फ़ोल्डर के भीतर से दिया जाता है, अधिकतम 256 MiB; बाकी सब पर404मिलता है। - रिक्वेस्ट बॉडी अधिकतम 24 MiB की होती है।
सीक्रेट
सीक्रेट का मान कभी इंजन से बाहर नहीं जाता:
- सर्वर पर मान केवल पढ़ने योग्य होते हैं: एनवायरनमेंट वैरिएबल
SIGNALLAB_SECRET_<NAME>, या सीक्रेट फ़ोल्डर में फ़ाइल<NAME>(डिफ़ॉल्ट रूप से/run/secrets/signallab)। ब्राउज़र से किसी को सेट करना या हटाना अस्वीकार किया जाता है (secret.read_only), ताकि किसी पेज में टाइप किया गया मान कभी किसी कमज़ोर जगह पर सहेजा न जाए। देखें सीक्रेट। - कोई भी कमांड मान नहीं लौटाती; इंटरफ़ेस को केवल यह पता चलता है कि कोई नाम सेट है या नहीं।
- प्रयोग सीक्रेट को
{{secret.NAME}}के रूप में नाम देते हैं। जब कोई रन या भेजना उनका उपयोग करता है, तो वह जो भी टेक्स्ट बताता है — चरण, त्रुटियाँ, रन रिपोर्ट — उनमें उनकी जगह••••दिखता है, और इंस्पेक्टर के फ़्रेम बाइट-दर-बाइट छिपाए जाते हैं। - HTTP नोड के क्रेडेंशियल केवल रिक्वेस्ट भेजे जाते समय
Authorizationहेडर बनते हैं; चरण, फ़्रेम और रिपोर्ट रिस्पॉन्स रखते हैं, वह हेडर कभी नहीं।
क्या लॉग होता है
लॉग, क्लाइंट के पते के साथ, दर्ज करता है: शुरू किया गया हर जॉब — स्टॉर्म, स्कैन, ब्रॉडकास्ट, मॉनिटर, जनरेटर, रन, एमुलेटर — हर साइन इन, और ग़लत टोकन के साथ हर साइन इन। देखें लॉग।
सर्वर क्या कभी नहीं करता
- होस्ट का फ़ायरवॉल बदलना। डेस्कटॉप ऐप आपके कहने पर फ़ायरवॉल नियम जोड़ सकता है; सर्वर पर वह कमांड अस्वीकार की जाती है (
firewall.server)। होस्ट का फ़ायरवॉल उसका मामला है जो होस्ट चलाता है। (एक कमांड वाली इंस्टॉल स्क्रिप्ट ufw या firewalld में सर्वर का पोर्ट खोलने का विकल्प देती है, और पहले पूछती है — देखें होस्ट का फ़ायरवॉल।) - टोकन के बिना पहुँच योग्य रूप में शुरू होना, लूपबैक के अलावा किसी भी पते पर।
- अपने डेटा फ़ोल्डर के बाहर की फ़ाइल देना।
- ब्राउज़र में टाइप किया गया सीक्रेट सहेजना।
- ख़ुद TLS बोलना: इसके आगे एक HTTPS प्रॉक्सी रखें (देखें HTTPS प्रॉक्सी के पीछे)।
इंजन की हर सीमा — स्वीप में अधिकतम 1024 होस्ट, बीकन से प्रति सेकंड अधिकतम 50,000 पैकेट — सर्वर पर भी वैसे ही लागू होती है जैसे ऐप में। ये सुरक्षा सीमाएँ हैं, अनुमति नहीं: ट्रैफ़िक केवल उन सिस्टम पर भेजें जो आपके हैं या जिन्हें टेस्ट करने की आपको अनुमति है।
कंटेनर
इमेज एक बिना विशेषाधिकार वाले उपयोगकर्ता (uid और gid 10001) के रूप में चलती है और केवल /data में लिखती है। यह केवल पढ़ने योग्य रूट फ़ाइल सिस्टम, बिना capabilities और no-new-privileges के साथ बिना बदलाव के चलती है — जैसे इंस्टॉल स्क्रिप्ट और deploy/compose.yaml इसे शुरू करते हैं। हर इमेज SBOM, बिल्ड provenance और हस्ताक्षरित GitHub attestation के साथ प्रकाशित होती है:
gh attestation verify oci://ghcr.io/proanima/signallab:1.0.0 -R ProAnima/SignalLabSignal Lab बाहरी दुनिया को क्या भेजता है
आपके भेजे ट्रैफ़िक के अलावा Signal Lab दो जगहों से बात करता है, दोनों स्टूडियो की।
अपडेट जाँच
केवल डेस्कटॉप ऐप अपडेट खोजता है; सर्वर और ब्राउज़र कभी नहीं। Signal Lab के बारे में में दिन में एक बार जाँचें चालू होने पर, दिन में एक बार, और जब भी आप अपडेट जाँचें दबाते हैं, ऐप स्टूडियो के हब (hub.proanima.net) से पूछता है — और GitHub की नवीनतम रिलीज़ से केवल तब, जब हब तक न पहुँचा जा सके। सवाल में होता है:
- ऐप का संस्करण;
- ऑपरेटिंग सिस्टम और प्रोसेसर आर्किटेक्चर;
- इस इंस्टॉलेशन की एक रैंडम संख्या (
X-Install-Id), जो एक बार बनाई जाती है और ऐप की सेटिंग्स के साथ रखी जाती है, ताकि नई रिलीज़ पहले कुछ ही इंस्टॉलेशन तक पहुँच सके। यह आपके या कंप्यूटर के बारे में कुछ नहीं बताती।
केवल प्रकाशित रिलीज़ दी जाती हैं। जिस डाउनलोड का हस्ताक्षर ऐप में बनी कुंजी से मेल नहीं खाता, वह इंस्टॉल नहीं होता, और जब तक आप इंस्टॉल और रीस्टार्ट करें न दबाएँ, कुछ भी इंस्टॉल नहीं होता।
फ़ीडबैक
डेवलपर्स को लिखें (हेडर में ✉, और Signal Lab के बारे में में भी) स्टूडियो के हब के ज़रिए डेवलपर्स को संदेश भेजता है, जो उसे ई-मेल से आगे भेजता है; ऐप में इसके लिए कोई पासवर्ड नहीं होता। यह केवल वही भेजता है जो फ़ॉर्म दिखाता है: आपका संदेश, आपका ई-मेल अगर आप दें, आपके जोड़े गए स्क्रीनशॉट, और — अपने आप संलग्न के नीचे — कंसोल लॉग और संस्करण और सिस्टम, जिनमें से हर एक को आप भेजने से पहले खोल सकते हैं और जिसका टिक हटा सकते हैं। इस कंप्यूटर का नाम, उसका पता और आपके फ़ोल्डर इनमें शामिल नहीं होते। ब्राउज़र से, फ़ॉर्म सर्वर भेजता है।