programing

EventSource의 HTTP 인가 헤더(서버가 송신한 이벤트)

testmans 2023. 3. 6. 20:49
반응형

EventSource의 HTTP 인가 헤더(서버가 송신한 이벤트)

Authorization 헤더를 HTML5 EventSource로 설정해야 합니다.Websockets가 등장한 이후 Server Sent Events가 사용되지 않는 것 같아서 도움이 되는 문서를 찾을 수 없습니다.제가 이미 찾은 방법은 url 내에서 인증 데이터를 전달하는 것입니다.이 방법은 마음에 안 들어요.

Angular를 사용하고 있습니다.JS를 사용하여 $httpProvider에 가로채기를 설정하지만 EventSource는 AngularJS에 의해 가로채지 않기 때문에 헤더를 추가할 수 없습니다.

당신의 투고가 1년 전에 끝났다는 것을 알지만, 저는 지금 좋은 답변으로 같은 처지에 있다는 것을 알게 되었습니다.이게 누군가에게 도움이 되거나 최소한 아이디어라도 주길 바라고 있어요

쿠키는 쉬워 보이지만 누군가 쿠키를 차단하면 어떻게 될까요?사이트를 사용하려면 쿠키를 활성화해야 합니다.보안상의 이유로 쿠키를 비활성화했기 때문에 이 시점에서 사이트를 신뢰할 수 있을지 의심하기 시작합니다.보안상의 이유로 쿠키를 활성화해야 합니다!

AJAX를 사용하면 SSL을 통해 인증 데이터를 쉽게 POST할 수 있지만 SSE에서는 가능하지 않습니다.사람들이 "querystring만 사용하세요"라고 말하는 게시물은 많이 보았지만 인증 데이터를 일반 텍스트(example.com/stream?sessionID=idvalue))로 전송하여 고객의 보안을 침해하고 싶지 않습니다.

몇 시간 동안 머리를 짜낸 결과, 고객의 인증 데이터에 영향을 주지 않고 전체적인 목표를 달성할 수 있다는 것을 깨달았습니다.EventSource 접속을 확립할 때 POST를 할 수 있는 방법은 아직 발견되지 않았지만 브라우저가 재접속할 때마다 EventSource를 사용하여 인증 토큰을 안전하게 전달할 수 있습니다.중요한 것은 원하는 세션을 얻는 것입니다.마지막 이벤트에 대한 ID/토큰아이디

사용자는 사용자 이름/비밀번호를 사용하여(또는 로컬 저장소에 보관하는 토큰을 AJAX POST하여) 평소처럼 인증할 수 있습니다.AJAX 인증 프로세스는 짧은 토큰(60초 후 만료 또는 사용 시 만료됨)을 가진 JSON 개체를 반환하고 원하는 백엔드(예를 들어 mySQL)에 더 긴 토큰과 함께 저장합니다.이 시점에서 다음과 같이 SSE 접속을 시작합니다.

    qString = "?slt=" + "value-that-expires-within-seconds";
    streamURL = "http://example.com/stream.php";
    var streamSource = new EventSource(streamURL + qString);

    streamSource.addEventListener('auth',function(e) {
        var authStatus = JSON.parse(e.data);
        if (authStatus.session !== 'valid') {
            qString = "";
            streamSource.close();
        }
    })

대응하는 PHP에서는 다음과 같은 작업을 수행합니다.

        header("Content-Type: text/event-stream\n");
        ob_end_flush();
        ob_start();

        if (isThisShortLivedTokenValid($_GET["slt"])) {
            // The short-lived-token is still valid... so we will lookup
            // the value of the corresponding longer-lasting token and
            // IMMEDIATELY invalidate the short-lived-token in the db.
            sendMsg($realToken,'auth','session','valid');
            exit;
        } else if (isThisRealTokenValid($_SERVER["HTTP_LAST_EVENT_ID"])){
            while (1) {
                // normal code goes here
                // if ($someCondition == 'newDataAvailable') sendMsg($realToken,'chat','msg-id','msg-content');
            }
        } else {
            http_response_code(404); // stop the browser from reconnecting.
            exit; //quit the PHP script and don't send anything.
        }


        function sendMsg($id, $event, $key, $val) {
            echo "{" . PHP_EOL;
            echo "event: " . $event . PHP_EOL;
            echo "id: $id" . PHP_EOL;
            echo 'data: {"' . $key . '" : "' . $val . '"}' . PHP_EOL;
            echo "}" . PHP_EOL;
            echo PHP_EOL;
            ob_flush();
            flush();
        }

        function isThisShortLivedTokenValid($sltValue) {
            //stuff to connect to DB and determine if the
            //value is still valid for authentication
            return $dbResult == $sltValue ? TRUE : FALSE;
        }

SSE는 단명토큰에 접속하고 PHP는 단명토큰에 대해 검증하여 DB에서 삭제하므로 다시는 인증할 수 없습니다.온라인 뱅킹에 로그인하기 위해 6자리 코드를 문자메시지로 받았을 때와 비슷합니다.PHP를 사용하여 데이터베이스에서 취득한 REAL 토큰을 이벤트 ID로 푸시합니다.Javascript가 이 이벤트를 수행할 필요는 없습니다.서버는 자동으로 연결을 종료하지만 더 많은 작업을 하고 싶다면 이벤트를 들을 수 있습니다.

이 시점에서 SSE 접속은 PHP가 스크립트를 완료한 후 종료되었습니다.다만, 브라우저는 자동적으로 접속을 재정립합니다(통상은 3초).이번에는 lastEventId를 전송합니다...이 값은 연결을 끊기 전에 토큰 값으로 설정했습니다.다음 연결 시 이 값이 토큰으로 사용되며 앱이 예상대로 실행됩니다.메시지 또는 이벤트를 보낼 때 실제 토큰을 이벤트 ID로 사용하기 시작하는 한 연결을 끊을 필요는 없습니다.이 토큰 값은 브라우저가 토큰을 수신했을 때와 이후 서버에 접속할 때마다 SSL을 통해 완전히 암호화되어 전송됩니다.「클리어」로 송신된 값은, 수신해 사용한 시점으로부터 수초 이내에 기한이 만료되어, 그 값을 검출한 사람은 사용할 수 없게 되었습니다.다른 사용자가 사용하려고 하면 404 응답이 표시됩니다.

이미 이벤트 스트림 ID를 다른 용도로 사용하고 있는 경우, auth-token과 이전에 사용한 값을 연결하여 다른 앱에 대해 투명하도록 변수로 분할하지 않는 한 "즉시 사용 가능"하지 않을 수 있습니다.예를 들어 다음과 같습니다.

    // when sending data, send both values
    $sseID = $token_value . "_" . $previouslyUsedID;
    sendMsg($sseID,'chat','msg-id','msg-content');

    // when a new connection is established, break apart the values
    $manyIDs = explode("_", $_SERVER["HTTP_LAST_EVENT_ID"])
    $token_value = $manyIDs[0]
    $previouslyUsedID = $manyIDs[1]

EventSource에는 HTTP 헤더를 서버로 보내기 위한 API가 없습니다.저도 SSE를 사용하여 실시간 채팅을 작성할 때 이 문제로 고민하고 있었습니다.

다만, SSE 서버가 인증 서버와 같은 서버라면, 쿠키는 자동적으로 송신된다고 생각합니다.

이 폴리필에는 인가 헤더 지원이 추가되었습니다.https://github.com/Yaffle/EventSource/

다음과 같은 작업을 수행할 수 있습니다.

new EventSource("https://domain/stream", { authorizationHeader: "Bearer ..." });

window.EventSource추가 헤더 전달을 아직 지원하지 않는 것 같습니다.좋은 소식은 다른 일반적인 구현이 있다는 것입니다.EventSource추가 헤더를 지원합니다.그 중 몇 가지는 다음과 같습니다.

const eventSource = new EventSource(resoureUrl, {
            headers: {
                'Authorization': 'Bearer ' + authorizationToken
            }
        });

eventSource.onmessage = result => {
    const data = JSON.parse(result.data);
    console.log('Data: ', data);
};

eventSource.onerror = err => {
    console.log('EventSource error: ', err);
};

이벤트 소스 polyfill의 이 포크를 사용하면 라파엘즐리스보아의 설명과 마찬가지로 인가 헤더를 추가할 수 있습니다.https://github.com/AlexGalays/EventSource#923b9a0998fcfd7753040e09aa83764b3cc0230d

Ï don't know if you can provide the authentication header as a second argument like in rafaelzlisboa's example, I got it to work by creating a headers object, and putting my authorization header in there, like this:

new EventSource("https://domain/stream", { headers: { Authorization: Bearer.... }});

인증 토큰을 전달하는 다른 방법은 쿼리 파라미터로서 URL을 통과하는 것이지만 보안을 고려해야 합니다.서버측 쿼리 파라미터를 통한 인가 지원도 추가합니다.

SSE 콜 전에 이 문제를 해결했습니다.나머지에서는 SSE 콜 및 취득에 필요한 것과 동일한 보안 프로토콜과 응답 OTP가 필요합니다.또한 이 OTP를 전송하여 콜 쿼리 파라미터를 확인하고 웹 필터에서 이 OTP를 검증하여 인증 헤더로 대체합니다.

인증 토큰이 EventSource() 호출로 전송되는지 확인하기 위해 많은 게시물을 검토했습니다.https://github.com/whatwg/html/issues/2177 헤더를 추가할 수 있는 polyfill 대안도 있지만 다른 사람들은 ssl을 통해 인증 토큰을 보내는 것을 언급했습니다.

polyfill EventSource()를 사용하거나 쿼리 파라미터 내의 인증 토큰을 ssl 경유로 송신하는 대신 다음과 같이 EventSource URL 파라미터 내의 eventSource ID(EventSrcUID)를 송신합니다.

사용자 인증 시 eventSrcUUID는 서버상의 sseEmitter와 함께 생성되어 sseEmitterMap에 배치됩니다.

클라이언트는 응답에서 eventSrcUUID를 가져와 파라미터에 eventSrcUID를 포함한 EventSource() 콜을 호출합니다.서버에서는 sseEmitterMap을 참조하여 eventSrc 객체를 가져옵니다.세션 데이터에 저장된 sseEmitter 객체는 클라이언트에 이벤트 알림을 보내기 위해 사용됩니다.

언급URL : https://stackoverflow.com/questions/28176933/http-authorization-header-in-eventsource-server-sent-events

반응형