aタグのrel属性!Tabnabbing回避からSEOまで
始め
aタグの存在はコーディング勉強始めたぐらいから知ってましたが、rel属性については最近初めて知りました。なんで今まで分からなかったんだろう…と思いましたので一回整理します。
1. Tabnabbing
1-1. aタグのtarget属性
ウェブサイトでハイパーリンクをクリックすると現在見てたタブで開くか、新しいタブで開くかのどちらかの場合が多いと思います。その動きの設定はにも記載されている通り、target
属性で指定できます。
aタグのtarget
属性(MDNのaタグドキュメントから)
- _self: 現在の閲覧コンテキストです。 (既定値)
- _blank: ふつうは新しいタブですが、新しいウィンドウを使用するようにブラウザーを設定できます。
この他にもありますが、よく使われているものはこの2つかと思いますので一旦2つだけ持ってきました。デフォルト値は_selfなのでtarget属性自体を設定しなかったら自動的にtarget="_self"
になります。
1-2. New Tabを通じた攻撃
いままで話したtarget="_self"
の隙間に潜り込むTabnabbingという攻撃について説明させていただきます。
例えば、luvmini.example.com
というサイトを見ているとしましょう。
そのサイトにはother.example.com
に飛べる外部リンクがあります。ユーザーはそのリンクをクリックし、other.example.com
を新しいタブで開きました。
ここから大事ですが、その新しく開いたother.example.com
タブにはwindow.opener
という属性が存在します。MDNドキュメントによると、window.opener
は現在のウィンドウを開いたウィンドウへの参照を返すやつのようです。つまり、新しく開いたタブから親タブ(既存のタブ)を参照できるということです。
これの何がまずいかと言うと、ユーザーが新しいタブを見てる間に誰かが悪意を持って既存のタブを操作できるという意味です。
例えの続きをしましょう。ユーザーがother.example.com
を見ている間に、悪い人がJSを用いて親タブluvmini.example.com
のlocationをluvmimi.example.com
というフィッシングサイトに変えました。見た目も前もって同じように作っといて、アドレスもほぼ同じなのでパット見違うサイトだと分からりにくいです。
そしてユーザーがother.example.com
を見終わった後に変更されたluvmimi.example.com
に戻ります。フィッシングサイトなので当たり前にログインされてない状態ですが、ユーザーは「あれ?ログアウトされちゃったんかな」と思ってIDとパスワードを入力します。
そしてフィッシングサイトのluvmimi.example.com
は、ユーザーが入力したIDとパスワードを悪い人のサーバーに送信して本当のサイトであるluvmini.example.com
にリダイレクトさせて逃げます。ユーザーは普通にログインしたと思うだけで、被害を自覚することも難しいです。
これがTabnabbingという情報を盗む攻撃です。2010年にセキュリティー専門家Aza Raskinがつけた名前ですから結構知以前からあったフィッシングのようですね。この手の攻撃はSNSなどのコミュニティやメールでよく起きます。
2. rel="noopener"
2-1. セキュリティーについて
Tabnabbingの危険を防ぐためにrel=noopener
属性が追加されました。rel=noopener
をつけると、新しいタブを既存タブと違う、別途スレッドで開くことができます。
これの何が良いかというと、別途スレッドで動くので新しいタブから既存タブを参照できなくなります。
メールボックスに溜まってECサイトからのプロモーションメールで試してみたら、window.opener
がnull
になってました(韓国のサイトで試したのでハングルが見えますね)。これだったらJSで操作しようとしてもUncaught TypeError
が発生するので安全だと思います。
aタグに関するMDNドキュメントのtarget
説明にもこのような注釈があります。
注: 新しいブラウザー (例えば Firefox 79 以降) では、 target="_blank" を <a> 要素に設定すると、暗黙に rel の動作を rel="noopener" と設定したのと同様になります。
Tabnabbingの攻撃を防ぐためにこのようなバージョンアップをしたのが分かります。
2-2. パフォーマンスについて
また、noopener
はパフォーマンス的にも利点があります。
元々は新しいタブと既存タブが同じスレッドで動くので、新しいタブで開いたサイトがものすごく重かったら既存タブまで遅くなります。
しかし、別途スレッドだったら新しいタブのサイトがどれだけ重くても既存タブには影響がないので、既存タブが遅くなる心配がないです。
2-3. ブラウザのサポート状況
ここで大事なのはブラウザがこの属性をサポートしてるかどうかですね。Can I useで確認してみたらモーダンブラウザは大体サポートしているようです。しかし、Firefoxは2017年にリリースされた52バージョンからサポートしてることを考えると、そこまでは安心できないかもしれません。IEは未だにサポートしてない
3. rel="noreferrer"
3-1. セキュリティーについて
noreferrer
というものもまります。aタグにrel=noreferrer
をつけると、HTTPヘッダーから参照情報を削除することで参照情報が渡されることを塞げます。つまり、新しいタブから既存タブの情報を削除して漏れないようにすることでしょう。noreferrer
もnoopener
も新しいタブからwindow.opener
にアクセスするとnull
が来るので、結果的には同じことをやってますが、原理には違いがあります。
-
noopener
は新しいタブを別途スレッドに完全に分離させることで既存タブを参照できなくする -
noreferrer
は同じスレッドで新しいタブ開くけど既存タブの情報を渡さないことで既存タブを参照できなくする
3-2. SEOについて
また、noreferrer
について調べるとSEOに悪影響があるかもという心配も見つけられますが、noreferrer
がSEOに直接的な影響を与えることはありません。
グーグルのWebmaster Trends AnalystであるJohn Muellerが「noopener
とnoreferrer
はSEOに影響がありますか?」と聞かれてシンプルに「nope」と答えてるツイッターもありました。
しかし、グーグルアナリティクスレポートを混乱させるリスクはあります。
グーグルアナリティクスを使うとユーザーがどうやってウェブサイトに入ったかを分析できます。その種類には、
- referral(他のサイトが載せたリンクを通じて入った場合)
- Direct(url入力などで直接入った場合)
- Organic Search(検索エンジンの検索で入った場合)
- Social(SNSから入った場合)
などなど、色々なものがあります。aタグから他のサイトに遷移した場合はreferralに当てはまりますが、noreferrer
をつけるとDirectに分類されてしまいます。
これは分析レポートに事実ではないことを含ませるので、あまりよろしい状況ではありません。という訳で、このテーマについて詳しく話している他のブログでも内部リンクではrel=”noreferrer”
を使わないように!と言ってました。
Definitely do not use the rel=”noreferrer” attribute on internal links, it can mess up with your Google analytics reports.
内部リンクでrel=”noreferrer”属性を使うことは絶対にしないようにしましょう。グーグルアナリティクスのレポートで混乱することがあります。
3-3. ブラウザのサポート状況
noreferrer
はnoopener
より古いのバージョンのブラウザもサポートしています。同じくCan I useで確認できます。
aタグに関するMDNドキュメントのtarget
説明にはTabnabbingを防ぐためにrel="noreferrer"
をつけるようにと書いています。
注:
target
を使用する際は、window.opener
APIの悪用を避けるためにrel="noreferrer"
を追加してください。
おそらくnoreferrer
のほうがもっと古いブラウザもサポートしているからMDNではnoreferrer
の方をおすすめしていると思われます。一般的にはrel="noopener noreferrer"
のように両方つける方法が多く採用されていると感じですね。
4. rel="nofollow"
rel属性の中にはnofollow
というものもあります。aタグにこれをつけたらウェブクローラーがそのリンクを収集できなくします。つまり、そのリンクをSEOに反映されないようにするということでしょう。愚かな私は最初に「え、これ要る?」と思いましたが、もちろん要ります。
4-1. 有料リンク
有料リンクはSEOペナルティの対象です。お金払ってリンクを買って検索結果を騙す場合があるからのりゆうのようです。有料リンクに対するGoogleの方針は公式ドキュメントでもっと詳しく確認できます。
しかし、有料リンクは必ず検索結果操作の目的だけで使われてるわけでもありません。例えば、ある商品の広告をしたい場合なでも有料リンクを含みます。この部分に関しては上貼ったドキュメントでも言及しています。
すべての有料リンクが Google のガイドラインに違反するわけではありません。リンクの売買も、検索結果の操作でなく宣伝を目的として行われる限り、ウェブ上での通常の経済活動となります。広告として購入したリンクでは、そのことを明示する必要があります。
この「広告だと明示する」方法がrel=nofollow
をつけることです。そうしたら有料リンクを入れてもSEOペナルティを受けなくなります。
4-2. 他のユーザーによって生成されるコンテンツ
SEOに関するGoogleのドキュメントにこういう部分があります。
他のサイトにリンクすると、自分のサイトに対する評判の一部を別のサイトに与えることになります。ときどき、このことを利用しようとして、別のサイトのコメント欄や掲示板に自分のサイトへのリンクを追加するユーザーがいます。そのため、あるサイトに否定的に言及するとともに、自分のサイトへの評判をそのサイトには与えたくないと考える場合もあるでしょう。
不特定多数のユーザーが作成できるコメント欄や掲示板などは、他人が自分のサイトの評判を上げるためにリンクを投稿する可能性が高いです。この時rel=nofollow
を使うと、Googleに自分のページの評価をリンク先のページに渡さないようにと伝えることができます。
4-3. 埋め込み
埋め込みで他のサイトのウィジェットリンクを乗せることは結構あると思います。その中で、埋め込みはしたいのに埋め込み先のサイトに私のサイトには載せたくない場合もあるかもしれません。こういう場合もrel=nofollow
を使ったらSEOに反映されないので、安心して埋め込みできます。
4-4. nofollowの進歩
nofollowは2005年生まれた属性で、今まで説明した通りリンクをSEO評価対象から外せることに使われてました。確かにnofollow
は有用ですが、本来なら評価対象にすべきリンクまで全部対象外にしてしまうなどの問題もあがって来ました。この問題を解決するためにGoogleは2019年新しい方針を発表します。
-
rel="sponsored"
: 広告や有料プレースメントのリンク(一般に「有料リンク」と呼ばれます) -
rel="ugc"
: コメントやフォーラム投稿など、ユーザー作成コンテンツ(UGC) -
rel="nofollow"
: リンクにその他の適切な値がなく、そのリンクとサイトを関連付けたくない場合、またはリンク先のページをサイトからクロールさせないようにする場合
まずは全部nofollow
でやってたのを目的ごとにsponsored
、ugc
、nofollow
の3つに分けました。そして他の変化もあります。
When nofollow was introduced, Google would not count any link marked this way as a signal to use within our search algorithms. This has now changed. All the link attributes -- sponsored, UGC and nofollow -- are treated as hints about which links to consider or exclude within Search. We'll use these hints -- along with other signals -- as a way to better understand how to appropriately analyze and use links within our systems.
簡略にいうと、今まではnofollow
をつけたリンクは完全にSEO対象外にしてたけど、今(2019.09.05)からはヒントとして収集するかもしれないという内容です。公式ドキュメントにもかいてありますが、既存のnofollow
を全部この3つ分けて変更する必要はないものの、これからGoogleはこの3つを分けて使うことをおすすめするというスタンスです。
終わり
最初に書き始めたときは軽い気持ちだったのに、深ぼれば深ぼるほど内容が無限に出てきてびっくりしました(特にSEO周りが)。この記事は本当に足指一本入れたぐらい浅い内容ですが、私みたいな初心者の方々に役に立ったらいいなと思います。
Discussion