원본 간 요청에 대한 쿠키 설정


103

원본 간 쿠키를 공유하는 방법은 무엇입니까? 더 구체적으로,Set-Cookie 헤더와 헤더를 조합Access-Control-Allow-Origin 무엇입니까?

내 상황에 대한 설명은 다음과 같습니다.

실행중인 API에 대한 쿠키를 설정하려고합니다. localhost:4000에서 호스팅되는 웹 앱에서localhost:3000 .

브라우저에서 올바른 응답 헤더를받는 것 같지만 유감스럽게도 효과가 없습니다. 다음은 응답 헤더입니다.

HTTP / 1.1 200 정상
Access-Control-Allow-Origin : http : // localhost : 3000
다름 : Origin, Accept-Encoding
Set-Cookie : token = 0d522ba17e130d6d19eb9c25b7ac58387b798639f81ffe75bd449afbc3cc715d6b038e426adeac3316f0511dc7fae3f7; Max-Age = 86400; 도메인 = localhost : 4000; 경로 = /; Expires = Tue, 19 Sep 2017 21:11:36 GMT; HttpOnly
콘텐츠 유형 : application / json; charset = utf-8
콘텐츠 길이 : 180
ETag : W / "b4-VNrmF4xNeHGeLrGehNZTQNwAaUQ"
날짜 : 2017 년 9 월 18 일 월요일 21:11:36 GMT
연결 : 연결 유지

또한 Response CookiesChrome 개발자 도구의 네트워크 탭을 사용하여 트래픽을 검사 할 때 아래에있는 쿠키를 볼 수 있습니다. 그러나 아래의 응용 프로그램 탭에서 쿠키가 설정되는 것을 볼 수 없습니다 Storage/Cookies. CORS 오류가 표시되지 않으므로 다른 것이 누락되었다고 가정합니다.

어떤 제안?

업데이트 I :

React-Redux 앱 의 요청 모듈을 사용 /signin하여 서버 의 엔드 포인트에 요청을 발행하고 있습니다. 서버의 경우 Express를 사용합니다.

Express 서버 :

res.cookie ( 'token', 'xxx-xxx-xxx', {maxAge : 86400000, httpOnly : true, 도메인 : 'localhost : 3000'})

브라우저에서 요청 :

request.post ({uri : '/ signin', json : {userName : 'userOne', 비밀번호 : '123456'}}, (err, response, body) => {
    // 작업
})

업데이트 II :

이제 요청 및 응답 헤더를 미친 듯이 설정하여 요청과 응답 모두에 있는지 확인합니다. 아래는 스크린 샷입니다. 헤더를 주목 Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-MethodsAccess-Control-Allow-Origin. Axios의 github 에서 찾은 문제를 살펴보면 필요한 모든 헤더가 이제 설정되었다는 인상을 받았습니다. 하지만 아직 운이 없습니다 ...

여기에 이미지 설명 입력


4
@PimHeijden이 이것을보세요 : developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/… 아마도 withCredentials의 사용이 당신에게 필요한 것일까 요?
Kalamarico

2
Ok 당신은 요청을 사용하고 있으며 이것이 최선의 선택이 아니라고 생각합니다.이 게시물과 답변을 살펴보십시오. axios가 유용 할 수 있다고 생각합니다. stackoverflow.com/questions/39794895/…
Kalamarico

감사! request모듈이 브라우저에서 사용하기위한 것이 아님 을 알아 차리지 못했습니다 . Axios는 지금까지 훌륭한 일을하는 것 같습니다. 이제 헤더 : Access-Control-Allow-Credentials:trueAccess-Control-Allow-Origin:http://localhost:3000(CORS를 활성화하는 데 사용됨)을 모두받습니다 . 이 바로 보인다하지만 Set-Cookie... 헤더 나던 아무것도 할
핌 Heijden

동일한 문제이지만 Axios 직접 사용 : stackoverflow.com/q/43002444/488666 . { withCredentials: true }실제로 Axios 측에서 필요 하지만 서버 헤더도주의 깊게 확인해야합니다 ( stackoverflow.com/a/48231372/488666 참조 )
Frosty Z

어떤 서버 헤더?
Pim Heijden

답변:


169

해야 할 일

CORS 요청에 의한 쿠키 수신 및 전송을 허용하려면 다음을 수행하십시오.

백엔드 (서버) : HTTP 헤더 Access-Control-Allow-Credentials값을 true. 또한, 확인 HTTP 헤더 Access-Control-Allow-OriginAccess-Control-Allow-Headers및 설정 하지 와일드 카드* .

Express js에서 CORS 설정에 대한 자세한 내용은 여기에서 문서를 읽어보세요.

프런트 엔드 (클라이언트) :XMLHttpRequest.withCredentials 플래그를로 설정합니다 true. 사용 된 요청-응답 라이브러리에 따라 다른 방법으로 수행 할 수 있습니다.

또는

CORS를 쿠키와 함께 사용하지 마십시오. 프록시로이를 달성 할 수 있습니다.

어떤 이유로 든 피하지 마십시오. 해결책은 위에 있습니다.

도메인에 포트가 있으면 Chrome이 쿠키를 설정하지 않는 것으로 나타났습니다. localhost(포트없이) 설정 은 문제가되지 않습니다. 이 팁에 대해 Erwin 에게 감사드립니다 !


2
나는 당신이 이것을 localhost확인 하기 때문에이 문제가 있다고 생각합니다 : stackoverflow.com/a/1188145 그리고 이것은 당신의 경우에 도움이 될 수 있습니다 ( stackoverflow.com/questions/50966861/… )
Edwin

5
이 답변은 저에게 많은 도움이되었습니다! 그것을 찾는 데 오랜 시간이 걸렸습니다. 그러나 대답은 Access-Control-Allow-Origin명시 적 도메인 설정 이 필요하다는 것을 언급해야한다고 생각 "*"합니다. 그렇다면 그것은 완벽한 답이 될 것입니다
e.dan

6
이것은 좋은 대답이며 CORS, 헤더, 백엔드 및 프런트 엔드에 대한 모든 설정과 실제 하위 도메인으로 / etc / hosts를 로컬로 재정 의하여 localhost를 피합니다. 여전히 우체부가 응답 헤더에 SET-COOKIE를 표시하지만 크롬 디버그는 그렇지 않습니다. 응답 헤더에 이것을 표시하고 쿠키는 실제로 크롬에 설정되어 있지 않습니다. 확인해야 할 다른 아이디어가 있습니까?
bjm88

1
@ bjm88 이걸 알아 내 셨나요? 나는 똑같은 상황에 있습니다. 쿠키는 localhost : 3010에서 localhost : 5001로 연결할 때 제대로 설정되지만 localhost : 3010에서 fakeremote : 5001 (내 호스트 파일에서 127.0.0.1을 가리킴)으로 작동하지 않습니다. 사용자 정의 도메인 (localhost : 3010에서 mydomain.com으로 연결)이있는 실제 서버에서 내 서버를 호스팅 할 때도 똑같습니다. 이 답변에서 권장되는 모든 것을 수행했으며 다른 많은 것을 시도했습니다.
양식

1
Angular에서 필요한 클라이언트 측 변경은 withCredentials를 추가하는 것입니다. HttpClient.post, .get, options 등에 전달 된 옵션에 true입니다.
Marvin

18

2020 년에 출시 된 Chrome 브라우저에 대한 참고 사항입니다.

Chrome의 향후 릴리스는 다음으로 설정된 경우 교차 사이트 요청으로 만 쿠키를 제공합니다. SameSite=NoneSecure .

따라서 백엔드 서버가 SameSite = None을 설정하지 않으면 Chrome은 기본적으로 SameSite = Lax를 사용하며 {withCredentials : true} 요청에이 쿠키를 사용하지 않습니다.

더 많은 정보 https://www.chromium.org/updates/same-site .

Firefox 및 Edge 개발자도 향후이 기능을 출시하기를 원합니다.

사양은 여기에서 찾을 수 있습니다. https://tools.ietf.org/html/draft-west-cookie-incrementalism-01#page-8


5
samesite = none 및 보안 플래그를 제공하려면 HTTPS가 필요합니다. HTTPS가 옵션이 아닌 로컬 시스템에서이를 달성하는 방법은 무엇입니까? 어떻게 든 우회 할 수 있습니까?
nirmal patel

@nirmalpatel Chome 개발 콘솔에서 "Lax"값을 제거하면됩니다.
LennyLip

5

클라이언트가 원본 간 요청에서 쿠키를 읽을 수 있으려면 다음이 필요합니다.

  1. 서버의 모든 응답에는 헤더에 다음이 있어야합니다.

    Access-Control-Allow-Credentials: true

  2. 클라이언트는 withCredentials: true옵션 과 함께 모든 요청을 보내야합니다.

Angular 7 및 Spring Boot를 사용한 구현에서 다음과 같이 달성했습니다.


서버 측:

@CrossOrigin(origins = "http://my-cross-origin-url.com", allowCredentials = "true")
@Controller
@RequestMapping(path = "/something")
public class SomethingController {
  ...
}

origins = "http://my-cross-origin-url.com"부분은 Access-Control-Allow-Origin: http://my-cross-origin-url.com모든 서버의 응답 헤더에 추가 됩니다.

allowCredentials = "true"부분은 Access-Control-Allow-Credentials: true클라이언트가 쿠키를 읽기 위해 필요한 모든 서버의 응답 헤더에 추가 됩니다.


고객 입장에서:

import { HttpInterceptor, HttpXsrfTokenExtractor, HttpRequest, HttpHandler, HttpEvent } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from 'rxjs';

@Injectable()
export class CustomHttpInterceptor implements HttpInterceptor {

    constructor(private tokenExtractor: HttpXsrfTokenExtractor) {
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // send request with credential options in order to be able to read cross-origin cookies
        req = req.clone({ withCredentials: true });

        // return XSRF-TOKEN in each request's header (anti-CSRF security)
        const headerName = 'X-XSRF-TOKEN';
        let token = this.tokenExtractor.getToken() as string;
        if (token !== null && !req.headers.has(headerName)) {
            req = req.clone({ headers: req.headers.set(headerName, token) });
        }
        return next.handle(req);
    }
}

이 클래스를 사용하면 실제로 모든 요청에 ​​추가 항목을 주입합니다.

첫 번째 부분 req = req.clone({ withCredentials: true });withCredentials: true옵션 과 함께 각 요청을 보내기 위해 필요한 것입니다 . 이것은 실질적으로 OPTION 요청이 먼저 전송된다는 것을 의미하므로이 토큰이 헤더에 첨부되어야하는 실제 POST / PUT / DELETE 요청을 보내기 전에 쿠키와 인증 토큰을 얻을 수 있습니다. 서버가 요청을 확인하고 실행하도록 명령합니다.

두 번째 부분은 모든 요청에 ​​대해 anti-CSRF 토큰을 특별히 처리하는 부분입니다. 필요할 때 쿠키에서 읽고 모든 요청의 헤더에 씁니다.

원하는 결과는 다음과 같습니다.

응답 의뢰


이 답변은 기존 답변에 무엇을 추가합니까?
Pim Heijden

2
실제 구현. 게시하기로 결정한 이유는 동일한 문제를 검색하고이를 실현하기 위해 여러 게시물의 조각을 함께 추가하는 데 많은 시간을 소비하기 때문입니다. 이 게시물을 비교 용으로 사용하면 다른 사람이 똑같이하는 것이 훨씬 쉬울 것입니다.
Stefanos Kargas

주석에 설정 allowCredentials = "true"을 표시 @CrossOrigin하는 것이 도움이되었습니다.
ponder275

위의 답변에서 언급 한 @lennylip은 samesite 및 보안 플래그에 대한 오류를 표시합니다. 보안 플래그없이 localhost 서버로이를 달성하는 방법.
nirmal patel

2

Express의 경우 Express 라이브러리를 다음으로 업그레이드하십시오. 4.17.1 경우 최신 안정 버전 인 . 그때;

CorsOption에서 : origin로컬 호스트 URL 또는 프런트 엔드 프로덕션 URL로 설정하고 예 credentialstrue들어

  const corsOptions = {
    origin: config.get("origin"),
    credentials: true,
  };

config npm module을 사용하여 동적으로 원본을 설정했습니다 .

그런 다음 res.cookie에서 :

localhost의 경우 : sameSite 및 보안 옵션을 전혀 설정할 필요가 없으며 사용 사례에 따라 XSS 공격 및 기타 유용한 옵션 을 방지 httpOnly하기 true위해 http 쿠키에 대해 설정할 수 있습니다 .

프로덕션 환경의 경우 원본 간 요청 sameSitenone대해 로 설정 secure하고 true. 기억 sameSite에만 지금에서와 같은 명시 최신 버전 및 최신 크롬 버전 이상에서만 설정 쿠키와 작품 https, 보안 옵션에 따라서 필요.

내가 어떻게 동적으로 만들 었는지

 res
    .cookie("access_token", token, {
      httpOnly: true,
      sameSite: app.get("env") === "development" ? true : "none",
      secure: app.get("env") === "development" ? false : true,
    })

0

Pim의 답변은 매우 유용합니다. 제 경우에는

Expires / Max-Age: "Session"

dateTime이면 만료되지 않았더라도 백엔드에 쿠키를 보내지 않습니다.

Expires / Max-Age: "Thu, 21 May 2020 09:00:34 GMT"

같은 문제를 만날 수있는 미래의 사람들에게 도움이 되길 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.