Nix + Caddy 서버에서 CORS 설정하기
개요: 여러곳에서 사용할 수 있는 API 서버를 만들기가 쉽지 않다.
간단하게 말하자면 웹표준을 준수하는 CORS를 만들기가 꽤 번거롭다.
처음에는 그냥 access-control-allow-...
헤더를 적당히 설정하면 CORS는
해결되는 건줄 알았다:
access-control-allow-origin *
access-control-allow-methods *
access-control-allow-headers "origin,content-type,accept"
정도만 설정해도 행복했었는데, 나중에 인증 붙이려고 보니까…
access-control-allow-origin: *
인 경우, credentials가 전달되지 않음
글을 쓰면서 생각해보니 이걸 허용하면 XSS 공격이 들어왔을 때 현재 브라우저의 인증 정보가 마구 유출될 수 있어서 불가피한 선택으로 보인다.- 따라서 access-control-allow-origin에 내가 허용하는 도메인 목록을 나열해서
적어줘야 하는데, 그럼…
- 개발은 어떻게 하나?
http://localhost:3000
을 허용해야 하나? - 내가 XSS 구겨넣은 앱에서 접근하는건 또
origin: null
이라는 황당한 헤더인데, 이런것도 allow시켜주면 되는건가?
- 개발은 어떻게 하나?
- 그리고
...-allow-origin
에 여러개의 허용 사이트 목록을 보내줄 수 있는지도 모르겠지만 보내선 안될 것 같은 느낌이 들었다. 따라서 요청의origin
이 맞는 경우에만 거기에 맞춰서 CORS 헤더를 반환하도록 해야 했다. 바꿔말하면 서버가 요청의 헤더값을 참조해서 매칭을 수행해야 한다는 것.
결론적으로, Caddy 서버를 NixOS에서 설정하는 것 기준으로 다음과 같은 설정 파일이 만들어졌다.
{ pkgs, ... }: {
services.caddy =
{
enable = true;
extraConfig = ''
(cors) {
@origin{args.0} header Origin {args.0}
header @origin{args.0} Access-Control-Allow-Origin "{args.0}";
header @origin{args.0} Access-Control-Allow-Credentials "true";
header @origin{args.0} Access-Control-Allow-Methods *;
header @origin{args.0} Access-Control-Allow-Headers "Origin,Content-Type,Accept,Authorization";
}
'';
virtualHosts = {
"gql-service.example.com".extraConfig = ''
@cors_preflight method OPTIONS
@emptyorigin header !Origin
header @emptyorigin {
Access-Control-Allow-Origin "*"
Access-Control-Allow-Methods "GET,POST,OPTIONS"
Access-Control-Allow-Headers "Origin,Content-Type,Accept,Authorization"
Access-Control-Allow-Credentials "true"
};
import cors http://localhost:3000
import cors https://web.example.com
import cors null
handle @cors_preflight {
header {
Access-Control-Max-Age "3600"
}
respond "" 204
}
reverse_proxy localhost:8181
'';
};
};
}
결론
쓸데없이 번거롭다.