즉 SOP란 자신과 동일한 출처(Origin)의 서버로 부터만 데이터를 요청하여 받을 수 있도록 하는 정책이다.
https://www.google.com:443
https://www.google.com:443/search?q=CORS : 동일출처
http://www.google.com:443 : 다른출처
https://www.naver.com:443 : 다른출처
https://www.google.com:123 : 다른출처
: Option 메서드를 통해 다른 도메인의 리소스에 요청이 가능한지 확인하고 가능하다면 실제 요청을 보낸다.
: 요청을 보내면 즉시 cross origin인지 확인한다.
: 인증 관련 헤더를 포함할 때 사용하는 요청이다. 쿠키나 토큰을 전달하고 싶을 때 사용하는 요청이다.
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*"); // 모든 도메인
res.header("Access-Control-Allow-Origin", "https://example.com"); // 특정 도메인
});
const cors = require("cors");
const app = express();
app.use(cors());
const options = {
origin: "http://example.com", // 접근 권한을 부여하는 도메인
credentials: true, // 응답 헤더에 Access-Control-Allow-Credentials 추가
optionsSuccessStatus: 200, // 응답 상태 200으로 설정
};
app.use(cors(options));
app.get("/example/:id", cors(), function (req, res, next) {
res.json({ msg: "example" });
});
기본적으로 @CrossOrigin은 모든 출처, 모든 헤더, @RequestMapping 주석에 지정된 Http 메소드에 최대 30분을 허용한다. 어노테이션에 속성 값을 넣어 기본 값을 대체할 수 있다.
속성값을 살펴보면,
@CrossOrigin(origin="*", allowedHeaders = "*")
@Controller
public class MainController {
@GetMapping(path = "/")
public String main(Model model) {
return "main";
}
}
스프링 CORS : CorsFilter 사용하기
서블릿 필터 인터페이스를 이용하여 개발되었다. 웹 서버의 모든 리소스의 요청을 가로채서 Cross domain request인지 체크하여 실제 요청 페이지에 전달하기전에 적절한 CORS 정책과 해더들을 적용한다.
Access-Control-Allow-Origin
도메인 간 요청을 할 수 있는 권한이 부여된 도메인을 지정한다.
Access-Control-Allow-Credentials
도메인 간 요청에 credential 권한이 있는지 없는지 지정한다.
Access-Control-Expose-Headers
노출하기에 안전한 헤더를 나타낸다.
Access-Control-Max-Age
pre-flighted 요청이 얼마만큼의 시간동안 캐시되는지
Access-Control-Allow-Methods
리소스에 접근할 때 메소드가 허용되는지
Access-Control-Allow-Headers
어떤 헤더 필드 네임이 실제 요청에서 사용할 수 있는지 가리킨다.
@Component
public class SimpleCorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT, PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}