Websockets क्लाइंट API में HTTP हेडर


201

ऐसा लगता है कि अपने HTTPso कस्टमर के साथ किसी भी HTTP हेडर क्लाइंट के साथ कस्टम HTTP हेडर जोड़ना आसान है, जो इसका समर्थन करता है, लेकिन मुझे JSON API के साथ ऐसा करने का तरीका नहीं मिल रहा है।

फिर भी, ऐसा लगता है कि कल्पना में इन हेडर का समर्थन होना चाहिए ।

किसी को भी यह कैसे प्राप्त करने पर एक सुराग है?

var ws = new WebSocket("ws://example.com/service");

विशेष रूप से, मुझे एक HTTP प्राधिकरण शीर्ष लेख भेजने में सक्षम होना चाहिए।


14
मुझे लगता है कि एक अच्छा समाधान यह है कि WebSocket को प्राधिकरण के बिना कनेक्ट करने की अनुमति दी जाए, लेकिन फिर ब्लॉक करें और सर्वर पर प्रतीक्षा करें ताकि वह वेबसेकेट से प्राधिकरण को पुनः प्राप्त कर सके जो इसके ऑनोपेन इवेंट में प्राधिकरण की जानकारी प्रसारित करेगा।
Motes

@Motes द्वारा दिया गया सुझाव सबसे उपयुक्त लगता है। ऑनऑन से एक प्राधिकरण कॉल करना बहुत आसान था जो आपको प्राधिकरण प्रतिक्रिया के आधार पर सॉकेट को स्वीकार / अस्वीकार करने की अनुमति देता है। मैंने मूल रूप से सेक-वेब-सॉकेट-प्रोटोकॉल हेडर में ऑर्टिकल टोकन भेजने का प्रयास किया था लेकिन यह हैक की तरह लगता है।
बैटरएकिड

@ हाय, क्या आप "ब्लॉक और सर्वर पर प्रतीक्षा करें" भाग को समझा सकते हैं? जब तक कोई "संदेश" संदेश नहीं आता, तब तक आप किसी भी संदेश को संसाधित नहीं करते हैं?
हिमाल

@ हिमाल, हां सर्वर डिज़ाइन को कनेक्शन की शुरुआत में प्राधिकरण के अलावा डेटा भेजने या किसी अन्य डेटा को स्वीकार नहीं करना चाहिए।
Motes

@ उत्तर के लिए धन्यवाद। मैं अवरुद्ध भाग से थोड़ा भ्रमित था, मेरी समझ से आप प्रारंभिक connectअनुरोध को रोक नहीं सकते । मैं बैकएंगो पर Django चैनल का उपयोग कर रहा हूं और मैंने इसे connectइवेंट पर कनेक्शन स्वीकार करने के लिए डिज़ाइन किया है । यह तब receiveघटना में एक "is_auth" ध्वज सेट करता है (यदि यह एक वैध वस्तु संदेश देखता है)। यदि is_auth ध्वज सेट नहीं है और यह एक सामान्य संदेश नहीं है तो यह कनेक्शन बंद कर देता है।
हिमाल

जवाबों:


212

अद्यतन किया गया 2x

संक्षिप्त उत्तर: नहीं, केवल पथ और प्रोटोकॉल फ़ील्ड निर्दिष्ट किया जा सकता है।

दीर्घ उत्तर:

क्लाइंट / ब्राउज़र को भेजने के लिए अतिरिक्त हेडर निर्दिष्ट करने के लिए जावास्क्रिप्ट वेबस्केट्स एपीआई में कोई विधि नहीं है । HTTP पथ ("GET / xyz") और प्रोटोकॉल हेडर ("Sec-WebSocket-Protocol") को WebSocket कंस्ट्रक्टर में निर्दिष्ट किया जा सकता है।

Sec-WebSocket- प्रोटोकॉल हेडर (जिसे कभी-कभी वेबसोकेट विशिष्ट प्रमाणीकरण में उपयोग किए जाने के लिए विस्तारित किया जाता है) WebSocket कंस्ट्रक्टर के वैकल्पिक दूसरे तर्क से उत्पन्न होता है:

var ws = new WebSocket("ws://example.com/path", "protocol");
var ws = new WebSocket("ws://example.com/path", ["protocol1", "protocol2"]);

निम्नलिखित हेडर में उपरोक्त परिणाम:

Sec-WebSocket-Protocol: protocol

तथा

Sec-WebSocket-Protocol: protocol1, protocol2

WebSocket प्रमाणीकरण / प्राधिकरण को प्राप्त करने के लिए एक सामान्य पैटर्न एक टिकटिंग प्रणाली को लागू करना है जहाँ WebSocket क्लाइंट की मेजबानी करने वाला पृष्ठ सर्वर से टिकट का अनुरोध करता है और फिर इस टिकट को WebSocket कनेक्शन सेटअप के दौरान URL / क्वेरी स्ट्रिंग में प्रोटोकॉल क्षेत्र में पास करता है। या कनेक्शन स्थापित होने के बाद पहले संदेश के रूप में आवश्यक है। सर्वर तब केवल कनेक्शन को जारी रखने की अनुमति देता है यदि टिकट वैध है (मौजूद नहीं है, पहले से उपयोग नहीं किया गया है, ग्राहक आईपी टिकट मैचों में एन्कोडेड है, टिकट में टाइमस्टैम्प हाल ही में है, आदि)। यहाँ WebSocket सुरक्षा जानकारी का सारांश दिया गया है: https://devcenter.heroku.com/articles/websocket-ecurity

मूल प्रमाणीकरण पूर्व में एक विकल्प था, लेकिन इसे हटा दिया गया है और आधुनिक ब्राउज़र हेडर नहीं भेजते हैं भले ही वह निर्दिष्ट हो।

मूल प्रामाणिक जानकारी (पदावनत) :

प्राधिकरण शीर्ष लेख WebSocket URI के उपयोगकर्ता नाम और पासवर्ड (या सिर्फ उपयोगकर्ता नाम) क्षेत्र से उत्पन्न होता है:

var ws = new WebSocket("ws://username:password@example.com")

उपरोक्त शीर्षक में स्ट्रिंग "उपयोगकर्ता नाम: पासवर्ड" बेस 64 एनकोड के साथ परिणाम है:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

मैंने क्रोम 55 और फ़ायरफ़ॉक्स 50 में बेसिक कोर का परीक्षण किया है और यह सत्यापित किया है कि मूल नॉर्म्स जानकारी वास्तव में सर्वर के साथ बातचीत की जाती है (यह सफारी में काम नहीं कर सकता है)।

मूल प्रमाणीकरण के लिए दिमित्री फ्रैंक के लिए धन्यवाद जवाब


38
मैं उसी समस्या को लेकर आया हूं। बहुत बुरा है कि ये मानक इतने खराब रूप से एकीकृत हैं। आप उम्मीद करेंगे कि वे WebSockets API के लिए आवश्यकताएँ खोजने के लिए XHR API को देखें (क्योंकि WebSockets और XHR संबंधित हैं), लेकिन ऐसा लगता है कि वे केवल एक द्वीप पर ही API विकसित कर रहे हैं।
११

4
@eleotlecram, HyBi वर्किंग ग्रुप से जुड़ें और उसे प्रपोज़ करें। समूह जनता के लिए खुला है और प्रोटोकॉल के बाद के संस्करणों के लिए काम चल रहा है।
कनक

5
@ चरेली: यदि आप सर्वर को पूरी तरह से नियंत्रित करते हैं, तो यह एक विकल्प है। अपने सामान्य HTTP सर्वर से टिकट / टोकन उत्पन्न करने के लिए अधिक सामान्य दृष्टिकोण है और फिर ग्राहक को टिकट / टोकन (या तो वेबसोकेट पथ में एक क्वेरी स्ट्रिंग के रूप में या पहले वेबसोकेट संदेश के रूप में) भेजें। Websocket सर्वर तब यह पुष्टि करता है कि टिकट / टोकन वैध है (समाप्त नहीं हुआ है, पहले से ही उपयोग नहीं किया गया है, उसी समय से IP से आ रहा है, आदि)। इसके अलावा, मेरा मानना ​​है कि अधिकांश वेबसोकेट क्लाइंट बुनियादी स्थिति का समर्थन करते हैं (हालांकि आपके लिए पर्याप्त नहीं हो सकता है)। अधिक जानकारी: devcenter.heroku.com/articles/websocket-security
kanaka

3
मुझे लगता है कि इसके डिजाइन से। मैं इस धारणा के तहत हूं कि कार्यान्वयन जानबूझकर HTTP से उधार ले रहा है, लेकिन डिज़ाइन द्वारा उन्हें यथासंभव अलग रखा गया है। विशिष्ट अनुपात में पाठ जारी है: "हालांकि, डिज़ाइन वेबसॉकेट को HTTP तक सीमित नहीं करता है, और भविष्य के कार्यान्वयन पूरे प्रोटोकॉल को पुन: स्थापित किए बिना समर्पित पोर्ट पर एक सरल हैंडशेक का उपयोग कर सकते हैं। यह अंतिम बिंदु महत्वपूर्ण है क्योंकि इंटरैक्टिव मैसेजिंग के ट्रैफ़िक पैटर्न। मानक HTTP ट्रैफ़िक से निकटता से मेल नहीं खाते और कुछ घटकों पर असामान्य भार उत्पन्न कर सकते हैं। "

3
दुर्भाग्य से यह एज में काम नहीं करता है। धन्यवाद, एमएस: /
sibbl

40

वैकल्पिक समाधान का अधिक, लेकिन सभी आधुनिक ब्राउज़र कनेक्शन के साथ डोमेन कुकीज़ भेजते हैं, इसलिए उपयोग कर रहे हैं:

var authToken = 'R3YKZFKBVi';

document.cookie = 'X-Authorization=' + authToken + '; path=/';

var ws = new WebSocket(
    'wss://localhost:9000/wss/'
);

अनुरोध कनेक्शन हेडर के साथ समाप्त:

Cookie: X-Authorization=R3YKZFKBVi

1
यह कनेक्शन पर पहुंच टोकन पास करने का सबसे अच्छा तरीका लगता है। इस समय।
कैमिल

2
क्या होगा यदि WS सर्वर URI क्लाइंट URI से भिन्न है?
डेनिश

@ अच्छी तरह से तब यह काम नहीं करता है, क्योंकि आप अन्य डोमेन क्लाइंट साइड के लिए कुकीज़ सेट नहीं कर सकते हैं
टॉफैंडेल

35

HTTP प्राधिकरण शीर्ष लेख समस्या को निम्नलिखित के साथ संबोधित किया जा सकता है:

var ws = new WebSocket("ws://username:password@example.com/service");

फिर, एक उचित बेसिक ऑथराइजेशन HTTP हेडर प्रदान किया जाएगा usernameऔर साथ ही password। यदि आपको मूल प्राधिकरण की आवश्यकता है, तो आप सभी तैयार हैं।


मैं Bearerहालांकि उपयोग करना चाहता हूं , और मैंने निम्न चाल का सहारा लिया: मैं सर्वर से निम्नानुसार कनेक्ट करता हूं:

var ws = new WebSocket("ws://my_token@example.com/service");

और जब सर्वर साइड पर मेरा कोड गैर-खाली उपयोगकर्ता नाम और खाली पासवर्ड के साथ बेसिक ऑथराइजेशन हेडर प्राप्त करता है, तो यह यूजरनेम को टोकन के रूप में व्याख्या करता है।


12
मैं आपके द्वारा सुझाए गए समाधान की कोशिश कर रहा हूं। लेकिन मैं अपने अनुरोध में प्राधिकरण शीर्षलेख को देखने में सक्षम नहीं हूं। मैंने इसे विभिन्न ब्राउज़रों जैसे क्रोम V56, फ़ायरफ़ॉक्स V51.0 का उपयोग करके आज़माया है। मैं अपने लोकलहोस्ट पर अपना सर्वर चला रहा हूँ। इसलिए websocket url "ws: // myusername: mypassword @ localhost: 8080 / mywebsocket" है। किसी भी विचार क्या गलत हो सकता है? धन्यवाद
LearnToLive

4
क्या यूआरएल के जरिए टोकन ट्रांसफर करना सुरक्षित है?
मैरागासोव

2
उपयोगकर्ता नाम के लॉग इन होने के कारण टोकन के रूप में खाली / उपेक्षित उपयोगकर्ता नाम और गैर-खाली पासवर्ड बेहतर हो सकता है।
आंद्रेकेआर

9
मैं @LearnToLive से सहमत हूं - मैंने इसका उपयोग wss (जैसे wss://user:password@myhost.com/ws) के साथ किया और Authorizationसर्वर साइड पर कोई हेडर नहीं मिला (क्रोम संस्करण 60 का उपयोग करके)
user9645

6
मेरे पास @LearnToLive और @ user9645 जैसा ही मुद्दा है; जब URI wss://user:pass@hostप्रारूप में है, तो न तो क्रोम और न ही फ़ायरफ़ॉक्स प्राधिकरण शीर्षक जोड़ रहे हैं । क्या यह ब्राउज़र द्वारा समर्थित नहीं है, या हैंडशेक के साथ कुछ गलत हो रहा है?
डेविड कैक्ज़िनस्की

19

आप हेडर नहीं जोड़ सकते, लेकिन, यदि आपको कनेक्शन के क्षण में सर्वर को मान देने की आवश्यकता है, तो आप url पर एक क्वेरी स्ट्रिंग भाग निर्दिष्ट कर सकते हैं:

var ws = new WebSocket("ws://example.com/service?key1=value1&key2=value2");

वह URL मान्य है लेकिन - निश्चित रूप से - आपको उसे पार्स करने के लिए अपना सर्वर कोड संशोधित करना होगा।


14
इस समाधान के साथ सावधान रहने की जरूरत है, क्वेरी स्ट्रिंग को इंटरसेप्ट किया जा सकता है, प्रॉक्सी में लॉग इन किया जा सकता है आदि ताकि संवेदनशील जानकारी (उपयोगकर्ता / पासवर्ड / प्रमाणीकरण टोकन) पास हो जाए, यह तरीका पर्याप्त सुरक्षित नहीं होगा।
निर्वस्त्र

5
@ WSS के साथ quirystring शायद सुरक्षित होना चाहिए
सेबस्टियन

8
ws सादा पाठ है। Ws प्रोटोकॉल का उपयोग करके किसी भी चीज को इंटरसेप्ट किया जा सकता है।
गेब्रियल कारियोली

1
@SebastienLorber यह क्वेरी स्ट्रिंग का उपयोग करने के लिए सुरक्षित नहीं है इसे एन्क्रिप्ट नहीं किया जा रहा है जो HTTPS पर लागू होता है, लेकिन चूंकि "ws: // ..." प्रोटोकॉल का उपयोग किया जाता है, यह वास्तव में कोई फर्क नहीं पड़ता।
Lu4

5
@ Lu4 क्वेरी स्ट्रिंग एन्क्रिप्टेड है, लेकिन URL क्वेरी पैरामीटर stackoverflow.com/questions/499591/are-https-urls-encrypted/… & ब्लॉग .httpwatch.com / 2009 के रूप में संवेदनशील डेटा नहीं जोड़ने के अन्य कारणों की एक मेजबानी है। /

16

जब आप JavaScript WebSockets API का उपयोग करके WebSockets कनेक्शन स्थापित करना चाहते हैं, तो आप कस्टम हेडर नहीं भेज सकते। आप Subprotocolsदूसरे वेबस्केट क्लास कंस्ट्रक्टर का उपयोग करके हेडर का उपयोग कर सकते हैं :

var ws = new WebSocket("ws://example.com/service", "soap");

और फिर आप Sec-WebSocket-Protocolसर्वर पर कुंजी का उपयोग करके सबप्रोटोकॉल हेडर प्राप्त कर सकते हैं ।

एक सीमा भी है, आपके Subprotocols हेडर मूल्यों में अल्पविराम ( ,) नहीं हो सकता है !


1
Jwt में अल्पविराम हो सकता है?
स्को में CESCO

1
मैं ऐसा नहीं मानता। JWT में तीन बेस 64-एन्कोडेड पेलोड होते हैं, प्रत्येक को एक अवधि के अनुसार अलग किया जाता है। मेरा मानना ​​है कि इस नियम से अल्पविराम की संभावना है।
BillyBBone

2
मैंने इसे लागू किया और यह काम करता है - बस अजीब लगता है। धन्यवाद
BatteryAcid

3
क्या आप सुझाव दे रहे हैं कि हम Sec-WebSocket-Protocolहेडर को वैकल्पिक रूप से हेडर के रूप में उपयोग करें Authorization?
18'18

13

ऑथराइजेशन हेडर भेजना संभव नहीं है।

टोकन क्वेरी पैरामीटर संलग्न करना एक विकल्प है। हालाँकि, कुछ परिस्थितियों में, यह आपके मुख्य लॉगिन टोकन को सादे पाठ में क्वेरी पैरामीटर के रूप में भेजने के लिए अवांछनीय हो सकता है क्योंकि यह हेडर का उपयोग करने की तुलना में अधिक अपारदर्शी है और अंत में लॉग इन किया जाएगा। यदि यह आपके लिए सुरक्षा चिंताओं को बढ़ाता है, तो एक विकल्प केवल वेब सॉकेट सामान के लिए एक माध्यमिक JWT टोकन का उपयोग करना है

इस JWT को जेनरेट करने के लिए एक REST एंडपॉइंट बनाएं , जो निश्चित रूप से केवल आपके प्राथमिक लॉगिन टोकन (हेडर के माध्यम से प्रेषित) के साथ प्रमाणित उपयोगकर्ताओं द्वारा पहुँचा जा सकता है। वेब सॉकेट JWT को आपके लॉगिन टोकन से अलग तरीके से कॉन्फ़िगर किया जा सकता है, उदाहरण के लिए एक छोटे समय के साथ, इसलिए यह आपके अपग्रेड अनुरोध के क्वेरी परम के रूप में चारों ओर भेजने के लिए सुरक्षित है।

उसी मार्ग के लिए एक अलग JwtAuthHandler बनाएं, जिस पर आप SockJS EventbusHandler को पंजीकृत करते हैं । सुनिश्चित करें कि आपका ऑथर हैंडलर पहले पंजीकृत है, इसलिए आप अपने डेटाबेस के खिलाफ वेब सॉकेट टोकन की जांच कर सकते हैं (JWT को किसी तरह बैकएंड में अपने उपयोगकर्ता से जुड़ा होना चाहिए)।


यह एकमात्र सुरक्षित समाधान था जो मैं एपीआई गेटवे वेबसोकेट के लिए ले सकता था। स्लैक अपने आरटीएम एपीआई के साथ कुछ ऐसा ही करता है और उनके पास 30 सेकंड का समय है।
andrhamm

2

कनक के जवाब की बदौलत पूरी तरह से इसे हैक कर लिया गया।

ग्राहक:

var ws = new WebSocket(
    'ws://localhost:8080/connect/' + this.state.room.id, 
    store('token') || cookie('token') 
);

सर्वर (इस उदाहरण में Koa2 का उपयोग करते हुए, लेकिन जहां कहीं भी समान होना चाहिए):

var url = ctx.websocket.upgradeReq.url; // can use to get url/query params
var authToken = ctx.websocket.upgradeReq.headers['sec-websocket-protocol'];
// Can then decode the auth token and do any session/user stuff...

4
क्या यह सिर्फ आपके टोकन को उस खंड में पास नहीं करता है जहाँ आपके ग्राहक को एक या अधिक विशिष्ट प्रोटोकॉल का अनुरोध करना है? मैं यह काम कर सकता हूं, कोई समस्या भी नहीं है, लेकिन मैंने यह नहीं करने का फैसला किया और इसके बजाय वो किया जो MOC ने सुझाव दिया था और तब तक ब्लॉक करें जब तक कि ओनोपेन () पर ऑक्टेन टोकन नहीं भेजा जाता। प्रोटोकॉल अनुरोध को ओवरलोड करने से हेडर मुझे गलत लगता है, और जैसा कि मेरा एपीआई सार्वजनिक खपत के लिए है, मुझे लगता है कि यह मेरे एपीआई के उपभोक्ताओं के लिए थोड़े भ्रमित करने वाला है।
Jay

0

मेरा मामला:

  • मैं एक उत्पादन WS सर्वर से कनेक्ट करना चाहता हूँ www.mycompany.com/api/ws...
  • वास्तविक क्रेडेंशियल्स (एक सत्र कुकी) का उपयोग कर ...
  • स्थानीय पृष्ठ से ( localhost:8000)।

document.cookie = "sessionid=foobar;path=/"डोमेन से मेल नहीं खाने के कारण सेटिंग मदद नहीं करेगी।

समाधान :

जोड़े 127.0.0.1 wsdev.company.comको /etc/hosts

इस तरह से आपका ब्राउज़र कुकीज़ का उपयोग करेगा mycompany.comजब www.mycompany.com/api/wsआप एक वैध उपडोमेन से जुड़ रहे हैं wsdev.company.com


-1

मेरी स्थिति में (Azure Time Series अंतर्दृष्टि wss: //)

ReconnectingWebsocket आवरण का उपयोग करना और एक सरल समाधान के साथ हेडर जोड़ने में सक्षम था:

socket.onopen = function(e) {
    socket.send(payload);
};

इस मामले में पेलोड कहां है:

{
  "headers": {
    "Authorization": "Bearer TOKEN",
    "x-ms-client-request-id": "CLIENT_ID"
}, 
"content": {
  "searchSpan": {
    "from": "UTCDATETIME",
    "to": "UTCDATETIME"
  },
"top": {
  "sort": [
    {
      "input": {"builtInProperty": "$ts"},
      "order": "Asc"
    }], 
"count": 1000
}}}

-3

तकनीकी रूप से, आप प्रोटोकॉल उन्नयन चरण से पहले कनेक्ट हेडर के माध्यम से इन हेडर को भेजेंगे। यह मेरे लिए एक nodejsपरियोजना में काम करता है :

var WebSocketClient = require('websocket').client;
var ws = new WebSocketClient();
ws.connect(url, '', headers);

3
यह npm (नोड के लिए) में वेबसोकेट क्लाइंट के लिए है। npmjs.com/package/websocket कुल मिलाकर यह वही होगा जो मैं देख रहा हूं, लेकिन ब्राउज़र में।
२०

1
इसे डाउनवोट किया गया है क्योंकि यह हेडर पैरामीटर वेबसोकेट प्रोटोकॉल लेयर पर है, और सवाल HTTP हेडर के बारे में है।
टॉइलट

" headersअनुरोध के साथ भेजने के लिए अतिरिक्त मनमाना HTTP अनुरोध हेडर निर्दिष्ट करने के लिए या तो अशक्त या एक वस्तु होनी चाहिए।" से WebSocketClient.md ; इसलिए, headersयहाँ HTTP लेयर है।
मोमोको

इसके अलावा, जो कोई भी कस्टम हेडर प्रदान करना चाहता है connect, उसे विधि के फ़ंक्शन हस्ताक्षर को ध्यान में रखना चाहिए , जैसा कि वर्णित किया जाना चाहिए connect(requestUrl, requestedProtocols, [[[origin], headers], requestOptions]), अर्थात , उदाहरण के लिए, headersके साथ प्रदान किया जाना चाहिए । केवल स्ट्रिंग को इस मामले में अनदेखा किया जा सकता है। requestOptionsws.connect(url, '', headers, null)origin
मोमोको

-3

आप हेडर को किसी ऑब्जेक्ट के अंदर तीसरे पैरामीटर (विकल्प) में एक कुंजी-मूल्य के रूप में पास कर सकते हैं । प्राधिकरण टोकन के साथ उदाहरण। प्रोटोकॉल (दूसरा पैरामीटर) को शून्य के रूप में छोड़ दिया

ws = नया WebSocket ('ws: // localhost', null, {हेडर: {प्राधिकरण: टोकन}})

संपादित करें: लगता है कि यह दृष्टिकोण केवल नोडज पुस्तकालय के साथ काम करता है मानक ब्राउज़र कार्यान्वयन के साथ नहीं। इसे छोड़कर क्योंकि यह कुछ लोगों के लिए उपयोगी हो सकता है।


मेरी उम्मीदें एक सेकंड के लिए थी। WebSocket ctor में 3rd Param लेने पर एक अधिभार नहीं प्रतीत होता है।
लेविटिकॉन

Wscat कोड से विचार मिला। github.com/websockets/wscat/blob/master/bin/wscat लाइन 261 wich ws पैकेज का उपयोग करता है। सोचा कि यह एक मानक उपयोग था।
Nodens
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.