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 上のサーバで試してみる。
-
https://bypass-test-001.herokuapp.com/deny
X-Frame-Options: DENY
-
https://bypass-test-001.herokuapp.com/same
X-Frame-Options: SAMEORIGIN
以下の2つの html でブラウザ表示、およびコンソールログを確認する。
※ 上記 herokuapp は現在稼働しておりません
1.通常の iframe で書いた 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
<!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
ブラウザ
コンソールログ
"Refused to display 'https://bypass-test-001.herokuapp.com/deny' in a frame because it set 'X-Frame-Options' to 'deny'."
結果: iframe w/ X-Frame-Bypass で書いた html
ブラウザ
表示できた。
コンソールログ
X-Frame-Bypass が動いているのがわかります。
エラーは出ますが中でゴニョゴニョやっているんでしょう。最終的に表示できました。
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'."
結果: iframe w/ X-Frame-Bypass で書いた html
ブラウザ
こちらも表示できますね。
コンソールログ
補足1: Vue で使う場合
これが何気に苦労しました。npm でパッケージ化されているのですが、どう書いたら動くのかわからず、、
結局 vue-head で module を読み込んで使うことにしました。
無理やり感のあるコードですが、参考まで。
<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 を取ってこれれば表示できるんですね。多分。
おわり。