지난 편에서 모두에게 웹을 여는 접근성을 다뤘습니다. 이번에는 외부의 콘텐츠를 우리 페이지 안에 끼워 넣는 방법과, 거기에 따르는 위험을 살펴봅니다. 다른 곳에 있는 영상이나 지도, 결제 창, 위젯 같은 것을 우리 페이지 안에 창처럼 띄워 보여 주는 일이 흔합니다. 이 끼워 넣기는 강력하지만, 남의 콘텐츠를 우리 페이지에 들이는 만큼 신중하게 다루지 않으면 보안 구멍이 됩니다.
제가 이 끼워 넣기의 위험을 처음 실감한 것은, 외부 위젯을 무심코 페이지에 넣었다가 그 위젯이 우리 페이지의 정보에 접근하려는 것을 발견했을 때였습니다. 편하게 쓰려고 넣은 것이 자칫 사용자의 정보를 위험에 빠뜨릴 뻔한 것이죠. 그날 이후 저는 외부 콘텐츠를 넣을 때 반드시 안전 장치를 함께 채우게 되었습니다. 이번 편에서 그 장치들을 정리하겠습니다.
1. 끼워 넣기란 무엇인가
다른 페이지를 우리 페이지 안에 창처럼 띄우는 전용 태그가 있습니다. 이 태그를 두고 그 안에 보여 줄 외부 주소를 지정하면, 그 주소의 페이지가 우리 페이지 안에 작은 창으로 나타납니다. 유튜브 영상을 페이지에 심거나, 지도를 넣거나, 외부 문서를 보여 줄 때 흔히 쓰는 방식입니다.
이 창 안의 페이지는 우리 페이지와는 별개로 독립적으로 동작합니다. 그 안에서 스크롤하고, 버튼을 누르고, 그 페이지 나름의 기능을 씁니다. 겉으로는 우리 페이지의 일부처럼 보이지만, 실제로는 우리가 통제하지 않는 남의 페이지가 창을 통해 들여다보이는 것입니다. 이 사실을 늘 의식해야 합니다.
이 방식의 편리함은 분명합니다. 복잡한 영상 재생기나 지도 기능을 우리가 직접 만들지 않고, 이미 잘 만들어진 외부 서비스를 그대로 가져다 쓸 수 있습니다. 몇 줄만으로 강력한 기능을 페이지에 얹을 수 있으니 개발 시간이 크게 절약됩니다.
하지만 편리함의 이면에 위험이 있습니다. 우리가 들이는 것은 남의 코드이고, 그 코드가 무슨 일을 하는지 우리는 완전히 알지 못합니다. 신뢰할 수 있는 서비스라면 괜찮지만, 출처가 불분명하거나 신뢰가 확실하지 않은 콘텐츠를 그냥 들이면 그 코드가 사용자에게 해를 끼칠 수 있습니다.
그래서 끼워 넣기를 다루는 핵심은 신뢰의 정도에 따라 권한을 조절하는 것입니다. 완전히 신뢰하는 서비스에는 필요한 기능을 허용하고, 신뢰가 확실하지 않은 콘텐츠에는 권한을 최소로 조여야 합니다. 이 조절을 가능하게 하는 안전 장치들이 이 태그에 마련되어 있습니다. 이제 그것들을 살펴보겠습니다.
정리하면 끼워 넣기는 남의 페이지를 우리 페이지 안에 창으로 띄우는 강력하지만 위험한 도구입니다. 편리함만 보고 무턱대고 쓰면 보안 구멍이 되므로, 신뢰의 정도에 맞춰 권한을 조절하는 것이 관건입니다.
2. 권한을 차단하고 최소만 허용하기
끼워 넣은 창에 걸 수 있는 가장 중요한 안전 장치가 권한 제한입니다. 이 장치는 창 안의 콘텐츠가 할 수 있는 일을 기본적으로 모두 차단한 뒤, 우리가 명시적으로 허락한 것만 되돌려주는 방식으로 동작합니다. 아무것도 못 하게 막아 놓고 필요한 것만 하나씩 풀어 주는 것이죠.
이 방식이 좋은 이유는 안전한 쪽으로 기본값이 잡혀 있기 때문입니다. 아무 설정 없이 이 장치를 걸면 창 안의 콘텐츠는 스크립트 실행도, 폼 제출도, 다른 곳으로 이동시키기도 할 수 없습니다. 그 상태에서 이 콘텐츠에 정말 필요한 기능이 무엇인지 따져 하나씩 허용하면, 딱 필요한 만큼만 권한을 주게 됩니다.
예를 들어 외부 위젯이 동작하려면 스크립트 실행이 필요하다면 그것만 허용하고, 새 창을 여는 기능이 필요하다면 그것을 추가로 허용하는 식입니다. 이렇게 필요한 것만 골라 허용하면, 그 콘텐츠가 우리가 허락하지 않은 위험한 일을 시도해도 막힙니다. 최소 권한의 원칙이 여기에 그대로 적용됩니다.
이 권한 제한을 걸지 않으면 창 안의 콘텐츠는 상당히 많은 일을 할 수 있습니다. 우리 페이지를 다른 곳으로 이동시키거나, 예상치 못한 창을 띄우거나, 사용자를 속이는 행동을 할 여지가 생깁니다. 그래서 신뢰가 확실하지 않은 콘텐츠에는 이 권한 제한을 반드시 거는 것이 안전합니다.
제가 실무에서 굳힌 습관은, 외부 콘텐츠를 넣을 때 일단 권한을 모두 차단한 상태에서 시작하는 것입니다. 그런 다음 그 콘텐츠가 제대로 동작하지 않으면, 무슨 권한이 필요한지 하나씩 확인하며 최소한으로 풀어 줍니다. 처음부터 다 열어 두고 위험한 것을 막는 것보다, 다 막고 필요한 것만 여는 편이 훨씬 안전했습니다.
아래는 권한을 차단하고 최소만 허용한 예시입니다. 스크립트와 새 창만 허용한 것을 보세요.
<iframe src="https://widget.example.com" title="외부 위젯"
sandbox="allow-scripts allow-popups"></iframe>
3. 위험한 조합 피하기
권한을 풀어 줄 때 특히 조심해야 할 위험한 조합이 있습니다. 창 안의 콘텐츠에 스크립트 실행을 허용하면서 동시에 그 콘텐츠를 우리와 같은 출처로 취급하도록 허용하는 조합입니다. 이 둘을 함께 허용하면, 그 콘텐츠가 스스로 자신에게 걸린 권한 제한을 풀어 버릴 수 있습니다. 안전 장치를 걸어 놓고 그 장치를 스스로 해제할 열쇠를 쥐여 주는 격입니다.
이것이 왜 위험한지 조금 더 풀어 보겠습니다. 같은 출처로 취급된다는 것은 그 콘텐츠가 우리 페이지와 같은 권한을 갖는다는 뜻에 가깝습니다. 거기에 스크립트 실행까지 허용하면, 그 콘텐츠는 자신에게 걸린 제한을 코드로 풀고, 원래라면 막혔어야 할 일들을 하게 됩니다. 결국 권한 제한을 건 것이 무의미해집니다.
그래서 이 두 권한을 동시에 여는 것은 사실상 안전 장치를 걸지 않은 것과 다름없습니다. 정말 신뢰하는 콘텐츠, 우리가 직접 통제하는 콘텐츠가 아니라면 이 조합은 피해야 합니다. 저는 외부 콘텐츠에 이 두 가지를 함께 허용하려는 코드를 볼 때마다 반드시 다시 검토합니다.
물론 우리가 완전히 통제하는 우리 자신의 콘텐츠를 창으로 띄우는 경우라면 이야기가 다릅니다. 그 콘텐츠가 무슨 일을 하는지 우리가 다 알고 있으니 위험이 없습니다. 위험한 것은 어디까지나 우리가 통제하지 못하는 남의 콘텐츠에 이 강한 권한 조합을 주는 경우입니다.
제가 이 위험한 조합을 배우기 전에는, 외부 콘텐츠가 잘 동작하지 않으면 권한을 이것저것 다 열어 문제를 해결하려 했습니다. 그러다 이 조합의 위험을 알고 나서는, 권한을 열 때 이 조합이 되지 않도록 각별히 살피게 되었습니다. 편하자고 다 열었다가 큰 구멍을 낼 뻔한 아찔한 순간들이 있었습니다.
정리하면 스크립트 실행과 같은 출처 취급을 함께 허용하는 것은 안전 장치를 무력화하는 위험한 조합입니다. 신뢰가 확실하지 않은 콘텐츠에는 이 조합을 절대 쓰지 말아야 합니다. 권한을 풀 때는 늘 이 조합이 되지 않는지 확인하는 습관이 필요합니다.
4. 기능 접근 제어하기
권한 제한과는 별개로, 창 안의 콘텐츠가 기기의 특정 기능에 접근하는 것을 제어하는 장치도 있습니다. 카메라, 마이크, 위치 정보, 전체 화면 같은 민감한 기능들에 대해, 이 창이 그것들을 쓸 수 있는지 없는지를 우리가 정할 수 있습니다. 기본적으로 이런 민감한 기능은 막혀 있고, 필요한 경우에만 허용합니다.
이 제어가 왜 필요할까요. 창 안의 콘텐츠가 우리 모르게 카메라나 마이크를 켜려 한다면 큰 문제입니다. 이 장치로 어떤 기능에 접근할 수 있는지를 명시적으로 정해 두면, 우리가 허락하지 않은 기능은 그 콘텐츠가 아예 쓸 수 없습니다. 사용자의 사생활을 지키는 중요한 방벽입니다.
예를 들어 화상 통화 위젯을 넣는다면 카메라와 마이크 접근을 허용해야 그 위젯이 동작합니다. 반면 단순히 정보를 보여 주기만 하는 위젯이라면 그런 기능을 허용할 이유가 없으므로 막아 둡니다. 콘텐츠의 성격에 맞게, 정말 필요한 기능만 열어 주는 것이 원칙입니다.
영상을 끼워 넣을 때는 전체 화면 기능을 허용하는 경우가 많습니다. 사용자가 영상을 전체 화면으로 크게 보고 싶어 하기 때문입니다. 이처럼 그 콘텐츠의 정상적인 사용에 필요한 기능은 열어 주되, 그 이상은 열지 않는 균형을 잡습니다. 무엇이 정상적인 사용에 필요한지를 판단하는 안목이 필요합니다.
제가 이 기능 제어를 챙기며 느낀 것은, 이것이 사용자에 대한 책임의 문제라는 점입니다. 우리 페이지에 들어온 사용자는 우리를 믿고 들어온 것인데, 우리가 부주의하게 외부 콘텐츠에 민감한 기능을 열어 주면 그 신뢰를 저버리는 셈입니다. 그래서 저는 민감한 기능은 정말 필요한 최소한만, 신뢰하는 콘텐츠에만 허용합니다.
아래는 영상 콘텐츠에 필요한 기능만 허용한 예시입니다. 전체 화면을 허용한 것을 보세요.
<iframe src="https://video.example.com/embed" title="소개 영상"
allow="fullscreen; picture-in-picture" loading="lazy"></iframe>
5. 성능과 접근성 마무리
끼워 넣기는 성능에도 영향을 줍니다. 창 안의 페이지는 그 자체로 하나의 페이지라, 로드될 때 상당한 자원을 씁니다. 페이지에 이런 창이 여럿 있고 모두 처음부터 로드되면, 페이지가 무거워지고 느려집니다. 특히 화면 밖에 있어 당장 보이지도 않는 창까지 미리 로드하는 것은 낭비입니다.
이를 해결하는 방법이 지연 로드입니다. 화면에 보이지 않는 창은 미리 로드하지 않고, 사용자가 스크롤해서 그 창이 화면에 가까워질 때 로드하도록 미루는 것입니다. 그러면 처음 페이지가 뜰 때의 부담이 크게 줄어 페이지가 빠르게 표시됩니다. 화면 아래쪽의 영상 임베드 같은 것에 특히 효과적입니다.
다만 첫 화면에 바로 보이는 중요한 창에는 지연 로드를 걸지 않는 편이 좋습니다. 사용자가 바로 볼 콘텐츠를 굳이 미뤄 로드하면 오히려 늦게 뜨기 때문입니다. 화면 밖의 것은 미루고, 화면 안의 중요한 것은 미루지 않는 구분이 필요합니다.
접근성도 잊으면 안 됩니다. 끼워 넣은 창에는 그것이 무엇인지 설명하는 이름을 붙여야 합니다. 이 이름이 없으면 화면 낭독 프로그램은 그냥 창이라고만 안내해, 사용자는 그 안에 무엇이 들었는지 알 수 없습니다. 소개 영상이라든가 위치 지도처럼 명확한 이름을 붙이면 사용자가 창의 내용을 짐작할 수 있습니다.
제가 실무에서 정착한 끼워 넣기 점검표는 이렇습니다. 신뢰가 확실하지 않으면 권한을 차단하고 최소만 허용했는가, 위험한 권한 조합을 피했는가, 민감한 기능은 필요한 것만 열었는가, 화면 밖 창은 지연 로드했는가, 그리고 창에 이름을 붙였는가입니다. 이 다섯 가지를 확인하면 끼워 넣기의 위험 대부분을 막을 수 있었습니다.
이번 편에서는 끼워 넣기의 개념, 권한 차단과 최소 허용, 위험한 조합 피하기, 기능 접근 제어, 그리고 성능과 접근성까지 살펴봤습니다. 다음 편에서는 문법 문자를 다루는 엔티티와 특수문자로 넘어가겠습니다. 외부의 것을 안전하게 들이는 법을 익혔으니, 이제 글자를 다루는 세밀한 기법을 배울 차례입니다.