SQLインジェクションとplaceholder機能を使った対応処理
SQLインジェクション
r.GET("/1/users/:Id"
上記のAPIをWebで叩くとき、WebではURLがブラウザの上部に表示され、下記のようにURLが表示される。
"https://domain.jp/users/id"
パラメーター部分(id)はURLを直接書き換えることで別の値に置き換えることができる。
データベースと連携して動作するWebサイトでは、外部から入力された値を元にSQL文を組み立てるため、
入力された値によって意図しないSQLが生成され、結果として不正にDBのデータが読み取られたり、データが改ざんまたは削除される恐れがある。
この手法の攻撃を"SQLの注入"という意味でSQLインジェクションと呼ぶ。
placeholder機能
SQLインジェクションの対応として、安全なパラメーターを使ってSQL文を生成するplaceholder機能を使うことができる。
Routes
func GetUser(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { // パラメータをチェック Id, err := strconv.ParseInt(ps.ByName("id"), 10, 0) helpers.CheckErr(err, "Invalid Id") // 問題なければモデルの処理へ受けわたす R.JSON(w, http.StatusOK, models.GetUser(Id)) }
Models
func GetUser(Id int64) UserView { query := UserQuery + ` WHERE s.user_id = ? AND s.user_deleted_date IS NULL ` var user UserView _, err := DbMap.Select(&user, query, id) helpers.CheckErr(err, "Executing query failed") return user }
"SELECT s.user_id = ? "の?には"_, err := DbMap.Select(&user, query, id) "によりidで渡ってきた値が代入されてSQL文が生成される。
A Tour of Go vol.1
Packages
goのプログラムはパッケージで構成され、mainパッケージから開始される。
ソースコードの冒頭で自身を表すパッケージを記載し、
続いてインポートするパッケージを記述する。
package main import { "fmt" "net/http" "tmhub/helpers" }
自社のソースコードではpackageの後にくるものは下記5つ
- main
- helpers
- models
- config
- routes
これはトップレベルに配置されているフォルダと一部一致する。
インポートのパスで"tmhub/helpers"と呼び出されているパッケージは冒頭がpackage helpersステートメントで始まる。
Goでは構成するファイルを全てpackageという要素とみなす。
Exported names
パッケージをインポートすると、そのパッケージがエクスポートしている名前を参照することができる。
Goでは外部のパッケージから参照できるエクスポートされた名前は大文字から始まる。
func main() {
fmt.Println(math.Pi)
}
上記のコードで `math.pi` とすると参照できずエラーが出力される。
cannot refer to unexported name math.pi
Functions
引数では変数名の後に型を記述する。
この時引数の型が同じ場合は変数を先に記述して最後に型を記述する記法もある。
func add(x int, y int) int { return x + y } func add(x, y int) int { return x + y }
関数は複数の戻り値を返すこともできる。
また戻り値は引数に続いて宣言することができる。
func split(sum int) (x, y int) { x = sum * 4 / 9 y = sum - x return }
(sum int)に続く(x, y int)が戻り値
上記のコードの結果は7 10が返る
戻り値を引数の後に並べて宣言する。
return は記述必須。個人的にはreturnが記述必須なら戻り値はreturnに続けて書くか
もしくは戻り値を先頭に記述するなら当然返却するものとしてreturn記述省略可とかにして欲しかった。。
GoのMVC
最近業務でGoの修正を行う機会があり、クライアント側しか触ってこなかった自分には未知のことがたくさんあった。
まずは大枠としてMVCから学ぶ。
MVCはレイヤーアーキテクチャという設計手法に基づいている。
レイヤーアーキテクチャ
アプリケーションを責務に応じたいくつかの層としてとらえる設計手法。
View | ユーザーインターフェース層 | モデルのデータを取り出してユーザが見るのに適した形で表示する要素 |
---|---|---|
Controller | アプリケーション層 | ユーザからの入力(通常イベントとして通知される)をモデルへのメッセージへと変換してモデルに伝える要素 |
Model | ドメイン層 | データと手続きを表現し、データの変更をViewに通知する要素 |
- 各オブジェクトはいずれかの層に属し、複数の層にまたがることはない
- 層の関係は一方通行であり、相互参照する関係は層をまたがない
ModelはControllerやViewでどう呼び出されるか知るべきではないし、ControllerはViewがどのように描画するか知るべきでない。
互いの層を一方的に利用するようにすることで、オブジェクト間の結合を疎に保ち、ドメインロジックの凝集度を高める。
これは作り手により異なるところかもしれないが、Goの勉強なので自社で扱っているプロダクトのGoの構造をこれにあてはめた。
Controller
- routes: アプリからユーザーが入力したデータを受け取り、どの処理をするかをモデルへ通知する。
- handlers: モデルへ通知する前にセッションのチェックなど毎回実施されるチェック処理を行う。
- helpers: 便利道具。毎回実施するチェック、とはいかないがさまざまなところで使う処理群。
Model
- models: ビジネスロジック。
routes
func New (r * httprouter.Router) { r.GET('users/:id', handlersLoginRequired(GetUser)) }
handlersであるhandlersLoginRequired()でユーザーがログインしていることを確認し、modelのGetUser()へ通知する。
WebSocketを使ってリアルタイムチャットアプリを作った
Reactの勉強の一環としてWebSocketを用いたリアルタイムチャットアプリを作った。
使用ライブラリ
リアルタイムな双方向通信を可能にするNode.jsライブラリとブラウザ用ライブラリのセット
WebSocket
サーバーとクライアントの双方向通信を可能にする技術。
ウェブ ブラウザとサーバー間に「ソケット」接続を確立する API を定義してあり、クライアントとサーバーの間に持続的接続が存在するためどちらの側からでもいつでもデータの送信を開始できる。
主にHTMLで書かれた文書を転送するためのプロトコルであるHTTPでは双方向の通信ができなかったために生み出された。
この時、一定間隔でサーバに問い合わせをし続けるポーリングやサーバで発生したイベントをクライアントからの要請なしにクライアントに送信することができる技術であるCometなどを使ってどうにかHTTPでクライアントとサーバ間の双方向通信を実現しようという動きもあった。
WebSocket通信の確立
HTTP通信によりハンドシェイクを行うことで通信を確立させる。
リクエスト
HTTPのUpgradeヘッダを使用し、プロトコルの変更を行う。
レスポンス
ステータスコード101「Switching Protocols」が返る。
これによりハンドシェイクによってコネクションが確立し、これ以降はHTTPではなくWebSocketのプロトコルで通信が行われることになる。
SPA(ReactとExpress)
Reactの勉強の一環としてSPAを作成してみた。
WebサーバーはNode.jsで構築するが、その際にフレームワークはExpressを使用した。
SPA
それまでWebアプリケーションは画面の表示を変更するたびにWebサーバーと通信を行い、表示すべきHTMLを受け取っていた。
それに対しSPAでは必要な時だけWebサーバーと通信する。
これにより使い勝手や操作性が向上するが反面複数のモジュールを読み込むために初回の読み込みには時間がかかる。
使用したライブラリ
NeDB
データはJSON形式で保存され、全てJavaScriptで書かれているのでバイナリ依存の心配は不要。
NeDBについて詳しく書かれた記事はこちら
JavaScriptでDBもAPIもクライアント側も全部作れてしまうのでいい時代に生まれた。
作ったものは簡単な掲示板
APIを自作してDBとやりとりするところまで全部書いたのは初めてでなんとなくAPIとかサーバー全般に対して恐怖心があったけどぬぐえた気がする。
Reactの描画処理が速い理由
Reactの描画処理では仮想DOMの採用にはじまり、高速化するために工夫がこらされている。
工夫の方向としては"処理が重いリアルなDOMの操作を極力抑える"というものでる。
まずはリアルDOMの処理内容を知り、そこからどういった点で仮想DOMの方が速いのか比較する。
続きを読む