Translate

[HTML][Javascript] 브라우저에서 이미지로딩 및 링크(link) 이동 시 리퍼러(referer) 넘기지 않는 방법



referer 를 빼고 서버에 요청을 보내는 방법은 몇가지가 있다.



언어 종류별로 방법은 조금씩 차이가 있지만

서버에서 사용하는 방법은 다음과 같은 방법이 있다.

1. 서버에서 HTTP요청(TCP)을 보낼 때 Header 정보를 수정하여 referrer 정보를 수정하거나 공백으로 보내는 방법

2. 서버에서 시스템의 curl 명령어를 이용하여 웹서버에 Request 후 Response 를 받는 방법



클라이언트에서 사용하는 방법은 다음과 같은 방법이 있다.

1. 브라우저에서 요청을 보낼 시 패킷을 캡쳐 후 변조하여 서버에 보내는 방법




하지만 서버에서 프로그램으로 구현을 해야 하거나 사용자가 툴 사용법을 익혀서 작업을 해야 하는 불편함이 있다.



ReferrerKiller(링크) 라는 페이지를 보고 링크를 눌러서 웹페이지 이동을 하면서 꼼수를 쓰지 않고 referer를 보내지 않는 방법을 알게되었다.


참 아이디어가 참신하고 대단하다는 생각이 들었다.
iframe 의 src 내부에 html 소스를 넣을 생각을 하다니..


ReferrerKiller 의 데모페이지의 소스는 아래와 같다.

<!doctype html>
<html>
 <header>
  <meta charset="utf-8" />
  <title>ReferrerKiller demo</title>
  <script src="ReferrerKiller.js"></script>
 </header>
 <body>
  <h1>Demonstration of how to prevent your browser of sending the referrer http header.</h1>
  <h3>Check the hack's source code <a href="ReferrerKiller.js">here</a>.</h3>
  <h2>Links</h2>
  <ul>
   <li>Not sending referrer <span id="url_kill_referrer"></span></li>
   <li>Sending referrer <a href="http://www.xhaus.com/headers" target="destiny">http://www.xhaus.com/headers</a></li>
  </ul>
  <iframe name="destiny" width="100%" height="460" src="about:blank"></iframe>
  <script>
   document.getElementById('url_kill_referrer').innerHTML = ReferrerKiller.linkHtml( 'http://www.xhaus.com/headers', 'http://www.xhaus.com/headers', { target: 'destiny' }, { verticalAlign: 'bottom' } );
  </script>
  <h2>Image uploaded to pixhost</h2>
  <ul>
   <li>Without sending referrer: <br/> <span id="image_kill_referrer"></span></li>
   <li>Sending referrer: <br/> <img src="http://img4.pixhost.org/images/1693/14341576_a_fun.jpg" /></li>
  </ul>
  <script>
   document.getElementById('image_kill_referrer').innerHTML = ReferrerKiller.imageHtml('http://img3.pixhost.org/images/2669/14341603_a_fun.jpg');
  </script>
 </body>
</html>


ReferrerKiller 라이브러리를 사용하는 방법은 너무나도 쉽다.
데모페이지를 보면 두가지 사용방법이 나온다.


1. ReferrerKiller.linkHtml(url, innerHTML, anchorParams, iframeAttributes)
2. ReferrerKiller.imageHtml(url, imgAttributesParam)





둘다 iframe 태그를 리턴하며 비어있는 iframe 내부에서 해당 URL을 호출하기 때문에 실질적으로 referer 가 없게된다.

때문에 URL을 바로 호출하던.. 아니면 링크를 누르던 스크립트를 통해 referer가 없는 페이지의 구현이 가능하다.


나중에 링크가 안될 수 있는 것을 염려하여 소스를 살짜쿵 퍼왔다.
소스의 주소는 다음과 같다.
http://referrer-killer.googlecode.com/git/ReferrerKiller.js

/**
 * @Project: ReferrerKiller.
 * @Licence: The MIT License.
 * @Author: Juan Pablo Guereca.
 * @Description: Crossbrowser referrer killing solution.
 *   It's a hack that prevents the browser of sending the http referrer in the following cases:
 *    - Link: You can have a link in your website being sure that the destiny won't know about your site.
 *    - Image: You can display an image from another site being sure the other site won't know your website is displaying it.
 *  Other interesting use is displaying an image without blocking the rest of the content, this way in case the image fails
 * it allows the rest of the page to load normally.
 *   Uses:
 *    - Load static content in parallel.
 *    - Provide privacy to your web users.
 *    - Saving bandwidth, considering you safe the extra bytes of the http referrer.
 *   Abuses:
 *    - Stilling bandwidth, using some other site contents (hotlinking, http://en.wikipedia.org/wiki/Inline_linking).
 * @Compatibility:
 *   It's been tested successfully on:
 *    - Chrome 24.
 *    - Firefox 15.
 *    - Safari 6.
 *    - Opera 12: it sends the referrer in the case of anchors if the target is an iframe, not if it opens in other window
 *     or the same one, for images it never sends the referrer even without using the hack.
 *    - IE 6, 7, 8.
 *    - IE 9: it works for images but not links, that's why in that oogle's url redirection is used for this browser, in this case
 *      there is an intermediate page.
 * @Interface:
 *   - ReferrerKiller.linkHtml(url, [innerHtml], [anchorParams], [iframeAttributes]). Returns a string.
 *   - ReferrerKiller.linkNode(url, [innerHtml], [anchorParams], [iframeAttributes]). Returns an Html Node.
 *   - ReferrerKiller.imageHtml(url, [imgParams], [iframeAttributes]). Returns a string.
 *   - ReferrerKiller.imageNode(url, [imgParams], [iframeAttributes]). Returns an Html Node.
 */

/**
 * @module ReferrerKiller
 */
var ReferrerKiller = (function () {
 var URL_REDIRECTION = "https://www.google.com/url?q=", // You can use another service if you use https protocol no referrer will be sent.
  PUB = {},
  IE_GT_8 = (function () {
    /*- Detecting if it's IE greater than 8 -*/
    var trident,
     match = navigator.userAgent.match(/Trident\/(\d)+/);
    if (null === match) {
     return false;
    }
    trident = parseInt(match[1], 10);
    if (isNaN(trident)) {
     return false;
    }
    return trident > 4;
  })();

 /**
  * Escapes double quotes in a string.
  *
  * @private
  * @param {string} str
  * @return {string}
  */
 function escapeDoubleQuotes(str) {
  return str.split('"').join('\\"');
 }
 
 /**
  * Given a html string returns an html node.
  *
  * @private
  * @param {string} html
  * @return {Node}
  */
 function htmlToNode(html) {
  var container = document.createElement('div');
  container.innerHTML = html;
  return container.firstChild;
 }
 
 /**
  * Converts object to html attributes string.
  *
  * @private
  * @param {object} obj
  * @return {string}
  */
 function objectToHtmlAttributes(obj) {
  var attributes = [],
   value;
  for (var name in obj) {
   value = obj[name];
   attributes.push(name + '="' + escapeDoubleQuotes(value) + '"');
  }
  return attributes.join(' ');
 }

 /**
  * It applies the hack to kill the referrer to some html.
  *
  * @public
  * @param {string} html.
  * @param {object} [iframeAttributes]
  * @return {string} html.
  */
 function htmlString(html, iframeAttributes) {
  var iframeAttributes  = iframeAttributes || {},
   defaultStyles = 'border:none; overflow:hidden; ',
   id;
  /*-- Setting default styles and letting the option to add more or overwrite them --*/
  if ('style' in iframeAttributes) {
   iframeAttributes.style =  defaultStyles + iframeAttributes.style;
  } else {
   iframeAttributes.style = defaultStyles;
  }
  id = '__referrer_killer_' + (new Date).getTime() + Math.floor(Math.random()*9999);
  /*-- Returning html with the hack wrapper --*/
  return '<iframe \
    style="border 1px solid #ff0000" \
    scrolling="no" \
    frameborder="no" \
    allowtransparency="true" ' +
   /*-- Adding style attribute --*/
   objectToHtmlAttributes( iframeAttributes ) +
   'id="' + id + '" ' +
   ' src="javascript:\'\
   <!doctype html>\
   <html>\
   <head>\
   <meta charset=\\\'utf-8\\\'>\
   <style>*{margin:0;padding:0;border:0;}</style>\
   </head>' +
   /*-- Function to adapt iframe's size to content's size --*/
   '<script>\
     function resizeWindow() {\
     var elems  = document.getElementsByTagName(\\\'*\\\'),\
      width  = 0,\
      height = 0,\
      first  = document.body.firstChild,\
      elem;\
     if (first.offsetHeight && first.offsetWidth) {\
      width = first.offsetWidth;\
      height = first.offsetHeight;\
     } else {\
      for (var i in elems) {\
           elem = elems[i];\
           if (!elem.offsetWidth) {\
            continue;\
           }\
           width  = Math.max(elem.offsetWidth, width);\
           height = Math.max(elem.offsetHeight, height);\
      }\
     }\
     var ifr = parent.document.getElementById(\\\'' + id + '\\\');\
     ifr.height = height;\
     ifr.width  = width;\
    }\
   </script>' +
   '<body onload=\\\'resizeWindow()\\\'>\' + decodeURIComponent(\'' +
   /*-- Content --*/
   encodeURIComponent(html) +
  '\') +\'</body></html>\'"></iframe>';
 }

 /*-- Public interface --*/

 /**
  * It creates a link without referrer.
  *
  * @public
  * @param {string} url
  * @param {string} innerHTML
  * @param {object} [anchorParams]
  * @param {object} [iframeAttributes]
  * @return {string} html
  */
 function linkHtml(url, innerHTML, anchorParams, iframeAttributes) {
  var html,
   urlRedirection = '';
  innerHTML = innerHTML || false;
  /*-- If there is no innerHTML use the url as innerHTML --*/
  if (!innerHTML) {
   innerHTML = url;
  }
  anchorParams = anchorParams || {};
  /*-- Making sure there is a target attribute and the value isn't '_self' --*/
  if (!('target' in anchorParams) || '_self' === anchorParams.target) {
   /*-- Converting _self to _top else it would open in the iframe container --*/
   anchorParams.target = '_top';
  }
  if (IE_GT_8) {
   urlRedirection = URL_REDIRECTION;
  }
  html = '<a rel="noreferrer" href="' + urlRedirection + escapeDoubleQuotes(url) + '" ' + objectToHtmlAttributes(anchorParams) + '>' + innerHTML + '</a>';
  return htmlString(html, iframeAttributes);
 }
 PUB.linkHtml = linkHtml;
 
 /**
  * It creates a link without referrer.
  *
  * @public
  * @param {String} url
  * @param {String} innerHTML
  * @param {Object} [anchorParams]
  * @param {object} [iframeAttributes]
  * @return {Node}
  */
 function linkNode(url, innerHTML, anchorParams, iframeAttributes) {
  return htmlToNode(linkHtml(url, innerHTML, anchorParams, iframeAttributes));
 }
 PUB.linkNode = linkNode;
 
 /**
  * It displays an image without sending the referrer.
  *
  * @public
  * @param {String} url
  * @param {Object} [imgAttributesParam]
  * @return {String} html
  */
 function imageHtml(url, imgAttributesParam) {
  var imgAttributes = imgAttributesParam || {},
  /*-- Making sure this styles are applyed in the image but let the possibility to overwrite them --*/
   defaultStyles = 'border:none; margin: 0; padding: 0';
  if ('style' in imgAttributes) {
   imgAttributes.style = defaultStyles + imgAttributes.style;
  } else {
   imgAttributes.style = defaultStyles;
  }
  return htmlString('<img src="' + escapeDoubleQuotes(url) + '" ' + objectToHtmlAttributes(imgAttributes) + '/>');
 }
 PUB.imageHtml = imageHtml;
 
 /**
  * It displays an image without sending the referrer.
  *
  * @public
  * @param {string} url
  * @param {object} [imgParams]
  * @return {Node}
  */
 function imageNode(url, imgParams) {
  return htmlToNode(imageHtml(url, imgParams));
 }
 PUB.imageNode = imageNode;

 /*-- Exposing the module interface --*/
 return PUB;
})();





댓글