본문 바로가기

3.구현/HTML5&Javascript

[HTML] crossorigin 속성

들어가기

최근 작성했던 글을 보다가 특정 이미지가 보이지 않는 상황을 인지했다. 원인을 확인해보니 Chrome에서 CROS 정책으로 인해서 이미지 처리 중에 “No 'Access-Control-Allow-Origin' header is present on the requested resource.” 오류가 발생했다. 하나씩 살펴보자.

작성자: ospace114@empal.com, http://ospace.tistory.com/

crossorigin

crossorigin 속성은 audio, img, link, script, video 태그에 있는 속성이다. 이는 각 요소가 교차출처 리소스 공유(Cross-Origin Resource Sharing, CORS) 요청하는 방식을 지정할 수 있다. 설정할 수 있는 값은 아래와 같다.

  • anonymous: CORS 요청의 credentials flag가 ‘same-orgin’으로 지정.
  • use-credentials: CORS 요청의 credential flasg가 ‘include’로 지정
  • “”: crossorigin 또는 crossorigin=””처럼 빈 값으로 anonymous와 동일

img 태그를 사용해서 테스트 해보자. img에서는 crossorigin을 사용할 일은 거의 없다. 아마도 script나 link에서 많이 사용한다. 테스트하기에는 img가 적당하다.

출처: https://en.m.wikipedia.org/wiki/File:Tistory_logo.png

<img
  src="https://blog.kakaocdn.net/dn/byaIey/btsFywStXq5/GQQ65l5Bcu0WOLzSZj9xcK/img.png"
  crossorigin="anonymous"
/>

요청 메시지에는 아래와 같이 설정된다.

실제 이미지는 깨져서 보이지 않는다. 콘솔창에서는 아래와 같은 메시지가 표시된다.

  • Access to image at '.../img.png' from origin 'http://...' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

즉, 이미지 로딩조차할 수 없다. 응답 헤더에 “Access-Control-Allow-Origin”이 없는 경우 해당 리소스 접근을 제한한다. 그러나 대부분 crossorigin을 사용하지 않고 사용한다.

<img
  src="https://blog.kakaocdn.net/dn/byaIey/btsFywStXq5/GQQ65l5Bcu0WOLzSZj9xcK/img.png"
/>

요청 메시지는 다음과 같다.

이미지 로딩에는 문제가 없다.

서버 응답의 “Access-Control-Allow-Origin” 값에 따라서 처리되거나 위처럼 에러 메시지가 표시된다. 예를 들어 crossOrigin이 “anonymouse”로 설절된 경우 “Access-Control-Allow-Origin”가 없거나 현재 도메인과 다른 경우에는 에러가 발생한다. “Access-Control-Allow-Origin”이 “*”으로 모두 허용된 경우에만 접근 가능하다.

그럼 crossOrigin을 설정하지 않은 경우에는 “Access-Control-Allow-Origin”이 없어도 접근할 수 있다. 단 이미지를 canvas로 후속 처리하는 경우에는 아래와 같은 예외가 발생하면서 처리할 수 없다.

만약 요청에 대해 응답 메시지에 “Access-Control-Allow-Origin”가 있을 경우가 있다.

또는 아래와 같이 특정 도메인이 지정될 수도 있다.

“Access-Control-Allow-Origin”가 만약 “*”으로 되어있는 경우 crossOrigin이 “anonymous”으로 접근할 수 있다. 물론 도메인이 있는 경우는 해당 도메인 요청만 허용된다.

  • The canvas has been tainted by cross-origin data.

자바스크립트로 이미지를 처리하는 경우를 살펴보자. 대부분 아래와 비슷하다.

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

let img = new Image();
img.onload = function() {
  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  // 중략
}
img.crossOrigin = "anonymous";
img.src = "https://blog.kakaocdn.net/dn/byaIey/btsFywStXq5/GQQ65l5Bcu0WOLzSZj9xcK/img.png";

crossOrigin이 “anonymous”인 경우이기 때문에 “Access-Control-Allow-Origin”이 “*”인 경우만 접근할 수 있다. 만약 “Access-Control-Allow-Origin”이 없다면 예외가 발생한다.

그래서 crossOrigin을 없애고 호출하면 “Access-Control-Allow-Origin”에 상관없이 가져올 수 있어서 호출했다면 다음과 같은 DOMException 예외가 발생한다.

즉, CORS로 인해서 이미지 화면 표시는 가능하지만 이미지 데이터를 액세스하는 작업은 안된다. 결국 “Access-Control-Allow-Origin”없는 이미지는 화면 표기까지는 가능하지만, 재가공해서 후처리할 경우는 불가능하다. 이럴 경우는 서버에서 CORS 설정하거나 CORS 을 지원하는 서버로 변경해야한다.

결론

작성했던 글에서 이슈가 있어서 이를 해결하면서 조금 당황했다. 물론 이전에 발생했는데 그동안 Chrome의 정책 변경을 알지 못했기에 이슈가 있었는지도 알 수 없다. 임시로 실시간 변경하는 이미지를 사용했었지만 지금은 이미지를 업로드해서 직접 사용하도록 수정했다. Chrome 보안 관련 정책에 대해서 잘 살펴봐야겠다라는 생각이 들었다. 즉, 지금 당장 문제가 없다고 무시하지 말고 어떤 이슈와 문제가 발생할지 미리 대비하고 준비해야된다는 뜻이다.

참고

[1] HTML attribute: crossorigin, https://developer.mozilla.org/ko/docs/Web/HTML/Attributes/crossorigin

[2] Nathan Vaughn, How To Fix “The Canvas Has Been Tainted By Cross-Origin Data” Errors, https://inspirnathan.com/posts/105-fix-tainted-canvas-from-cross-origin-error

[3] 교차 출처 리소스 공유(CORS), https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

반응형