LoginSignup
12
12

X-Frame-Options: DENY/SAMEORIGINでも iframe で表示する回避策

Last updated at Posted at 2021-01-02

Overview

標題の通り、X-Frame-Options: DENY or SAMEORIGIN でも iframe で表示する JS module を使ってみたのでメモ。

※ 記事内の herokuapp は現在稼働しておりません

X-Frame-Bypass

これを使えばできる(すべてのページが表示できるわけではありません)。

Note that:

  • すべてのページが表示できるわけではありません。
    • 例えば CAPTCHA が入ってたりするとダメです。
    • 踏み台にしている proxy から html を取得してこれないとダメみたいです。

How to use?

使い方は README に書いてある通りとてもシンプル。

JS module を読み込んで iframe タグに is="x-frame-bypass" を付けるだけ。

Try

X-Frame-Options: DENY / SAMEORIGIN を返す Heroku 上のサーバで試してみる。

以下の2つの html でブラウザ表示、およびコンソールログを確認する。

※ 上記 herokuapp は現在稼働しておりません

1.通常の iframe で書いた html

iframe_normal.html
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Normal iframe</title>
    <link rel="stylesheet" href="index.css">
  </head>
  <body>
    <div class="main">
      <iframe id="main-frame" frameborder="no"
        src="https://bypass-test-001.herokuapp.com/same">
      </iframe>
    </div>
  </body>
</html>

2.iframe w/ X-Frame-Bypass で書いた html

iframe_baypass.html
<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>iframe with x-frame-bypass</title>
    <link rel="stylesheet" href="index.css">
    <script type="module" src="https://unpkg.com/x-frame-bypass"></script>
  </head>
  <body>
    <div class="main">
      <iframe id="main-frame" frameborder="no" is="x-frame-bypass"
        src="https://bypass-test-001.herokuapp.com/same">
      </iframe>
    </div>
  </body>
</html>

X-Frame-Options: DENY

まずは X-Frame-Options ヘッダを確認

DENY になっている

$ curl -D - -s https://bypass-test-001.herokuapp.com/deny
HTTP/1.1 200 OK
Server: Cowboy
Date: Fri, 01 Jan 2021 09:09:04 GMT
Connection: keep-alive
X-Frame-Options: DENY
Content-Length: 93
Content-Type: text/html; charset=utf-8
Via: 1.1 vegur


    <pre>
    X-Frame-Options': 'DENY'
    Do not show this page via iframe.
    </pre>

結果: 通常の iframe で書いた html

ブラウザ

result_deny_normal.png

コンソールログ

"Refused to display 'https://bypass-test-001.herokuapp.com/deny' in a frame because it set 'X-Frame-Options' to 'deny'."

log_deny_normal.png

結果: iframe w/ X-Frame-Bypass で書いた html

ブラウザ

表示できた。

result_deny_bypass.png

コンソールログ

X-Frame-Bypass が動いているのがわかります。

エラーは出ますが中でゴニョゴニョやっているんでしょう。最終的に表示できました。

log_deny_bypass.png

X-Frame-Options: SAMEORIGIN

次は X-Frame-Options: SAMEORIGIN で試してみる。

ヘッダを確認

$ curl -D - -s https://bypass-test-001.herokuapp.com/same
HTTP/1.1 200 OK
Server: Cowboy
Date: Fri, 01 Jan 2021 09:09:10 GMT
Connection: keep-alive
X-Frame-Options: SAMEORIGIN
Content-Length: 119
Content-Type: text/html; charset=utf-8
Via: 1.1 vegur


    <pre>
    X-Frame-Options': 'SAMEORIGIN'
    Do not show this page via iframe without same-origin.
    </pre>

結果: 通常の iframe で書いた html

ブラウザの表示結果は DENY の場合と同じなので省略します。

コンソールログ

"Refused to display 'https://bypass-test-001.herokuapp.com/same' in a frame because it set 'X-Frame-Options' to 'sameorigin'."

log_sameorigin_normal.png

結果: iframe w/ X-Frame-Bypass で書いた html

ブラウザ

こちらも表示できますね。

result_sameorigin_bypass.png

コンソールログ

log_sameorigin_bypass.png

補足1: Vue で使う場合

これが何気に苦労しました。npm でパッケージ化されているのですが、どう書いたら動くのかわからず、、

結局 vue-head で module を読み込んで使うことにしました。

無理やり感のあるコードですが、参考まで。

IframeTest.vue
<template>
  <div class="iframe-test">
    <div class="test-frame">
    </div>
  </div>
</template>

<script>
export default {
  name: 'IframeTest',
  data () {
    return {
      iframeId: 'test-frame-id'
    }
  },
  head: {
    script: [
      {
        type: 'module',
        src: 'https://unpkg.com/x-frame-bypass'
      }
    ]
  },
  created: async function () {
    if (document.getElementById(this.iframeId)) {
      const iframe = document.getElementById(this.iframeId)
      iframe.remove()
    }
    const div = await document.getElementsByClassName('test-frame')
    div[0].insertAdjacentHTML(
      'afterbegin', this.getFrameHtml())
    await this.$nextTick()
  },
  methods: {
    getFrameHtml: function () {
      return `
        <iframe
          id="test-frame-id"
          frameborder="no"
          is="x-frame-bypass"
          src="https://bypass-test-001.herokuapp.com/deny">
        </iframe>`
    }
  }
}
</script>

<style scoped>
</style>

補足2: 少しだけモジュールの中身を確認

この API を使っている模様(他にも2つ proxy がある)。

This API enables cross-origin requests to anywhere.

Usage:

/               Shows help
/iscorsneeded   This is the only resource on this host which is served without CORS headers.
/<url>          Create a request to <url>, and includes CORS headers in the response.

If the protocol is omitted, it defaults to http (https if port 443 is specified).

Cookies are disabled and stripped from requests.

Redirects are automatically followed. For debugging purposes, each followed redirect results
in the addition of a X-CORS-Redirect-n header, where n starts at 1. These headers are not
accessible by the XMLHttpRequest API.
After 5 redirects, redirects are not followed any more. The redirect response is sent back
to the browser, which can choose to follow the redirect (handled automatically by the browser).

The requested URL is available in the X-Request-URL response header.
The final URL, after following all redirects, is available in the X-Final-URL response header.


To prevent the use of the proxy for casual browsing, the API requires either the Origin
or the X-Requested-With header to be set. To avoid unnecessary preflight (OPTIONS) requests,
it's recommended to not manually set these headers in your code.


Demo          :   https://robwu.nl/cors-anywhere.html
Source code   :   https://github.com/Rob--W/cors-anywhere/
Documentation :   https://github.com/Rob--W/cors-anywhere/#documentation

こいつで iframe src に指定した URL の html を取ってこれれば表示できるんですね。多分。

おわり。

12
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
12