じぶん対策

日々学んだことをアウトプットして備忘録にしています。

XSSとSQLインジェクションについて

XSSとは

Webアプリケーションの脆弱性を利用して行われるサイバー攻撃の1つ。
入力フォームなどに悪質なサイトへ誘導するスクリプトを埋め込みます。
悪質なサイトに誘導されると、ユーザーのブラウザ上で不正なスクリプトが実行されます。
攻撃の種類はマルウェア感染や個人情報の漏えい、フィッシング詐欺などがあります。
もともとのサイトから悪質なサイトへ跨いでスクリプトが実行されるので「クロスサイト」スクリプティングと呼ばれます。

XSSへの対策

XSSは入力フォームなどに直接スクリプトを埋め込んで実行されます。
参考 : https://www.amiya.co.jp/column/cross_site_scripting_20210118.html
対策としては以下のような方法があります。

  • エスケープ処理を行う
  • バリデーション処理によって意図していない文字の入力を制限する
  • 文字数制限によって長いコードの入力を制限することも効果があります。
  • WAF(Web Applicaton FireWall)を設置することも効果的です。

XSSの種類

XSSには以下の3種類がある。
参考: https://www.ipa.go.jp/files/000024726.pdf

non-persistent/Reflected XSS(反射型XSS

Stored/Persistent XSS(格納型/蓄積型/持続型XSS

DOM Based XSS

  • DOMは、「Document Object Model」の略で、HTMLやXMLを取り扱うためのAPIやデータ構造を定義したもの
  • ウェブページに含まれる正規のスクリプトにより、動的にウェブページを操作した結果、意図しないスクリプトをウェブページに出力してしまうタイプのXSS
  • 対策のためには正規のスクリプトを修正する必要がある。

クロスサイトリクエストフォージェリ(CSRF)とは

  • XSSに似たものにクロスサイトリクエストフォージェリ(CRSF)がある。
  • XSSとは違いセッション管理における脆弱性を狙った攻撃。
  • 罠となるサイトにアクセスしてしまうと、ターゲットとなる他のサイトにログイン状態になっていると、ターゲットとなるサイトに偽のリクエストが送信、実行されてしまう。

SQLインジェクションとは

XSSと同じくWebアプリケーションの脆弱性を利用して行われるサイバー攻撃の1つ。 入力フォームからSQL文を生成しているような場合に不正なSQL文を埋め込まれ、データベース内のデータの消去や改ざんを行われる。

SQLインジェクションへの対策

SQLインジェクションも同様に入力フォームなどに不正なSQLを埋め込んで実行されます。
対策として以下のような方法があります。

  • SQL文をプログラム中で作成する際にで特別な意味を持つ記号を素通りしないようエスケープ処理を行う。
  • データベースエンジンによっては安全にSQL文を生成する「バインド機構」やエスケープ処理用にAPIが用意されていたりする。
    • PHPの場合はPDOを用いてDBを操作する手法が主流となっており、bindParambindValueといった関数が用意されています。
    • bindValue
    • bindParam

本当に十分な対策なのか

上記あたりがよくある対策というか、グーグル先生に聞くと真っ先に出てくる情報かなと思います。
もう少しちゃんと調べていくと、このような対策だけでは不十分なようです。
結論から言うと、IPAが以下のサイトで安全なSQLの呼び出し方という資料を配布しています。
かなり信頼が置けそうです。
https://www.ipa.go.jp/security/vuln/websecurity.html

さくっと内容をまとめますが、一度資料全体に目を通しておくとよさそうです。 https://www.ipa.go.jp/files/000017320.pdf

安全なSQLの呼び出し方

  • SQLインジェクションの根本的解決の基本はバインド機構だが、エスケープ処理による対策も根本的解決の一つになる。
  • ただ、SQLにとって特別な意味を持つ記号はデータベースエンジンによって異なる。
  • SQLインジェクションの原因はSQL文を実際の値に展開する際にリテラルとして正しく文を生成しないと、パラメータに与えられた値がリテラルの外にはみ出した状態になり、リテラルの後ろに続く文として解釈される
    $q = "SELECT * FROM atable WHERE id='$id'";
    $id = ';DELETE FROM atable--
    のような場合に展開すると
    SELECT * FROM atable WHERE id='';DELETE FROM atable--'
    となり、データベースの内容が全て削除される結果となる。
  • 具体的な対策は以下の二つ。
    • 文字列リテラルに対してはエスケープすべき文字をエスケープすること。
    • 数値リテラルに対しては数値以外の文字を混入させないこと
  • アプリケーションからSQLを呼び出す際の方法には以下の二つがある。
  • それぞれの説明については割愛するが資料にある。
  • データベースエンジンや言語ごとに対応方法が違うのでそれも資料を参照。
  • 特にMySQLPostgreSQLはシングルクォート以外の文字をエスケープしないといけない。
  • バックスラッシュがエスケープ処理に使用されるメタ文字として解釈されるため、バックスラッシュ自身のエスケープも必要となる。
  • 文字列リテラルエスケープ処理では、文字エンコーディングに配慮する必要がある。

まとめ

  • SQLインジェクションへの対策はバインド機構とエスケープ処理が基本
  • そもそもSQLインジェクションの原因を知らないと対策が十分かどうかすら判断できないので理解が必要
  • 使用する言語、データベースエンジンごとの対策を確認することが大事。

所感

軽く検索するとなんとなくの概要は掴めるけど、信頼のおける情報かどうか、必要十分な情報かどうか判断するにはちゃんと自分で考える必要があるなと感じました。
以下のサイトはその辺りの検証をしていて参考になるとともに、こういう視点を持って自分で検証できる、してみるというのはブログの読者側にもメリットが大きくてありがたいです。 https://ockeghem.hatenablog.jp/entry/20111109/p1
また、本質的な対策を書いてくださっている方もいます。 https://ajiyoshi.hatenadiary.org/entry/20100409/1270809525

  • 単にプリペアドステートメントを使え
  • 絶対に文字列結合でSQLを構築しようとしてはいけない
  • IPAの「安全なSQLの呼び出し方」を読むこと

この辺りのセキュリティ対策はWebエンジニアとしては必須の知識なのできちんと身につけていきたいです。

(何も知らない判断できない状態でのグーグル先生との付き合い方が最近むずかしくなってるけど丸呑みせずに自分で判断しないと。。。)

ボーイスカウトの規則 Boy Scout Rule

参考文献

プリンシプルオブプログラミング

背景

参考文献に挙げた書籍はこの業界に入って一番初めに買った技術関連の書籍で今でも定期的に読み返しますがまだまだ身に付いてはいないと感じるのでひとつずつ深掘りしていこうと思います。

ボーイスカウトの規則

ボーイスカウトには、「自分のいた場所は来た時より綺麗にしなければならない」というシンプルなルールが存在します。
たとえ自分が来る前から汚かったとしても、綺麗にしてからその場を去るのです。
これはプログラミングにも当てはまります。

なぜ必要なのか

コードは時間の経過に従って腐敗し、品質が低下することが多々あります。
この原則をみんなが守るだけで、少なくとも今よりシステムの質が低下することは防げます。うまくいけば、システムの品質は徐々に向上さえするでしょう。

どのようにするのか

コードをリポジトリから取得した時よりも綺麗にしてコミットしましょう。
例えば、以下のような修正を継続的に積み重ねます。

  • 変数名をより良いものにする。
  • 大きすぎる関数を分割する。
  • 重複を排除する。
  • 条件文の連なりを無くす
  • 循環参照を解消する
  • インターフェースを追加して使用方法と実現方法を切り離す

プログラミングは「急がば回れ

ソフトウェア開発については最短距離で時間やコストを稼ぐより、回り道して品質をよくしたほうが良い結果につながります。
例えば、以下のような場合です。

  • 直接的な価値が得られないから、ユニットテストを書くのを省略する
    これには二つの問題があります。

    • 後で変更するのがとても難しくなる。また、保守にコストがかかる
    • 設計そのものが、「完全にテストできることを考慮された設計」と比べると使われ方が検討されていない分、良いものにはなっていない。
  • コスト軽減のため、目的が適合しないのに既存システムを無理やり使う
    これは、無理をしている以上必ず破綻します。結局きちんと用件に合わせてアーキテクチャを作り直すことになります。もちろんコストは後戻りした分、大幅に増えます。

考察

上記に述べたのが、参考文献に書かれていることの要約です。 ここから私見を交えて考察してみたいと思います。

タイミングについて

まず初めに考えたいのはボースカウトルールを適用するタイミングです。
コードの改善は継続的に行っていくべきです。しかし、1つのプルリクエストに本来のコミットとボーイスカウトルールを適用した修正のコミットを含めるべきではないと個人的には考えています。
その理由は、

  • 機能の追加や修正のプルリクより、見るのが辛い

からです。基本的にリファクタリングという作業は大規模になりがちだと思います。

レビュワーのことを考えると、レビューする観点を複数持ってレビューするのはしんどいです。
機能に関するプルリクと、修正に関するプルリクとを関心に基づいて分けた方がより親切です。
どういう単位で分割すればいいのか。いいなと思った記事を貼ります。

記事の中で
PR の小ささを保てる範囲内で、PR の外で確認しないといけない情報を減らす
という言葉が出てきますがいい考えだなと思いました。

この辺りの分割についてはコミットについても同じような考えで行うとよさそうです。
大切なのは意味のある単位で分割するという視点です。

そもそも難易度が高い

これは以前組み込み業界にいた時にもよく言われたのですが、
「すでに動いているコードを修正するな」
という言葉を聞いたことはないでしょうか。
これはコードの修正(リファクタリング)をすでに目的を果たしたものへの余計なお世話だとみなしています。
その裏側には、実際に必要のない努力を最小化するという意思が働いています。
ここでは本当に必要のない努力なのかということを考えてみます。 まず前提として、コードは変更されます。そのためにエンジニアはコードを読みやすく書く、設計手法を考えるといった努力をします。
ソフトウェアには安定した設計がなされるべきです。
修正が必要なコードというのは安定していない設計ということになります。
つまりコードを綺麗にして帰るというのは安定していない設計を安定した設計に近づけることです。
この意味でリファクタリングというのは必要なもの、ということになります。

ではなぜ余計なお世話だと感じるのでしょう。
一番大きな理由は

  • 影響範囲がわからず容易に手を出せない

からだと思います。
ソフトウェアの開発において小さな変更が大きな結果の違いを生むことは往々にしてあります。
だからと言って変更をしないというのはソフトウェアは必ず変更されるという前提に反します。
ではどうすれば良いでしょうか。
この問題を解決するにはユニットテストを書きましょう。影響範囲が一発でわかる上に設計を見直すことにもつながります。

ここでの話題はリファクタリングの重要性についてでしたが、今回の本題であるボーイスカウトルールについてはそこまで気合を入れるものではないのかなと感じています。
少しずつ、継続的に、できる範囲で良くしていくことが重要だと思います。

まとめ

  • リファクタリングは大事
  • でも修正と機能追加はまとめすぎないようにしよう。
  • ボーイスカウトルールの本質は少しずつ継続的にできる範囲で改善していくこと
  • そのためには修正に対して億劫にならないためにユニットテストをしっかり書くことが近道。

さいごに

参考にした書籍自体はこの業界に入った時、研修でお世話になった講師に勧められて自分で購入しました。
当時目を通しそれ以降も定期的に読み返しているのですが、頭で知ってはいても、まだまだ身についていないと感じています。
こういう抽象的な概念を実際に具体的なコードや自身の習慣に落とし込むのが難しいところだと感じています。
まずは先人の知恵を知る
そして自分に置き換えて意識して考える
最終的には意識せずともできるようになる
というステップを今後も着実に踏んでいければと思います。

web初学者によるクリーンアーキテクチャの理解

クリーンアーキテクチャについて

f:id:taisei_miyaji:20220321081706p:plain

参考

実装クリーンアーキテクチャ
クリーンアーキテクチャ完全に理解した
元ネタのブログ

クリーンアーキテクチャって?

まずGoogle先生に「クリーンアーキテクチャ」って何か聞くと上記の画像がヒットします。
見たことある人も多いのではないでしょうか。元ネタのボブおじさんのブログのリンクも貼ってあるので参考にしてください。
具体的なコードを見る前の段階として日本語や図で設計を理解することを目的としています。
「クリーンアーキテクチャって何ですか?」って聞かれた時にうまく言語化することが目標です。
(具体的な実装については参考に挙げたサイトを見ることをお勧めします。)
今回の目標はこの図を理解することです。

本質となる考え方

  • ビジネスロジックを独立させる。そのためには以下の二つを守る。
  • 独立させるメリットは取り換え可能になる = テストがしやすい。
  • 要するにメンテしやすくなる。

Enterprise Business Rules(Entities)

図の黄色のレイヤーです。
この層はビジネスロジックを表現するオブジェクトが所属している層です。
DDD(ドメイン駆動設計)が最も影響する層。 ビジネスルールをカプセル化したもの。

Application Business Rules(Use Cases)

図の赤色のレイヤーです。
「ソフトウェアが何ができるのか」を表現します。
アプリケーションの目的であるドメインにおける問題を解決するためにドメインオブジェクトを束ね上げ、ユースケースを実現する。
ちょっと難しいので例を出してみます。
例えば、買い物するとき、「注文」「受注」というドメインオブジェクトがあります。
ここでシステムを作る時に「買い物カート」が必要です。でもこれはもともとのビジネスには存在しない処理ですよね。
このようにリアルなビジネスにはないけれど、課題を解決するために必要なものを定義するのがこの層になります。

Interface Adapters(Controllers, Gateways, Presenters)

図の緑色のレイヤーです。
ここでのInterfaceはプログラミングにおけるInterfaceのことではないので注意してください。
アダプターの集合というニュアンスが近いです。
入力、永続化、表示を担当するオブジェクトが所属します。
入力(Controller)...入力されたデータの加工(イメージ: ゲームコントローラー)
永続化(Gateway)...データの保存処理(イメージ: メモリーカード、DB)
表示(Presenter)...結果の表示(イメージ: ディスプレイ)
以下のサイトにわかりやすい表があった。 https://gist.github.com/mpppk/609d592f25cab9312654b39f1b357c60.

用語 意味
Gateway Frameworks&Driversからのデータを抽象化する。RepositoryやSQLHandlerなど。
Presenter InteractorからOutput DataをOutput Boundaryを経由して受け取り、それをViewに適した形にして返す
Controller Webサーバ等からデータを受け取り、Input Dataに変換してUse Case(Input Boundary)へ渡す

Frameworks & Drivers(Devices, Web, UI, ExternalInterfaces, DB)

図の水色のレイヤーです。
Webフレームワークやデータベース操作オブジェクトなどのコード。
詳細なコード、ギークなコード。
フロントエンドのUIなど。

それぞれの層の依存関係性

それぞれの層について理解できたところで、もう一度図を見てみます。
左の円の中に矢印があります。この矢印はUMLでいう依存の矢印です。 つまり、外側が内側に依存している構図となっています。
ここで、依存についておさらいです。
例えば、Use CasesEntitiesに単方向で依存しているとします。この時、Entitiesに変更が生じた際、Use CasesEntitiesに依存しているため、影響を受けます。
これが依存関係です。反対に、Use Casesに変更が生じた際、Entitiesは影響を受けず、変更する必要はないです。
このように外側の層の変更が内側の層に影響しないような状態を外側から内側への単方向の依存関係といいます。

クリーンアーキテクチャの目的

依存関係を単方向、かつ内部の層が外部の層に依存しないことが理解できたと思います。
つまり、実現したいこと(ビジネスロジック)が変わったら、使用するDBやUIは見直す必要はある。
でも、使用するDBやUIのような外部のものを変更するために内部のビジネスロジックにまで変更が及ぶような設計はおかしいよね。ってことです。
クリーンアーキテクチャのメリットとして、以下があります。 - テストがしやすい。 これが一番大きなメリットです。例えば以下のようなケース。 - フロントエンドのテスト
バックエンドとフロントエンドを同時に開発しており、フロントエンドのテストをしたいけど、バックエンドのコードはできていない。
この場合はInteractorをモックにすることで任意の例外を投げたりしてテストができます。 - バックエンドのテスト
例えば、DBの選定が終わっていないけどビジネスロジックを書きたい場合。
何を出力するかの部分をビジネスロジックに書いていて、何に出力するかは外側の層にあります。 何に出力するか、どう出力するかについてはビジネスロジックは知らなくていいので、モックにできます。
具体的には、本番ではDBに書きこむけれど、テストの際には一旦インメモリに書き出して確認する。みたいなことができます。 - 疎結合が実現できる。 つまり、外側の層だけ交換することが可能です。内側に依存していないのですから。

Use Cases(右下の図)を理解する

f:id:taisei_miyaji:20220321081732p:plain.
この図が何を表しているのか私は初見でわからなかったので解説しておきます。
この図はより具体的な実装例を示していると思ってください。
まず、白抜きの矢印は汎化、矢印は依存を表しています。 また、右上の<I>はinterfaceを表しています。 処理の流れをこの図を見ながら整理すると、
1. Controllerが入力データをUse Case Inout Portに渡す 2. Use Case Input Portの実態であるUse Case Interactorに処理を移譲される。 3. Use Case Interactorは処理を行った結果(出力データ)をUse Case Output Portに渡す 4. Use Case Outputの実態であるPresenterに処理を移譲される。 5. Presenterは表示を行う。

こういう構成にしておくことで、Use Case Interactorを介してデータを受け渡ししているのでモックにしやすい=テストがしやすい構成になります。

まとめ

  • そもそもアーキテクチャの役割って何?必要なの?
    • プログラミングは自由。何でもできる。でも、サービスを作る上では方針をある程度決めておくといろんな事象に対応しやすいし、スムーズに開発できるよね。っていうイメージ。
  • ヘキサゴナルアーキテクチャ、オニオンアーキテクチャとクリーンアーキテクチャは目指すところは同じ
  • 関心の分離を目指している。つまり交換しやすく、かつテストがしやすい(モックが作りやすい)。
  • 関心の分離の実現のために、各レイヤーは内側に向かってのみ依存する。内側の円は外側の円について何も知らない。
  • 依存関係逆転の原則を重要視している(SOLID原則の一つ。これについてはまたまとめます。)
    • 抽象は詳細に依存してはならない。詳細が抽象に依存すべきである。
    • 今回の場合は抽象=ビジネスロジック,詳細=外側の層、DBとか。
    • 要するに技術面での変更がビジネスロジックに変更与えちゃダメってこと。
  • デメリットもある。
    • クラスがめちゃくちゃ増える。(スタブを自動生成するようなツール作ったりして解決する)
    • 一見複雑に見える(経験の問題、フォルダの切り出しの問題。適切なグルーピングを行うことで複雑どころかわかりやすくなるはず。)
  • クリーンアーキテクチャとは、適切なグルーピングによってレイヤーを分けて、それらを疎結合にして、依存を一方通行にすれば、テスタブルかつメンテしやすい設計が実現できる、というアーキテクチャ

MVCモデルとミドルウェアについて

MVCモデルについて

MVCとは

ソフトウェアをModel,View,Controllerの3要素の組み合わせでシステムを構築していく考え方。

Model

  • ビジネスロジックを担当するシステムの本体部分
  • データの変更をViewに通知する(Observerパターンを使うこともある)

    View

  • 表示、入出力といった部分を担当する。
  • Modelのデータを取り出してユーザが見る形で表示(Viewがデータを受け取っているわけではない)

Controller

  • ViewとModelを制御する(HTTPリクエストを適切なModelに渡す、ViewからのレスポンスHTTPをユーザに返す)
  • 自分自身ではロジックの実行はせず、Viewから入力を受け取り、それに応じてModelのロジックを呼び出し、結果をViewに渡す。
  • UIからの入力を担当する
  • イベントを受け取る。つまり画面上構成するイベントの数だけ処理がある

メリット

  • 機能ごとの分離が明確になるため、独立性が確保でき、分業しやすくなる。
  • コンポーネント間の依存度を下げることができる。つまり、再利用しやすくなる。
  • また、責任が分かれているため、複数人でメンテナンスすることを考えた時、同時に同じ領域を操作する危険が減り保守性も向上する。

Middlewareパターン

❄️PHPでMiddlewareパターンを実装する方法

特性

  • クライアントコードとハンドラの間に割って入り、入力を加工する
  • ハンドラとクライアントコードの間に割って入り、出力を加工する
  • クライアントコードとハンドラの間に割って入り、入力がハンドラに届く前に、早期に出力を返す

Middlewareパターンとは

Middlewareパターンの目的は、「ミドルウェア」と呼ばれるガワの処理で核となるハンドラを包むことで、プログラム本来の振る舞いを拡張可能にすること。
MVCウェブフレームワークでは、コントローラの入出力となるHTTPリクエストやレスポンスをアプリケーション全体で統一的に加工する用途などに採用されている。

どんな時に使えるか

  • HTTPS接続のみを許可し、HTTPで接続されると強制的にリダイレクトする。
  • 特定のIPアドレスだけ許可する
  • ログインしているユーザーにのみページを表示する
  • 特定の言語のみ、特定の国のみページを表示する
  • リクエストのログを記録する

LaravelにおけるMiddleware

Laravel Middleware 調べてみた
以下の三種類に分類できる。 - グローバルミドルウェア - ルートミドルウェア - コンストラクタ内のミドルウェア

処理の順番は以下の通り。
1. グローバルミドルウェア 2. ルートミドルウェア 3. コンストラクタ内ミドルウェア 4. コントローラーの処理 5. コンストラクタ内ミドルウェア 6. ルートミドルウェア 7. グローバルミドルウェア

コントローラーの処理をラップするイメージ。

公式

Laravel - ミドルウェア

追加(後で読む)

クリーンアーキテクチャ

クリーンアーキテクチャ完全に理解した

簡単にDocker概要メモ。

Dockerについて

Dockerとは

以下公式より引用

Docker はアプリケーションの開発、導入、実行を行うためのオープンなプラットフォームです。
Docker を使えば、アプリケーションをインフラストラクチャーから切り離すことができるため、ソフトウエアをすばやく提供することができます。
Docker であれば、アプリケーションを管理する手法をそのまま、インフラストラクチャーの管理にも適用できます。
Docker が採用する方法を最大限利用して、アプリケーションの導入、テスト、コードデプロイをすばやく行うことは、つまりコーディングと実稼動の合間を大きく削減できることを意味します。

メリット

  • 作成したコンテナ上でアプリケーションを開発することで開発環境と本番環境を揃えられるというメリットがあります。
  • コンテナの構築方法をドキュメントで管理できる。これによって異なるマシン上に同じ環境を素早く構築することが可能。

仮想マシンとの違い

  • 仮想マシン
    ホストOS上でハイパーバイザを動かす。ハイパーバイザ上にゲストOS、ミドルウェアやソフトウェアを動作させる。
  • Docker
    ホストOSの上にDocker Engineというソフトを立ち上げ、その上にコンテナというものを作成する。 コンテナの場合はホストOSのカーネルを利用する。軽量で高速に起動、停止が可能

Kubernetesとは

  • 簡単にいうと複数のコンテナを管理するサービス。コンテナ間でネットワークやストレージなどの連携を行う。