本節の重点内容#
安全問題は非常に一般的であり、危害を及ぼす可能性があります
- ユーザー
- 企業
- プログラマー(祭天 QAQ)
2 つの視点から見る Web 安全#
あなたがハッカーだとしたら —— 攻撃#
クロスサイトスクリプティング攻撃 XSS(Cross Site Scripting)#
悪意のあるスクリプトを注入し、攻撃を完了させる。その結果:ユーザーのプライバシーが漏洩するなど。
XSS は主に開発者がユーザーの提出内容を盲目的に信頼することを利用しています。
特徴
- 通常UI 上で感知しにくい(一般的には裏でスクリプトが実行される)
- ユーザー情報を盗む(cookie/token)
- **UI を描画(ポップアップなど)** し、ユーザーを騙してクリック / フォームに記入させる
例を挙げると
public async submit(ctx) {
const {content, id} = ctx.request.body;
await db.save({
content, // contentに対してフィルタリングを行っていない!!
id
});
}
public async render(ctx) {
const { content } = await db.query({
id: ctx.query.id
});
// contentに対してフィルタリングを行っていない!!
ctx.body = `<div>${content}</div>`;
}
上記のコードでは、ユーザーが入力した content 内容に対して何のフィルタリングも行っていないことがわかります。この時、<script>alert('xss');</script>
スクリプトを提出して攻撃することができます。
xss 攻撃は大きく分けていくつかの種類があります:Store XSS、Reflected XSS、DOM-based XSS、Mutation-based XSS
Store XSS#
- 提出された悪意のあるスクリプトがデータベースに存在する
- ページにアクセス -> データを読み取る == 攻撃される
- 最も危害が大きい、全ユーザーに見える
- 例:ある動画サイトに悪意のあるスクリプトがアップロードされ、データベースに保存されると、その後 e コマースサイトに動画共有アカウントが追加される。
Reflected XSS#
-
データベースを含まない
-
URLから攻撃し、URL にスクリプトを含める
DOM-based XSS#
-
サーバーの参加は不要
-
悪意のある攻撃の発起と実行は全てブラウザ内で完了する
-
スクリプトの注入が完了する場所はブラウザから来るもので、これが Reflected XSS との違いです。
Mutation-based XSS#
-
ブラウザの特性を利用した巧妙な攻撃方法
ユーザーが提供したリッチテキストコンテンツが javascript コードを介して innerHTML 属性に入ると、予期しない変化がこの認定を無効にすることがあります:ブラウザのレンダリングエンジンは本来無害な HTML コードを潜在的に危険な XSS 攻撃コードにレンダリングします。
-
巧妙で、最も防御が難しい方法であり、攻撃者はブラウザを非常によく理解しています。
クロスサイトリクエストフォージェリ(CSRF、クロスサイト偽造リクエスト)#
-
ユーザーが知らないうちに
-
ユーザー権限を利用(cookie)
-
指定された HTTP リクエストを構築し、ユーザーの敏感情報を盗むまたは変更する
ユーザーが悪意のあるページにアクセスすると、そのページが銀行に送金リクエストを送信します。ServerA は銀行のサーバーであり、このリクエストにユーザーの cookie が含まれていることを確認し、成功します。
CSRF は信頼されたユーザーからのリクエストを偽装して信頼されたウェブサイトを利用します。XSS 攻撃と比較して、CSRF 攻撃はあまり流行していないため(そのため防止リソースも非常に少ない)、防止が難しいため、XSS よりも
より危険である
と見なされています。
注入(Injection)#
-
SQL インジェクション:SQL パラメータを介して注入
ケース:リクエストフィールドを読み取り、文字列の形式で SQL 文を結合する
public async rederForm(ctx) { const {username, form_id } = ctx.query; const result = await sql.query(` SELECT a, b, c FROM table WHERE username = ${username} AND form_id = ${form_id} `); ctx.body = renderForm(result); }
そのため、攻撃者は userName を
any; DROP TABLE table;
として渡すことができ、結果としてデータベースを削除することができます。 -
コマンドラインインジェクションなど
-
読み取り + 改行のトラフィック攻撃
サービス拒否(DoS)攻撃#
-
何らかの方法(特定のリクエストを構築)で、サーバーリソースが著しく消費される。
-
さらなるリクエストに応答できず、リクエストが圧迫され、雪崩効果が発生する。
-
拡張:正規表現 —— 貪欲モード
- 繰り返しマッチング時、
?
/no ?
:「1つで十分」
/できるだけ多く
- 繰り返しマッチング時、
-
例:ReDoS: 正規表現に基づく DoS
-
貪欲:n 回失敗したら?n-1 回再試行?—— バックトラック
-
分散型 DoS(DDOS)
-
短時間内に、多数のボットデバイスからのリクエストトラフィックがあり、サーバーはすべてのリクエストをタイムリーに処理できず、リクエストが積み重なり、雪崩効果が発生し、新しいリクエストに応答できなくなる。(量が多ければそれで良い)
-
特徴:
-
IP に直接アクセス
-
任意の API
-
大量の帯域幅を消費(枯渇)
-
-
中間者攻撃(伝送層)#
-
平文伝送
-
情報改ざんが不可知
-
相手の身元が未確認
あなたが開発者だとしたら —— 防御#
XSS 攻撃防御#
-
常にユーザーの提出内容を信頼しない
- ユーザーの提出内容を直接 DOM に変換しないこと
-
既存のツール
- 主流のフレームワークはデフォルトで XSS を防御(react など)
- google-closure-library
- サーバーサイド:DOMPurify
-
ユーザーの要求:武道を語らず、必ず動的に DOM を生成する?
-
new DOMParser();
-
svg:スクリプトタグも挿入できるため、スキャンが必要
-
ユーザー定義のリダイレクトリンクは避ける(またはフィルタリングを行う)!
<a href="javascript:alert('xss')"></a>
-
-
カスタムスタイルにも注意
同一生成ポリシー(CSP)#
- プロトコル
- ドメイン名
- ポート
いずれかが異なる場合、クロスドメイン ×
ブラウザの同一生成ポリシー - Web 安全 | MDN (mozilla.org)
一般的な同一生成リクエストは問題ありませんが、クロスドメインは問題です。CSP は開発者が定義することを許可します。
- どのソース(ドメイン)が安全と見なされるか
- 安全なソースからのスクリプトが実行できる、それ以外は直接エラーを投げる
- eval + インラインスクリプトを直接拒否
- 設定
- サーバーのレスポンスヘッダー
Content-Security-Policy: script-src 'self'; // 同一生成 Content-Security-Policy: script-src 'self' https://domain.com
- ブラウザのレスポンスヘッダー
<meta http-equiv=" Content-Security-Policy" content="script-src self">
CSRF 攻撃防御#
-
Origin + Referrer
-
その他の判断方法【リクエストが合法的なソースから来ているか】
- 先にページがあり、後にリクエストがある
- if リクエストが合法的なページから来ている場合
- then サーバーはページリクエストを受け入れた
- then サーバーは識別できる
- 先にページがあり、後にリクエストがある
-
-
iframe 攻撃:Origin を制限するのか、それなら同一生成リクエストを行う
-
GET + POST を一緒にリクエストすることを避ける、攻撃者は一石二鳥!
// 以下のように更新+取得ロジックを同じGETインターフェースに入れないでください public async getAndUpdate(ctx) { const { update, id } = ctx.query; if (update) { await this.update(update); } ctx.body = await this.get(id); }
-
SameSite Cookie
-
Cookie ドメインを制限
-
ページのドメイン名が一致するかどうか
-
Cookie に依存するサードパーティサービスはどうする?
X サイトのプレーヤーを埋め込むと、ユーザーのログイン状態を認識できず、弾幕を送信できません。
Set-Cookie: SameSite=None; Secure ;
-
-
SameSite vs CORS(クロスサイトリソース共有)
これだけの CSRF 防御方法がある中で、CSRF を防ぐ正しい姿勢は何でしょうか?専用のミドルウェアを作成して、この分野の防御を生成します。
注入防御#
-
プロジェクト内の SQL クエリを見つける
-
プレパレッドステートメントを使用する
PREPARE q FROM 'SELECT user FROM users WHERE gender = ?'; SET @gender = 'female'; EXECUTE q USING @gender; DEALLOCATE PREPARE q;
-
最小権限の原則
- すべてのコマンドに sodo || root を使用しないこと ×
-
許可リストを作成し、フィルタリングを行う
- rm は絶対に拒否
-
URL タイプのパラメータに対してプロトコル、ドメイン名、IP などの制限を行う
- 攻撃者が内部ネットワークにアクセスするのを避ける
DoS 防御#
- コードレビュー(貪欲マッチングなどを避ける)
- コードスキャン + 正規表現パフォーマンステスト
- ユーザー提供の正規表現を避ける
DDoS 防御#
伝送層 —— 中間者防御#
有名な HTTPS を導入します。
- 信頼性:暗号化
- 完全性:MAC 検証
- 否認防止:デジタル署名
-
拡張:デジタル署名
-
秘密鍵(自分で保管)
-
公開鍵(公開可能)
-
CA:証明書機関
-
デジタル署名、ブラウザに組み込まれた CA 公開鍵
-
- 署名アルゴリズムが十分に強力でない場合:ブルートフォース攻撃を受ける(現在はかなり改善されています)
HTTP Strict-Transport-Security(HSTS)
- HTTP を積極的に HTTPS にアップグレードする
静的リソースがハイジャックされて改ざんされた?ハッシュを比較します。
結び#
- セキュリティは小さなことではありません
- 使用する依存関係(npm パッケージ、さらには NodeJS)が最も弱い環になる可能性があります
- 学び続ける姿勢を保つ
まとめと感想#
この授業では、先生が Web 安全に関する多くの知識を視覚的に説明しており、とても興味深いものでした。Web 攻撃の種類や防御方法などについて学びました。
本文で引用した内容の大部分は、劉宇晨先生の授業、MDN、外部ブログからの引用です:この機会に、XSS 攻撃を完全に理解する、CSRF についての浅い考察