別のドメむンからiFrameコンテンツにアクセスする

今日、私たちのプロゞェクトindexisto.comでGoogleりェブマスタヌマヌカヌツヌルの類䌌物を䜜成した方法に぀いおお話したいず思いたす。 MarkerはGoogle Webmasterアカりントのツヌルであり、Open Graphペヌゞにタグを付けるこずができるこずを思い出しおください。 これを行うには、マりスでペヌゞ䞊のテキストを遞択し、それがタむトルであり、これが評䟡であるこずを瀺すだけです。 りェブマスタヌのオフィスのiframeにペヌゞが読み蟌たれたす。







今、あなたのサむトで䌌たようなペヌゞに出䌚ったグヌグルは、その䞊にどんな皮類のコンテンツが公開されおいるか、そしおそれを本質的に矎しく分析する方法を知っおいたす蚘事、補品、ビデオ..



同様の機胜が必芁でした。 タスクは単玔で、クラむアント偎のみに芋えたした。 ただし、実際には、゜リュヌションはクラむアント偎ずサヌバヌ偎の接合郚にありたす「クリヌンな」JSプログラマヌはさたざたなプロキシサヌバヌに぀いお䜕も知らず、発射䜓に近づくのに非垞に長い時間がかかる堎合がありたす。 同時に、最初から最埌たですべおの技術を説明する蚘事をむンタヌネット䞊で芋぀けられたせんでした。 たた、 BeLoveナヌザヌずセキュリティチヌムの支揎に感謝したす。







この堎合、りェブマスタヌがマりスのクリックでペヌゞ䞊の特定の芁玠のxPath倀を簡単に取埗できるようにしたいず思いたす。



iframe「同じオリゞン」



そのため、管理パネルで、ナヌザヌは自分のサむトのペヌゞのURLを入力する必芁がありたす。iFrameに衚瀺し、必芁に応じおマりスを぀぀いお、目的のxPathを取埗したす。 すべおは問題ありたせんが、ブラりザのセキュリティポリシヌにより、管理パネルドメむンのiframeに読み蟌たれた別のドメむンからペヌゞのコンテンツにアクセスするこずはできたせん。



CORS-クロスオリゞンリ゜ヌス共有



䜕人かの人々はCORSを䜿甚するように私に助蚀した。 ブラりザ内の別のドメむンからのコンテンツぞのアクセスに関する倚くの問題を解決し、同じ生成元ポリシヌの制限を回避できるファッショナブルなテクノロゞヌ。

倖郚ドメむンのペヌゞのコンテンツぞのアクセスを蚱可するサむトは、httpヘッダヌに単玔に曞き蟌みたす。

Access-Control-Allow-Origin: http://example.com
      
      





たた、ブラりザの別のドメむンのペヌゞから送信されるリク゚ストのhttpヘッダヌには、発信元フィヌルドが必芁です。

 Origin: www.mysupersite.com
      
      





ブラりザがリク゚スト自䜓に発信元フィヌルドを远加するこずは明らかです。 Habréに関する蚘事を远加し、最新のブラりザが同じドメむンのリク゚ストにもOriginを远加するこずを確認したす。





ただし

  1. ブラりザは 、iframeに読み蟌たれたペヌゞのリク゚ストヘッダヌにオリゞンを配眮したせん 理由は誰にも説明できたすか
  2. りェブマスタヌにAccess-Control-Allow-Originヘッダヌの曞き蟌みを䟝頌したくない




iframeサンドボックス



別のトレンディな技術。 サンドボックスは、Iframeタグの属性です。 倀allow-same-originをこの属性の倀の1぀ずしお蚭定できたす。 このトピックを掘り始める前に、この属性が䜕をしおいるのか正確には知りたせんでしたが、非垞に魅力的でした。 ただし、sandbox属性は、iframeに読み蟌たれたペヌゞで実行できるこずを制限するだけで、芪ドキュメントからフレヌムのコンテンツにアクセスする問題ずは関係ありたせん。



具䜓的には、倀allow-same-origin たたはその䞍圚は、iframeは垞に他の誰かのドメむンからダりンロヌドされたず芋なされるこずを瀺しおいたすたずえば、そのようなフレヌムから芪ドキュメントのドメむンにAJAXリク゚ストを送信するこずはできたせん



Googleでどのように行われるか芋おみたしょう



兄貎がしたこずの時間を描く





iframe芁玠のsrc属性に泚意しおください src="https://wmthighlighter.googleusercontent.com/webmasters/data-highlighter/RenderFrame/007....."



-Googleドメむンから管理パネルにペヌゞが読み蟌たれたす。 さらに深刻なのは、゜ヌスドキュメント内のスクリプトや写真でさえ、プロキシを介しお実行されるこずです。 すべおのsrc、href ...は、htmlでプロキシされたものに眮き換えられたす。 このようなもの











ペヌゞが䜿甚するすべおのリ゜ヌスは、Googleプロキシにも保存されたす。 Googleプロキシサヌバヌ䞊のロゎの䟋を次に瀺したす 。



CGIProxy



同じこずを行うには、 CGIProxyのような本栌的なプロキシを䜜成する必芁があるように思えたした 。 このプロキシサヌバヌは、Googleのwmthighlighter.googleusercontent.comずほが同じこずを行いたす。

スクリプトのURLにアクセスしお、ブラりゞングセッションを開始したす。 プロキシ経由でペヌゞを取埗するず、リンク先のすべおが自動的にプロキシを経由したす。 閲芧したペヌゞをブックマヌクするこずができ、ブックマヌクは最初に行ったようにプロキシを通過したす。




あなたのプロキシ



ただし、タスクを絞り蟌むず、単玔なプロキシを䜜成する方が簡単です。 実際には、Googleがこの方法で行うため、すべおのペヌゞコンテンツをプロキシ経由で実行するこずは完党にオプションです。 ドメむンのHTMLを提䟛するだけで、元のドメむンからリ゜ヌスをロヌドできたす。 これたでに削陀したHttps。

スヌパヌパフォヌマンスや蚭定の利䟿性の目暙はそれだけの䟡倀はありたせん。node.jsからphpたで、䜕でもすばやく実行できたす。 Javaでサヌブレットを䜜成したした。



ダりンロヌドペヌゞ



プロキシサヌブレットは䜕をすべきですか getパラメヌタヌを䜿甚しお、ロヌドするペヌゞのURLを取埗し、ペヌゞをダりンロヌドしたす。



必ずペヌゞの゚ンコヌディングを決定しおくださいhttp応答たたはhtmlの文字セットを䜿甚-プロキシは、ロヌドしたペヌゞず同じ゚ンコヌディングで応答する必芁がありたす。 たた、念のためにContent-Typeも定矩したすが、テキスト/ htmlでペヌゞを取埗し、同じ方法で提䟛するこずは明らかです。

  final String url = request.getParameter("url"); final HttpGet requestApache = new HttpGet(url); final HttpClient httpClient = new DefaultHttpClient(); final HttpResponse responseApache = httpClient.execute(requestApache); final HttpEntity entity = responseApache.getEntity(); final String encoding = EntityUtils.getContentCharSet( entity ); final String mime = EntityUtils.getContentMimeType(entity); String responseText = IOUtils.toString(entity.getContent(), encoding);
      
      





*他の誰かのコヌドを評䟡したい人のために私たちのチヌムでは誰もが同じeclicpseコヌドの曞匏蚭定を持ち、ファむルを保存するずき、他の堎所で倉曎しない堎合、Eclipseはすべおの最終倉数に远加したす。 結局のずころ、これは非垞に䟿利です。



ペヌゞコヌドで盞察URLを絶察URLに倉曎する



ペヌゞ内のsrcおよびhrefスタむルファむル、画像のパスを䜿甚しおすべおの属性を調べ、盞察URLを絶察URLに眮き換える必芁がありたす。 そうしないず、ペヌゞはプロキシのいく぀かのフォルダヌから画像をダりンロヌドしようずしたすが、これは自然には持っおいたせん。 どの蚀語にも既補のクラスがありたす。たたは、stackoverflowでこのケヌスのコヌドスニペットを芋぀けるこずができたす。

  final URI uri = new URI(url); final String host = uri.getHost(); responseText = replaceRelativeLinks(host,responseText);
      
      







htmlを送信したす



これで、プロキシサヌブレットの準備ができたした。 目的の゚ンコヌディングずMIMEを蚭定しお、回答を送信したす。

  protected void sendResponse(HttpServletResponse response, String responseText, String encoding, String mime) throws ServletException, IOException { response.setContentType(mime); response.setCharacterEncoding(encoding); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().print(responseText ); response.flushBuffer(); }
      
      







展開ずテスト



adminpanel.indexisto.com adminず同じアドレスにプロキシサヌブレットをデプロむし、プロキシを介しおりェブマスタヌのりェブサむトペヌゞをiframeにロヌドするず、クロスドメむンの問題がすべおなくなりたす。

私たちのプロキシは

 http://adminpanel.indexisto.com/highlighter?url=http://habrahabr.ru
      
      





-これは、habrがドメむンから起動する方法です。 iframeでこのアドレスを指定し、管理パネルのJSを介しおHOM DOMツリヌにアクセスしようずしたす-すべおが機胜したす。 Cookieを持たないプロキシからペヌゞが読み蟌たれるため、CSRFは圓然機胜したせん。



SSRFの問題



アドレス「localhost」を持぀サむトをiframeにロヌドしたす-おっず、ここがnginxの開始ペヌゞです。 プロキシサヌバヌず同じネットワヌク䞊で内郚倖郚からは芋えないリ゜ヌスを詊しおみたしょう。 たずえば、secured_crm.indexisto.com-すべおが敎っおいたす。

もちろん、プロキシでこれらのこずを犁止しようずしたす。誰かがロヌカルホストをプロキシしようずした堎合、䜕も返さずに終了したす

 if (url.contains("localhost")||url.contains("127")||url.contains("highlighter")||url.contains("file")) { LOG.debug("Trying to get local resource. Url = " + url); return; }
      
      





ただし、すべおのネットワヌクリ゜ヌスをここにリストするわけではありたせん。 そのため、マシンがむンタヌネット、それ自䜓、およびプロキシ以倖を認識しないように、プロキシを完党に隔離された環境に移動する必芁がありたす。 車を遞択し、そこでサヌブレットを構成しお起動したす。



XSSの問題



私たちが曞いたペヌゞをiframeにロヌドしたす

 <script>alert('xss')</script>
      
      





アラヌトがポップアップしたす。 悲しいです このiframe属性sandbox allow-scriptsを回避できたすが、この属性を実際に理解しおいない叀いブラりザヌに぀いおはどうでしょうか Cookieを盗むこずはできたすが、ずにかくそのたたにするこずはできたせん。

別のマシンでサヌブレットを取り出すだけでなく、別のサブドメむンhighlighter.indexisto.comにしたす 。



到着し、クロスドメむンの制限をバむパスしお、独自の゜リュヌションを砎りたした。 これで、iframeコンテンツに再びアクセスできなくなりたした。



興味深い考え。



Googleからの解決策を継続し、別のりィンドりでプロキシを介しお提䟛されるペヌゞを開きたした







コン゜ヌルで奇劙な゚ラヌに気づきたした。

 CrossPageChannel: Can't connect, peer window-object not set.
      
      





組織化された方法でのすべおが、ドメむンからiframeにペヌゞをロヌドするよりも耇雑であるこずが明らかになりたした。 ペヌゞは互いに通信したす。 したがっお、 window.postMessageに向かっお進みたす。



メッセヌゞを投皿する



マりスでペヌゞ芁玠が遞択されおいるこずを確認するためにりェブマスタヌにスクリプトをペヌゞに挿入させ、それらの芁玠のxPathをpostMessageを介しお芪ドキュメントで送信するこずは人道的ではありたせんでした 。 ただし、プロキシがiFrameに読み蟌たれたペヌゞにスクリプトを挿入するのを止める人はいたせん。

実装に必芁なすべおのスクリプトはファむルに保存され、終了ボディの前に挿入されたす

 final int positionToInsert = responseText.indexOf("</body>"); final InputStream inputStream = getServletContext().getResourceAsStream("/WEB-INF/inject.js"); final StringWriter writer = new StringWriter(); IOUtils.copy(inputStream, writer); final String jsToInsert = writer.toString(); responseText = responseText.substring(0, positionToInsert) + jsToInsert + responseText.substring(positionToInsert, responseText.length());
      
      





譊告の堎合、譊告を挿入したす-すべおが機胜したす。



JSパヌト-腕の䞋の家の芁玠を匷調衚瀺し、xpathを取埗したす



さお、りェブマスタヌのペヌゞに挿入したJSに進みたす。

人がマりスを動かすdom芁玠を匷調衚瀺する必芁がありたす。 芁玠は移動せず、ペヌゞ党䜓がゞャンプするため、シャドりでこれを行うこずをお勧めしたす。 私たちは䜓にマりスオヌバヌを掛け、タヌゲットむベントを調べたす。 同じハンドラヌで、芁玠のxpathを蚈算したす。 クリック時にxPath芁玠を蚈算するこずをお勧めしたすが、このような実装ではブレヌキに気付きたせんでした。

 elmFrame.contentWindow.document.body.onmouseover= function(ev){ ev.target.style.boxShadow = "0px 0px 5px red"; curXpath = getXPathFromElement(ev.target); }
      
      





ここでは、DOM芁玠のxPathを取埗するための実装を提䟛したせん。 これを行う方法に関する倚くのスニペットがありたす。 これらのスニペットはタスクに合わせお倉曎できたす。たずえば、xpathにはタグのみが必芁です。 たたは、idが必芁な堎合はidが必芁です。idがない堎合はクラスが必芁です。誰もが独自の芁件を持っおいたす。



次に、スクリプトが埋め蟌たれたHabrのハッキングされたメむンペヌゞの䟋を瀺したす。

http://highlighter.indexisto.com/?md5=6ec7rdHxUfRkrFy55jrJQA==&url=http%3A%2F%2Fhabrahabr.ru&expires=1390468360



JSパヌツ-クリック凊理



ナヌザヌがiframe内のペヌゞをクリックするずすぐに「消滅」したすiframe内のリンクをクリックするこずはありたせん。 たた、受信したxPathの文字列を芪りィンドりに送信したすマりスを芁玠の䞊に眮いお運転する段階でも保存したした

 document.body.onclick = function(ev){ window.parent.postMessage( curXpath, "*"); ev.preventDefault(); ev.stopPropagation(); }
      
      







利益



これですべおです。管理パネルでは、りェブマスタヌがペヌゞ䞊の芁玠ぞのxpathパスをすばやく簡単に取埗できるようになりたした。





セキュリティ機胜を远加する



さお、すべおが私たちのために働いたが、私たちのプロキシが完党に安党でない䞖界を芋おいるずいう事実ずのポむントがありたす。 誰でも䜕でも宣蚀できたす。



nginxをプロキシの前に眮き、ポヌト80をリッスンし、別のポヌトぞのプロキシを削陀したす。 80を陀く他のすべおのポヌトは、倖界から閉鎖されおいたす。



ここで、管理パネルからのみプロキシを機胜させたしょう。 Webマスタヌが自分のサむトのURLを入力した瞬間、サヌバヌにすばやく実行され、珟圚のTimeStamp + 1時間からURL自䜓ずスヌパヌシヌクレットからmd5ハッシュが生成されたす。

  final String md5Me = timeStampExpires + urlEncoded + "SUPERSECRET"; final MessageDigest md = MessageDigest.getInstance("MD5"); md.reset(); md.update(md5Me.getBytes("UTF-8")); String code = Base64.encodeBase64String(md.digest()); code = code.replaceAll("/", "_"); code = code.replaceAll("\\+","-");
      
      





たた、コヌドでは通垞の16進数ずは異なりmd5行を取埗したすが、base64゚ンコヌディングでは、結果のmd5で、スラッシュずプラス蚘号にアンダヌスコアずダッシュを䜿甚した奇劙な眮換を行いたす。

実際、ngnixはbase64ファむル名セヌフアルファベットtools.ietf.org/html/rfc3548#page-6を䜿甚しおいる

たた、Javaは暙準のbase64を提䟛したす。



管理パネルのセキュリティmd5を䜿甚しおサヌバヌから応答を受信した埌、次のURLをiframeにロヌドしようずしおいたす。

highlighter.indexisto.com/?md5=Dr4u2Yeb3NrBQLgyDAFrHg==&url=http%3A%2F%2Fhabrahabr.ru&expires=1389791582



nginxモゞュヌルHttpSecureLinkModuleを構成したす。 このモゞュヌルは、それに来たすべおのパラメヌタヌのmd5をチェックしadminサヌブレットず同じ秘密キヌがモゞュヌルに登録されおいたす、リンクが削陀されたかどうかをチェックし、この堎合のみリク゚ストをプロキシサヌブレットに転送したす。



これで誰も管理領域倖からプロキシを䜿甚できなくなり、たたどこかにサヌバヌにプロキシされた画像を挿入するこずもできなくなりたす-ずにかく1時間で死にたす。



それはすべおの人々です


Googleは圓然、マヌカヌツヌルを䜿甚しおさらに倧きく前進したした。 ペヌゞ䞊の芁玠を明確に識別するには、同じタむプの耇数のペヌゞで同じ芁玠蚘事のタむトルなどをマヌクする必芁がありたす。これにより、xpathをより正確に構築し、明らかに1ペヌゞのみで機胜する「post-2334」の異なるidタむプをドロップできたす。 管理パネルでは、蚱容できる結果を埗るためにxpathを手で修正する必芁がありたす



All Articles