概要
気になったウェブページや参考にしたリソースをまとめて表示できるリンク集ページ「artifacts」を実装した。
URLを入力するだけでOGP情報(タイトル・概要・アイキャッチ画像・ドメイン名)を自動取得し、ブログカード形式で表示する。管理画面からリンクの追加・削除・並び替えが可能。
実装内容
データベース
リンクカードのデータを保存する専用テーブルを新設した。各レコードは以下のカラムを持つ。
- 記事URL
- サイトタイトル
- 概要文
- アイキャッチ画像URL
- ファビコンURL(Googleファビコンプロキシ経由)
- ドメイン名
- 表示順(sort_order)
表示順カラムにインデックスを付けてソートを高速化した。
OGP取得
URLを入力して「取得」ボタンを押すと、既存のOGP取得エンドポイントを呼び出してメタタグを解析する。取得した情報はプレビューとして管理画面に表示され、確認してから「追加」を押すとDBに保存される。
並び替え
カード一覧ではHTML5の Drag and Drop APIを使い、ドラッグ操作で表示順を変更できる。並び替え後は自動で並び替えAPIに送信され、DBの sort_order カラムが更新される。
公開ページのデザイン
2カラムのグリッドレイアウト(スマホは1カラム)でブログカードを並べる。各カードには以下を表示する。
- アイキャッチ画像(取得できない場合はSVGプレースホルダー)
- ドメイン名+ファビコン
- サイトタイトル
- 概要文(最大3行)
カードはホバーで浮き上がるアニメーションを付け、クリックすると外部ページが新しいタブで開く。
セキュリティ対応
外部URLを扱うページのため、以下のセキュリティ対策を実装した。
URLサニタイズ
- リンクURLは
https://で始まるもののみ許可する - アイキャッチ画像URLも同様に
https://のみ許可する - ファビコンURLはGoogleのファビコンプロキシドメインのみ許可する
XSS対策
- 管理画面のクライアントサイドJavaScriptでは
escapeHtml()/escapeAttr()を使い、外部から取得したテキストを直接DOMに挿入しない - 公開ページ側ではAstroのテンプレート変数展開(自動エスケープ)を使用する
- 外部リンクには
rel="noopener noreferrer"を付与する
SSRF対策
- OGP取得処理はバックエンドで行うが、既存のSSRF対策(プライベートIPブロック・タイムアウト)をそのまま継承している