Websockets 클라이언트 API의 HTTP 헤더


200

이를 지원하는 HTTP 헤더 클라이언트를 사용하여 웹 소켓 클라이언트에 사용자 정의 HTTP 헤더를 쉽게 추가하는 것처럼 보이지만 JSON API로 수행하는 방법을 찾을 수 없습니다.

그러나 spec에서 이러한 헤더를 지원해야합니다 .

누구나 그것을 달성하는 방법에 대한 단서가 있습니까?

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

특히, HTTP 인증 헤더를 보낼 수 있어야합니다.


14
좋은 해결책은 WebSocket이 인증없이 연결하도록 허용하지만 서버에서 차단하고 기다렸다가 onSocket 이벤트에서 인증 정보를 전송하는 webSocket에서 인증을받을 수 있다고 생각합니다.
Motes

@Motes의 제안이 가장 적합한 것 같습니다. 권한 부여 응답을 기반으로 소켓을 수락 / 거부 할 수있는 onOpen에서 권한 부여 호출을하는 것이 매우 쉽습니다. 원래 Sec-WebSocket-Protocol 헤더에서 인증 토큰을 보내려고 시도했지만 해킹처럼 느껴집니다.
BatteryAcid

@Motes 안녕하세요, "서버 차단 및 대기"부분을 설명해 주시겠습니까? "auth"메시지가 나타날 때까지 메시지를 처리하지 않는 것과 같은 것을 의미합니까?
Himal

@Himal, 예. 서버 디자인은 연결 시작시 데이터를 보내거나 권한 부여 이외의 다른 데이터를 허용해서는 안됩니다.
Motes

@Motes 답장을 보내 주셔서 감사합니다. 초기 connect요청을 차단 할 수 없다는 것을 이해했기 때문에 차단 부분에 혼란 스러웠습니다 . 백엔드에서 Django 채널을 사용하고 있으며 connect이벤트 연결을 허용하도록 설계했습니다 . 그런 다음 receive이벤트 에서 "is_auth"플래그를 설정합니다 (유효한 인증 메시지가 표시되는 경우). is_auth 플래그가 설정되지 않고 인증 메시지가 아닌 경우 연결을 닫습니다.
Himal

답변:


210

2 배 업데이트

짧은 대답 : 아니요. 경로 및 프로토콜 필드 만 지정할 수 있습니다.

더 긴 답변 :

JavaScript WebSockets API 에는 클라이언트 / 브라우저가 보낼 추가 헤더를 지정하는 방법이 없습니다 . HTTP 경로 ( "GET / xyz") 및 프로토콜 헤더 ( "Sec-WebSocket-Protocol")는 WebSocket 생성자에서 지정할 수 있습니다.

Sec-WebSocket-Protocol 헤더 (웹 소켓 특정 인증에 사용되도록 확장되는 경우도 있음)는 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 클라이언트를 호스팅하는 페이지가 서버로부터 티켓을 요청한 다음 URL / 쿼리 문자열, 프로토콜 필드의 WebSocket 연결 설정 중에이 티켓을 전달하는 티켓팅 시스템을 구현하는 것입니다. 또는 연결이 설정된 후 첫 번째 메시지로 필요합니다. 그런 다음 서버는 티켓이 유효한 경우 (연결이 존재하고, 이미 사용되지 않았거나, 티켓 일치로 인코딩 된 클라이언트 IP, 티켓의 타임 스탬프가 최근 인 경우 등) 연결을 계속 허용합니다. 다음은 WebSocket 보안 정보를 요약 한 것입니다 : https://devcenter.heroku.com/articles/websocket-security

기본 인증은 이전에는 옵션 이었지만 더 이상 사용되지 않으며 최신 브라우저는 지정된 경우에도 헤더를 보내지 않습니다.

기본 인증 정보 (더 이상 사용되지 않음) :

Authorization 헤더는 WebSocket URI의 사용자 이름 및 비밀번호 (또는 사용자 이름) 필드에서 생성됩니다.

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

위의 결과는 문자열 "username : password"base64로 다음 헤더를 생성합니다.

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

Chrome 55 및 Firefox 50에서 기본 인증을 테스트했으며 기본 인증 정보가 실제로 서버와 협상되어 있는지 확인했습니다 (Safari에서는 작동하지 않을 수 있음).

기본 인증 답변 을 제공 한 Dmitry Frank의 감사


37
나는 같은 문제를 겪었습니다. 이러한 표준이 제대로 통합되지 않아서 너무 나쁩니다. WebSockets API에 대한 요구 사항 (WebSocket 및 XHR이 관련되어 있기 때문에)을 찾기 위해 XHR API를 볼 것으로 기대하지만, 자체적으로 섬에서 API를 개발하는 것 같습니다.
eleotlecram

4
@eleotlecram, HyBi 실무 그룹에 가입하여 제안하십시오. 이 그룹은 공개되어 있으며 이후 버전의 프로토콜에 대한 작업이 진행 중입니다.
카나 카

5
@Charlie : 서버를 완전히 제어한다면, 이것이 하나의 옵션입니다. 보다 일반적인 방법은 일반 HTTP 서버에서 티켓 / 토큰을 생성 한 다음 클라이언트가 티켓 / 토큰을 보내도록하는 것입니다 (웹 소켓 경로의 쿼리 문자열 또는 첫 번째 웹 소켓 메시지). 그런 다음 웹 소켓 서버는 티켓 / 토큰이 유효한지 (만료되지 않았거나, 이미 사용되지 않았으며, 생성 될 때와 동일한 IP에서 온 것 등) 유효성을 검증합니다. 또한 대부분의 웹 소켓 클라이언트가 기본 인증을 지원한다고 생각합니다 (충분하지 않을 수도 있음). 더 많은 정보 : devcenter.heroku.com/articles/websocket-security
kanaka

3
디자인에 의한 것 같아요. 구현이 의도적으로 HTTP에서 빌려오고 있지만 가능한 한 설계 상으로 분리되어 있다는 인상을 받고 있습니다. 구체적인 내용은 다음과 같이 계속됩니다. "그러나 디자인은 WebSocket을 HTTP로 제한하지 않으며 향후 구현에서는 전체 프로토콜을 다시 만들지 않고도 전용 포트를 통해 더 간단한 핸드 셰이크를 사용할 수 있습니다.이 마지막 요점은 대화식 메시징의 트래픽 패턴이 중요하기 때문입니다. 표준 HTTP 트래픽과 거의 일치하지 않으며 일부 구성 요소에 비정상적인로드를 유발할 수 있습니다. "

3
불행히도 이것은 Edge에서 작동하지 않는 것 같습니다. 감사합니다, MS : /
sibbl

40

더 많은 대체 솔루션이지만 모든 최신 브라우저는 연결과 함께 도메인 쿠키를 보내므로 다음을 사용하십시오.

var authToken = 'R3YKZFKBVi';

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

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

요청 연결 헤더로 끝납니다.

Cookie: X-Authorization=R3YKZFKBVi

1
연결시 액세스 토큰을 전달하는 가장 좋은 방법 인 것 같습니다. 현재
cammil

1
WS 서버 URI가 클라이언트 URI와 다른 경우 어떻게해야합니까?
덴마크어

35

HTTP 인증 헤더 문제는 다음을 통해 해결할 수 있습니다.

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

그런 다음 제공된 username및 로 적절한 기본 인증 HTTP 헤더가 설정됩니다 password. 기본 인증이 필요한 경우 모든 준비가 완료된 것입니다.


Bearer그러나 사용하고 싶지만 다음과 같은 트릭을 사용했습니다. 다음과 같이 서버에 연결합니다.

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

그리고 서버 측의 코드가 비어 있지 않은 사용자 이름과 빈 암호로 기본 권한 부여 헤더를 받으면 사용자 이름을 토큰으로 해석합니다.


12
나는 당신이 제안한 해결책을 시도하고 있습니다. 그러나 요청에 Authorization 헤더가 추가되는 것을 볼 수 없습니다. Chrome V56, Firefox V51.0과 같은 다른 브라우저를 사용하여 시도했습니다. 내 로컬 호스트에서 서버를 실행하고 있습니다. 따라서 웹 소켓 URL은 "ws : // myusername : mypassword @ localhost : 8080 / mywebsocket"입니다. 무슨 일인지 알 겠어? 감사합니다
LearnToLive

4
URL을 통해 토큰을 이체하는 것이 안전합니까?
Mergasov

2
사용자 이름이 기록 될 수 있기 때문에 비어 있거나 무시 된 사용자 이름과 비어 있지 않은 암호가 토큰으로 더 좋습니다.
AndreKR

9
@LearnToLive에 동의합니다. wss (예 :)와 함께 사용 했으며 서버 측에 헤더 wss://user:password@myhost.com/ws가 없습니다 Authorization(Chrome 버전 60 사용)
user9645

6
@LearnToLive 및 @ user9645와 동일한 문제가 있습니다. URI가 wss://user:pass@host형식 일 때 크롬이나 파이어 폭스 모두 인증 헤더를 추가하지 않습니다 . 브라우저에서 지원하지 않습니까, 아니면 악수에 문제가 있습니까?
David Kaczynski

19

헤더를 추가 할 수는 없지만 연결시 서버에 값을 전달해야하는 경우 URL에 쿼리 문자열 부분을 지정할 수 있습니다.

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

해당 URL은 유효하지만 물론 구문 분석하려면 서버 코드를 수정해야합니다.


14
이 솔루션에주의해야하므로 쿼리 문자열이 인터셉트되고 프록시 등에 로그인 될 수 있으므로 민감한 정보 (사용자 / 비밀번호 / 인증 토큰)를 전달하면 충분히 안전하지 않습니다.
Nir

5
WSS와 @Nir 쿼리 문자열은 아마도 안전합니다
세바스티앙 Lorber

8
ws는 일반 텍스트입니다. ws 프로토콜을 사용하면 무엇이든 가로 챌 수 있습니다.
Gabriele Carioli

1
@SebastienLorber 쿼리 문자열을 사용하는 것이 안전하지는 않지만 HTTPS에 동일하게 암호화되지는 않지만 "ws : // ..."프로토콜이 사용되므로 실제로 중요하지 않습니다.
Lu4

5
@ Lu4 쿼리 문자열은 암호화되지만 URL 쿼리 매개 변수로 민감한 데이터를 추가하지 않는 다른 이유가 많이 있습니다. stackoverflow.com/questions/499591/are-https-urls-encrypted/… & blog.httpwatch.com/2009 / 02 / 20 /… 참조

16

JavaScript WebSockets API를 사용하여 WebSockets 연결을 설정하려는 경우 사용자 정의 헤더를 보낼 수 없습니다. Subprotocols두 번째 WebSocket 클래스 생성자를 사용하여 헤더를 사용할 수 있습니다 .

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

그런 다음 Sec-WebSocket-Protocol서버에서 키를 사용하여 서브 프로토콜 헤더를 얻을 수 있습니다 .

또한 서브 프로토콜 헤더 값에는 쉼표 ( ,)를 사용할 수 없습니다 .


1
Jwt에 쉼표가 포함될 수 있습니까?
CESCO

1
나는 그렇게 믿지 않습니다. JWT는 각각 마침표로 구분 된 세 개의 base64 인코딩 페이로드로 구성됩니다. 나는 이것이 쉼표의 가능성을 배제한다고 믿는다.
BillyBBone

2
나는 이것을 구현했고 작동합니다. 이상하게 느낍니다. 감사합니다
BatteryAcid

3
Sec-WebSocket-Protocol헤더를 헤더 대신 사용할 것을 제안 Authorization합니까?
rrw

13

발신 인증 헤더를 보낼 수 없습니다.

토큰 쿼리 매개 변수를 첨부하는 것은 옵션입니다. 그러나 경우에 따라 기본 로그인 토큰을 일반 텍스트로 쿼리 매개 변수로 전송하는 것이 바람직하지 않을 수 있습니다. 헤더를 사용하는 것보다 불투명하고 누가 아는 곳에 기록되기 때문입니다. 이것이 보안 문제를 일으키는 경우 대안은 웹 소켓에 대해서만 보조 JWT 토큰을 사용하는 것 입니다.

이 JWT 생성을위한 REST 엔드 포인트를 작성 하십시오. 기본 로그인 토큰으로 인증 된 사용자 (헤더를 통해 전송 된 사용자) 만 액세스 할 수 있습니다. 웹 소켓 JWT는 로그인 토큰과 다르게 구성 할 수 있습니다 (예 : 시간 초과가 짧기 때문에 업그레이드 요청의 쿼리 매개 변수로 전송하는 것이 더 안전합니다).

SockJS eventbusHandler를 등록하는 동일한 경로에 대해 별도의 JwtAuthHandler를 작성하십시오 . 인증 핸들러가 먼저 등록되어 있는지 확인하여 데이터베이스에 대해 웹 소켓 토큰을 확인할 수 있습니다 (JWT는 어떻게 든 백엔드의 사용자와 링크되어야 함).


이것이 API Gateway 웹 소켓에 대해 유일하게 확보 할 수있는 유일한 보안 솔루션이었습니다. Slack은 RTM API와 비슷한 기능을 수행하며 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
클라이언트가 하나 이상의 특정 프로토콜을 요청 해야하는 섹션에서 토큰을 전달하지 않습니까? 나는 이것도 문제없이 작동시킬 수 있지만, 이것을하지 않기로하고 MoTo가 제안한 것을 수행하고 인증 토큰이 onOpen ()에 전송 될 때까지 차단합니다. 프로토콜 요청 헤더를 오버로드하는 것은 나에게 잘못된 것처럼 보이며 내 API는 대중 소 비용이므로 API 소비자에게는 다소 혼란 스럽다고 생각합니다.
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/wswsdev.company.com


-1

내 상황에서 (Azure Time Series Insights 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 전반적으로 이것은 내가 찾고있는 것이지만 브라우저에서 그렇습니다 .
arnuschky

1
WebSocket 프로토콜 레이어 에이 헤더 매개 변수가 포함되어 있기 때문에 다운 투표되었으며 질문은 HTTP 헤더에 관한 것입니다.
Toilal

" headers는 null이거나 요청과 함께 보낼 추가 HTTP 요청 헤더를 지정하는 객체 여야합니다." 에서 WebSocketClient.md ; 따라서 headers여기에 HTTP 레이어가 있습니다.
momocow

또한, 사용자 정의 헤더를 제공하기 위해 원하는 사람은 마음의 함수 서명 유지해야 connect설명 방법을 connect(requestUrl, requestedProtocols, [[[origin], headers], requestOptions])이 예 headers와 함께 제공되어야한다 requestOptions, 예를 들어, ws.connect(url, '', headers, null). origin이 경우 문자열 만 무시할 수 있습니다.
momocow

-4

객체 내부 의 세 번째 매개 변수 (옵션) 에서 헤더를 키-값 으로 전달할 수 있습니다 . 인증 토큰이있는 예. 프로토콜 (두 번째 매개 변수)을 널로 두었습니다.

ws = new WebSocket ( 'ws : // localhost', null, {헤더 : {인증 : 토큰}})

편집 :이 방법은 표준 브라우저 구현이 아닌 nodejs 라이브러리에서만 작동하는 것으로 보입니다. 일부 사람들에게 유용 할 수 있으므로 그대로 두십시오.


나의 희망이 잠깐 동안 있었다. WebSocket ctor에서 3 번째 매개 변수를 취하는 과부하가없는 것 같습니다.
Levitikon

wscat 코드에서 아이디어를 얻었습니다. github.com/websockets/wscat/blob/master/bin/wscat 라인 261은 ws 패키지를 사용합니다. 이것이 표준 사용법이라고 생각했습니다.
Nodens
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.